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 |
| 0 |
| 1 |
| 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:
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
With the line
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 updated