皮卡丘靶场解题记录-XXE
皮卡丘靶场解题记录-XXE
1、漏洞原理总结:
xml:类似html,用成对的标签把数据包起来,用于结构化地存储数据。
1 | <人> |
DTD:xml顶部的声明区,类似于术语说明,约定好什么符号代表什么。
实体(ENTITY):xml里面的变量。在DTD里声明,然后在正文里用 &名字; 引用,解析器会自动把 &名字; 替换成它代表的内容。类似于开头写A=xxxxxxx,后面全文写A,然后解析器会自动把A替换成xxxxxxx。
内外实体的区别:
| 类型 | 值从哪来 | 写法 |
|---|---|---|
| 内部实体 | 值写死在 DTD 里 | <!ENTITY hacker "ESHLkangi"> |
| 外部实体 | 值去读外部文件/URL | <!ENTITY f SYSTEM "file:///etc/passwd"> |
SYSTEM 这个词 = “值不是写死的,去系统里取”。
比如,把payload写成内部实体,就会得到原样返回。这里就是把ESHLkangi定义成立hacker
1 |
|
2、我的测试过程:
3、核心漏洞代码分析:
1 | //考虑到目前很多版本里面libxml的版本都>=2.9.0了,所以这里添加了LIBXML_NOENT参数开启了外部实体解析 |
靶场代码如上:
现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。以PHP为例,在PHP里面解析xml用的是libxml,其在≥2.9.0的版本中,默认是禁止解析xml外部实体内容的。靶场里为了模拟漏洞,通过手动指定LIBXML_NOENT选项开启了xml外部实体解析。
本次使用的payload:
1 |
|
正常解析器会拒绝读外部文件(防 XXE),但这个靶场用 LIBXML_NOENT 把它”放开”了,所以 file:///etc/passwd 被真的读出来。
4、实战延伸:
很多功能看着不收 XML,但换个 Content-Type 头就能让它收 XML,而且那套 XML 解析代码可能从没被加固过——POST 的时候把 body 写成 XML、把 Content-Type: application/xml,看它解不解。
默认拒绝只保护了新版 PHP 一小片,Java/.NET/老系统/Office/SAML/回调等大量场景的 XML 解析器默认就能读外部文件;XXE 在实战并不少见——重点盯 SOAP、回调、文件上传、以及换 Content-Type 就能收 XML的接口
实际运用xxe的时候有两种姿势,姿势A是类似本题的,在参数里面塞xml;姿势B是整个body是xml(改 Content-Type 为 application/xml 强行切过去)。
姿势A:
后端代码有 $xml = $_POST['xml'] 这种写法——某个参数本身就是要收 XML 字符串。
1 | POST /pikachu/vul/xxe/xxe_1.php HTTP/1.1 |
xml=后面的一大坨是url编码的完整payload,注意书写的时候payload的原文要正确。
姿势B:
这里给到一个情景:假设目标是 POST /api/search,前端正常发 JSON 搜索。后端有段没加固的代码,能解析 XML(比如用 simplexml_load_string(file_get_contents(‘php://input’)))。
正常的请求:
1 | POST /api/search HTTP/1.1 ← ① |
攻击者的请求:换 Content-Type、换 body
1 | POST /api/search HTTP/1.1 ← ① 不动 |
其实就是利用有的老接口,同时注册了 JSON 和 XML 两套解析器,走json解析尝试用json注入可能没有漏洞,但是xml这个解析器可能从来没有人测过、可能完全没加固。