安全街
一步步,我们的信息安全时代

现在谈到注入大部分人都以为是SQL注入,其实不然,注入有很多种类:

  • SQL注入
  • HTML注入
  • 命令注入
  • Xpath注入
  • XML实体注入

而最后一种正是本文的主角,也被称为XXE
看到XXE这个名字第一眼以为是和XSS差不多,只不过是XML上的XSS,其实它俩一点关系都没有。XXE可以被用来读取任意文件执行系统命令探测内网,危害巨大。

基于XML的功能

XML可不仅仅和HTML一样只用作标记。XML有着强大的功能和严谨的格式。对于很多的基础在此不作详述,W3school上讲的很清楚。着重说一下在XXE中用处比较大的功能。

  • 1. DTD简介
    DTD是一种XML书写规范,我们可以自定义DTD来约束一个XML文档应该有什么标签,它们的嵌套格式等。DTD的作用如下:

    • 对这个XML的格式进行一个描述
    • 可以利用DTD来规范化XML,便于传输数据
    • 可以利用定义好的DTD来验证接受到的XML,看它是否符合这个格式,若不符合会报错。

      网上说XML由浏览器直接打开时,仅在IE下才会实用DTD来验证XML是否符合定义的规范,其他浏览器下是不会报错的。这个有待商榷,笔者实用IE浏览器也未能报错不符合DTD规范的XML。不过可以确定的是,在各类后端语言中,都有着验证XML是否符合DTD规范的功能。在这里赞不深究,因为这不是XXE的重点。

    • DTD中可以定义实体,利用各种协议来操作外部资源。这也是XXE中至关重要的一点。
  • 2. 一个简单的DTD示例
    <!DOCTYPE root [
    <!ELEMENT root (a,b,c)>
    <!ELEMENT a (#PCDATA)>
    <!ELEMENT b (#PCDATA)>
    <!ELEMENT c (#PCDATA)>
    ]>

    上面是一个简单的DTD,简单来解释一下:

    • 第1行,定义了根元素名字叫root
    • 第2行,描述了根元素root有三个子元素abc
    • 第3、4、5行,描述了元素abc的类型为PCDATA类型。

      类型分为CDATA和PCDATA。其中PCDATA是将会被解析的文本(比如将&lt;转义为<),而CDATA是不会被解析的文本。

  • 3. DTD参与的XML
    利用上面那个DTD,我们应该写出以下XML

    <?xml version='1.0'?>
    <!DOCTYPE root [ 
    <!ELEMENT root (a,b,c)>
    <!ELEMENT a (#PCDATA)>
    <!ELEMENT b (#PCDATA)>
    <!ELEMENT c (#PCDATA)>
    ]>
    <root>
    <a>haha</a>
    <b>lala</b>
    <c>papa</c>
    </root>

    其中第1行为XML声明,2~7行为上述DTD,8~12行为XML文档。

  • 4. DTD中的实体
    DTD中的实体相当重要,在ENTITY标签中定义,格式为<ENTITY 名称 "数据">。所谓实体,可以简单的理解为string 名称="数据"。然后在XML文档中可以以&名称;来调取定义好的数据。相当于取常量名一样。写一个例子:

    <?xml version='1.0'?>
    <!DOCTYPE root[
    <!ELEMENT root (a,b,c)>
    <!ELEMENT a (#PCDATA)>
    <!ELEMENT b (#PCDATA)>
    <!ELEMENT c (#PCDATA)>
    <!ENTITY d "heihei">
    ]>
    <root>
    <a>haha</a>
    <b>lala</b>
    <c>&d;</c>
    </root>

    输出为:

    <root>
    <a>haha</a>
    <b>lala</b>
    <c>heihei</c>
    </root>

    DTD中还支持参数实体,不过因为对XXE用处不大,在此不做详述。

  • 5. DTD的引入方式
    DTD的引入方式有多种,在此只说两种:

    • 内部DTD
      内部DTD就是写在XML内部的DTD,DTD与XML文档本身写在一起。上面的XML示例便使用的内部DTD。
    • 外部DTD
      外部DTD又分为公有和私有,在这里完全不用纠结这个问题,一律使用私有SYSTEM
      下面给出一个示例,1.xml引用和它同目录的2.dtd。
      1.xml

      <?xml version='1.0'?>
      <!DOCTYPE root SYSTEM "2.dtd">
      <root>
      <a>haha</a>
      <b>lala</b>
      <c>&c;</c>
      </root>

      2.dtd

      <?xml version="1.0"?>
      <!DOCTYPE root [ 
      <!ELEMENT root (a,b,c)>
      <!ELEMENT a (#PCDATA)>
      <!ELEMENT b (#PCDATA)>
      <!ENTITY c "heihei">
      ]>
      

      正常来说,正常解析应该如下:

      <root>
      <a>haha</a>
      <b>lala</b>
      <c>heihei</c>
      </root>
      

      但是现代浏览器大多数已经不支持引入外部实体不支持使用DTD验证XML。因此在浏览器中直接打开会出现c未定义的错误。另外在PHP下这段代码仍然失败,不支持外部DTD的引入。因此建议使用内部DTD的方式。

XXE的诞生

  • 1.协议
    上节说了XML与DTD的简单入门,这些都是XXE的知识储备。其中第4点讲到了DTD实体,通过一种类似于定义常量的方式,可以在XML中使用常量名来引入常量。这个”常量“并不仅仅能写成字符串的形式,事实上,它支持很多协议。例如:httphttpsfileftp等常见协议。如www.target.com下的a.txt内容为"heihei"。写出以下XML:

    <?xml version='1.0'?>
    <!DOCTYPE root[
    <!ELEMENT root (a,b,c)>
    <!ELEMENT a (#PCDATA)>
    <!ELEMENT b (#PCDATA)>
    <!ELEMENT c (#PCDATA)>
    <!ENTITY d "http://www.target.com/a.txt">
    ]>
    <root>
    <a>haha</a>
    <b>lala</b>
    <c>&d;</c>
    </root>
    

    a.txt的内容就会被读取出来:

    <root>
    <a>haha</a>
    <b>lala</b>
    <c>heihei</c>
    </root>
    
  • 2. 利用
    有了这些协议我们就可以干很多事了。比如XXE最常用的file协议,可以用来读取目标机器上所有本地文件。假如目标机器是Linux系统,传送一个这样的XML:

    <?xml version='1.0'?>
    <!DOCTYPE root[
    <!ENTITY xxe "file:///etc/passwd">
    ]>
    <x>&xxe;</x>
    

    若这个XML被正常解析,便会将目标机器的密码暴露出来。除此之外,XXE还能做很多攻击,思想都是利用这样的实体注入来达到自己的目的。具体的利用方式及姿势,会在下篇博文再进行探讨。

*本文为原创,作者T1dDl3R,首发于本博客。转载请注明

这篇文章还没有人发言,快抢第一!

发表评论