Exploiting over Sockets
File Descriptors and Sockets

Overview

File Descriptors are integers that represent conections to sockets or files or whatever you're connecting to. In Unix systems, there are 3 main file descriptors (often abbreviated fd) for each application:
Name
fd
stdin
0
stdout
1
stderr
2
These are, as shown above, standard input, output and error. You've probably used them before yourself, for example to hide errors when running commands:
1
find / -name secret.txt 2>/dev/null
Copied!
Here you're piping stderr to /dev/null, which is the same principle.

File Descriptors and Sockets

Many binaries in CTFs use programs such as socat to redirect stdin and stdout (and sometimes stderr) to the user when they connect. These are super simple and often require no more than a replacement of
1
p = process()
Copied!
With the line
1
p = remote(host, port)
Copied!
Others, however, implement their own socket programming in C. In these scenarios, stdin and stdout may not be shown back to the user.
The reason for this is every new connection has a different fd. If you listen in C, since fd 0-2 is reserved, the listening socket will often be assigned fd 3. Once we connect, we set up another fd, fd 4 (neither the 3 nor the 4 is certain, but statistically likely).

Exploitation with File Desciptors

In these scenarios, it's just as simple to pop a shell. This shell, however, is not shown back to the user - it's shown back to the terminal running the server. Why? Because it utilises fd 0, 1 and 2 for its I/O.
Here we have to tell the program to duplicate the file descriptor in order to redirect stdin and stderr to fd 4, and glibc provides a simple way to do so.
The dup syscall (and C function) duplicates the fd and uses the lowest-numbered free fd. However, we need to ensure it's fd 4 that's used, so we can use dup2(). dup2 takes in two parameters: a newfd and an oldfd. Descriptor oldfd is duplicated to newfd, allowing us to interact with stdin and stdout and actually use any shell we may have popped.
Note that the man page outlines how if newfd is in use it is silently closed, which is exactly what we wish.
Last modified 1yr ago