0x00 前言
-
CTF 加解密合集
-
CTF Web 合集
-
网络安全知识库
0x01 题目
题目名称:新年好? 分值:10 出题人:Firebasky 题目链接:https://a203e2c7-672a-42c9-af31-723d99890d57.challenge.ctf.show

访问首页,直接返回 app.js 源码。
const express = require('express'); const fs = require('fs'); const flag = require('./flag') const app = express(); app.get('/flag', function (req, res) { function getflag(flag) { res.send(flag); } let delay = 10 * 1000; if (Number.isInteger(parseInt(req.query.delay))) { delay = Math.max(delay, parseInt(req.query.delay)); } const t = setTimeout(getflag, delay, flag); setTimeout(() => { clearTimeout(t); try { res.send('Timeout!'); } catch (e) { } }, 1000); }); app.get('/', function (req, res) { res.set('Content-Type', 'text/javascript;charset=utf-8'); res.send(fs.readFileSync('./app.js')); }); app.listen(3000, '0.0.0.0', () => { console.log('Start listening') })

0x02 Write Up
访问靶场首页,页面直接输出完整 js 源码,重点看两处setTimeout。
const t = setTimeout(getflag, delay, flag); setTimeout(() => { clearTimeout(t); try { res.send('Timeout!'); } catch (e) { } }, 1000);

setTimeout 语法:setTimeout(回调函数, 延迟毫秒, 参数)。延迟时间到达后,执行回调,后续参数会传给回调函数。 代码逻辑:
-
访问
/flag路由,读取 GET 参数delay,默认 delay=10000ms;如果传入合法整数 delay,取默认值和传入值的较大者。 -
开启定时器 t,delay 毫秒后执行 getflag,getflag 会直接把 flag 返回给页面。
-
同时开启第二个定时器,1000 毫秒后执行,清除定时器 t,页面返回 Timeout!。
正常情况下,delay 最小是 10000ms,大于 1000ms。第二个定时器会先触发,clearTimeout(t)取消 getflag 执行,页面输出 Timeout!,拿不到 flag。
知识点:Node.js 中 setTimeout 的延时参数使用32 位有符号整数 ,取值上限2147483647。当传入数字 > 2147483647,会发生整数溢出,数值截断,实际延时会变成一个很小的值。
我们传入delay=2147483648,这个数字超出上限,溢出后实际延时小于 1000ms。getflag 会优先执行,在 clearTimeout 执行之前返回 flag。
构造 Payload 访问: https://a203e2c7-672a-42c9-af31-723d99890d57.challenge.ctf.show/flag?delay=2147483648
页面直接返回 flag: {"FLAG":"ctfshow{496d2e3e-d6d0-4840-92c9-ac6c4df5a47f}"}
