lsof -p PID可查bash进程0/1/2文件描述符是否连远程,正常应指向/dev/pts/N或/dev/tty,若指向/dev/tcp/ip/port或显示socket:[...]则极可能是反弹Shell;netstat/ss无法检测此类伪设备连接,需结合/proc/PID/fd/和fdinfo直接分析。

怎么看bash进程的0/1/2文件描述符是否连到了远程
直接看lsof -p PID输出里标准输入、输出、错误是否指向/dev/tcp/...或/dev/udp/...,是识别bash -i >&/dev/tcp/ip/port 0>&1类反弹Shell最可靠的依据。正常终端下这三者都该指向/dev/pts/N或/dev/tty。
执行步骤:
- 先用
ps aux | grep "bash.*-i"或ps aux | grep "/dev/tcp\|/dev/udp"粗筛可疑bash进程 - 对疑似PID运行
ls -l /proc/PID/fd/{0,1,2},快速确认目标文件描述符指向 - 若看到类似
socket:[1234567],再用lsof -p PID查具体IP和端口 - 特别注意用户是
www-data、nginx、apache等非交互式账户启动的bash,风险极高
为什么netstat和ss可能漏掉/dev/tcp连接
/dev/tcp/ip/port不是真实网络套接字,而是Bash内置的伪设备语法,底层调用socket() + connect(),但不会在netstat -tuln或ss -tuln里显示为“监听”或“已建立”的常规连接——它只是个单向出站连接,且生命周期短、无监听端口。
所以不能依赖netstat找反弹Shell,必须回到进程级视角:
-
lsof -i -P -n能列出所有带IP:PORT的socket连接,包括/dev/tcp触发的 -
cat /proc/PID/fdinfo/{0,1,2} 2>/dev/null | grep "ip:"可直接提取IP和端口,绕过lsof依赖 - 如果系统已被rootkit篡改,
lsof本身可能被hook,此时应优先用/proc/PID/fd/路径直读
如何批量检测所有bash进程的fd重定向异常
手动逐个查太慢,用这个命令一次扫完所有非登录态bash(排除掉你自己的交互式终端):
for pid in $(pgrep -f "bash.*-i"); do
if ! grep -q "pts" /proc/$pid/fdinfo/0 2>/dev/null; then
echo "[!] PID $pid -> $(readlink /proc/$pid/fd/{0,1,2} 2>/dev/null | tr '\n' ' ')";
fi;
done 2>/dev/null
关键点:
- 只检查含
-i参数的bash,过滤掉普通脚本执行 - 用
readlink /proc/$pid/fd/{0,1,2}比lsof更底层、更难被干扰 - 跳过
pts路径,意味着不是从终端来,大概率是网络重定向 - 输出里出现
socket:[...]或ipv4:xxx就需立即跟进
发现后别急着kill,先保存内存证据
直接kill -9会清空socket缓冲区,丢失攻击者刚输的命令、正在传输的数据。正确顺序是:
- 先用
gcore PID生成内存快照(需提前装gdb),留作后续分析 - 再用
cat /proc/PID/cmdline | tr '\0' '\n'确认原始启动命令,常含base64或curl地址 - 最后
kill -9 PID终止,并检查其父进程(ps -o ppid= -p PID),防止父进程自动拉起新实例 - 顺手查
/proc/PID/environ,有时攻击者会通过环境变量传参,比如LD_PRELOAD已加载恶意so
真正的难点不在识别,而在于:很多反弹shell根本不用bash -i,而是用python/perl/sh -c拼接,且fd重定向逻辑藏在子shell里——这时候得结合/proc/PID/fdinfo/和cat /proc/PID/status | grep PPid往回追三代父进程。


















