国内很多报了名的比赛大都是十月份左右才开始,所以协会里就提议打打国外的比赛,最近的就是这一场了,国外的比赛跟国内在题型上还是有很大的差别的,web题全是xss和js这种阴间题目,我们四五个人看了几个小时才解出了一道web,哎,终究还是不够努力
hello
<?php
/*
Read /next.txt
Hint for beginners: read curl's manpage.
*/
highlight_file(__FILE__);
$url = 'file:///hi.txt';
if(
array_key_exists('x', $_GET) &&
!str_contains(strtolower($_GET['x']),'file') &&
!str_contains(strtolower($_GET['x']),'flag')
){
$url = $_GET['x'];
}
system('curl '.escapeshellarg($url));
hiii o/
这一步很简单,主要就是绕过file和next的检测,array_key_exists('x', $_GET) &&!str_contains(strtolower($_GET['x']),'file') && !str_contains(strtolower($_GET['x']),'flag')
,这里的三个函数虽然不多见,但是猜也能猜个大概出来
array_key_exists():
判断传入的数组里有没有x这个键
str_contains():
和正则匹配的函数类似,匹配前面的参数里是否有后面参数中的关键词
strtolower():
将传入的字符串转为小写
可以看到,大小写绕过肯定是不行了,但是利用正则匹配绕过还是可以的
给了我们一个地址,访问一下,有这样一句话
did you know i can read files?? amazing right,,, maybe try /39c8e9953fe8ea40ff1c59876e0e2f28/read/?file=/proc/self/cmdline
那我们就照着他的意思读一下进程,里面有base64加密的密文,解码后得到这样的进程/bin/bun-1.0.2/app/index.js
拿到源码
const fs = require('node:fs');
const path = require('path')
/*
I wonder what is inside /next.txt
*/
const secret = '39c8e9953fe8ea40ff1c59876e0e2f28'
const server = Bun.serve({
port: 8000,
fetch(req) {
let url = new URL(req.url);
let pname = url.pathname;
if(pname.startsWith(`/${secret}`)){
if(pname.startsWith(`/${secret}/read`)){
try{
let fpath = url.searchParams.get('file');
if(path.basename(fpath).indexOf('next') == -1){
return new Response(fs.readFileSync(fpath).toString('base64'));
} else {
return new Response('no way');
}
} catch(e){ }
return new Response("Couldn't read your file :(");
}
return new Response(`did you know i can read files?? amazing right,,, maybe try /${secret}/read/?file=/proc/self/cmdline`);
}
return
}
});
我们重点关注这几行代码
if(path.basename(fpath).indexOf('next') == -1){
return new Response(fs.readFileSync(fpath).toString('base64'));
} else {
return new Response('no way');
}
path.basename():
这个函数会将我们传入的路径分割,将最后一个/后面的内容作为返回值
index.of():
也是相当于匹配字符串,如果没有就返回-1
fs.readFileSync(fpath).toString('base64'):
将读取到的文件用base64编码输出
我们猜测flag应该就在next.txt文件里面,但是如何绕过呢?既然basename()以最后一个/后面的内容作为返回值,我们不妨构造?file=/next.txt/1,这样返回的数据文件就是1,成功绕过了if条件,但是另一个问题来了,/next.txt/1这个文件肯定是不存在的,我们要想办法把/1截断,到这里你肯定会想到文件读取中的%00截断,没错我们最后的payload就是
?file=/next.txt%00/1
好好好,本来还想自己写的,明天直接抄了🐶
好好好,偷看我博客是吧