---
description: File Descriptors and Sockets
---

# Exploiting over 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:

```bash
find / -name secret.txt 2>/dev/null
```

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

```python
p = process()
```

With the line

```python
p = remote(host, port)
```

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](https://man7.org/linux/man-pages/man2/dup.2.html) outlines how if `newfd` is in use it is silently closed, which is exactly what we wish.
