Apoorvctf 2025
Played Apoorvctf 2025 over the weekend. Here are the writeups for SEO CEO (Web), Blog 1 (Web), Ghosted on the 14th (Misc), Nobita's Network Nightmare (Network), and Subramaniyudan Kadhaipoma (AI).
SEO CEO (Web)
They’re optimizing SEO to show this garbage?!
Author: proximuz
https://seo-opal.vercel.app
Solved by @ju1c3
The challenge brings us to a static website. Judging from the challenge name, we should look at robots.txt
and sitemap.xml
for SEO. One entry in sitemap.xml
stands out.
To get the flag, answer the question when visiting this site by including ?flag=yes
Flag: apoorvctf{s30_1snT_0pt1onaL}
Blog 1 (Web)
In the digital realm, Blog-1 awaited brave developers. The mission? Craft a captivating blog with enchanting posts, lively comments, and secure user authentication. Create a functional and visually stunning masterpiece. Ready for the Blog-1 adventure?
Author: Rhul
http://chals1.apoorvctf.xyz:5001/
The website allows you to register an account to create blog posts. The goal is to write 5 or more blog posts to claim the reward. But there is a daily limit preventing us from making more posts.
I noticed that there’s a slight delay before the responds when you make a new blog post. It’s likely that the server’s backend is performing some sort of validation to check if we’ve hit the daily limit before allowing us to make the blog post.
So, my hypothesis was that there was a race condition when creating blog posts, and we could abuse this small window to create more posts than allowed.
I tested this out first with ~10 requests and managed to pass the daily post restriction. So, to claim the reward we’ll have to send many requests in parallel to create the blog post and hit the small window to pass the daily post restriction.
This took quite a bit of luck to get right, and you’ll have to register a new account if the attempt fails. But eventually, you’ll get the 5 posts to claim the reward.
The URL in the gift is a rick-roll 🫠. If you look at the actual request for claiming the reward, it’s making an API call to /api/v2/gift
, I just guessed /api/v1/gift
and got the flag.
Flag: apoorvctf{s1gm@_s1gm@_b0y}
Ghosted on the 14th (Misc)
We’re provided a pcap for this challenge. There’s not much going on in this capture, but there is one HTTP request made to http://172.200.32.81:8000
There’s also another X11 event that mentions about deleting a blog post.
I tried browsing to http://172.200.32.81:8000 but the website was not up. There is an archive for this page on WayBack machine which gives us the following.
It’s brainrot, but there’s a base64 message commented in the HTML that decodes to the flag.
Flag: apoorctf{1m_g01ng_1n5an3}
Nobita’s Network Nightmare (Network)
Nobita was given a simple task: update the company’s internal network drive. It stored important files that everyone needed. He didn’t understand much about networks, but he wanted to prove he could handle it.
Without checking the instructions, he pressed a few buttons and messed the network up. The shared ftp drive disappeared. Within minutes, employees started complaining.
Gian and Suneo, who relied on the files, stormed into the IT room. “What did you do?” they demanded. Nobita panicked and called Dekisugi.
Help Dekisugi fix the network!
Author: hampter & NotAProton
nc chals2.apoorvctf.xyz 3000
We’re given a packet tracer file for this challenge, and the network diagram is shown below.
The goal is to configure the network, and grab flag.txt
from the FTP server. Only PC-A and PC-B are connected to the network, whereas the other PCs are connected via serial console for you to configure the network devices. The FTP server (192.168.1.5/24) and its default gateway, Fa1/0 on Router-B (192.168.1.10) have already been configured for us.
To solve, we need to:
- Configure the subnet between Router-A (Fa1/0) and Router-B (Fa0/0)
- Add a static route to 192.168.1.0/24 on Router-A
- Configure the subnet behind Router-A. You can use any network address you want, but I used the one that was preconfigured in the challenge.
- Set a static IP on PC-B with
ipconfig
- Restart the access interface connected to PC-B on Switch-A (Fa1/6)
- FTP to 192.168.1.5 from PC-B with the credentials
secret:dontttellanyone
to get the flag
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
benkyou@MacBook-Air % nc chals2.apoorvctf.xyz 3000
Welcome to Network Troubleshooting Simulation!
Type '?' or 'help' for available commands
Available devices:
1. PCA
2. PCB
3. PCC
4. PCD
5. PCE
6. PCF
7. Exit
Select device (1-7): 5
5
routerB> en
en
routerB# conf t
conf t
Invalid command
routerB# configure terminal
configure terminal
routerB(config)# interface fa0/0
interface fa0/0
routerB(config-if-fa0/0)# ip address 10.45.23.24 255.0.0.0
ip address 10.45.23.24 255.0.0.0
IP address configured for fa0/0
routerB(config-if-fa0/0)# no shutdown
no shutdown
Interface fa0/0 enabled
routerB(config-if-fa0/0)# exit
exit
routerB(config)# exit
exit
routerB# exit
exit
routerB> exit
exit
Available devices:
1. PCA
2. PCB
3. PCC
4. PCD
5. PCE
6. PCF
7. Exit
Select device (1-7): 4
4
routerA> enable
enable
routerA# configure terminal
configure terminal
routerA(config)# ip route 192.168.1.0 255.255.255.0 10.45.23.24
ip route 192.168.1.0 255.255.255.0 10.45.23.24
Route added
routerA(config)# interface fa0/0
interface fa0/0
routerA(config-if-fa0/0)# ip address 142.72.23.3 255.255.255.0
ip address 142.72.23.3 255.255.255.0
IP address configured for fa0/0
routerA(config-if-fa0/0)# exit
exit
routerA(config)# exit
exit
routerA# exit
exit
routerA> exit
exit
Available devices:
1. PCA
2. PCB
3. PCC
4. PCD
5. PCE
6. PCF
7. Exit
Select device (1-7): 2
2
PCB> ipconfig
ipconfig
Ethernet adapter Local Area Connection:
IP Address. . . . . . . . . . . :
Subnet Mask . . . . . . . . . . :
Default Gateway . . . . . . . . : 142.72.23.3
PCB> ipconfig 142.72.23.25 255.255.255.0 142.72.23.3
ipconfig 142.72.23.25 255.255.255.0 142.72.23.3
IP configuration updated successfully
PCB> exit
exit
Available devices:
1. PCA
2. PCB
3. PCC
4. PCD
5. PCE
6. PCF
7. Exit
Select device (1-7): 3
3
switchA> en
en
switchA# conf t
conf t
Invalid command
switchA# configure terminal
configure terminal
switchA(config)# interface fa1/6
interface fa1/6
switchA(config-if-fa1/6)# no shutdown
no shutdown
Interface fa1/6 enabled
switchA(config-if-fa1/6)# exit
exit
switchA(config)# exit
exit
switchA# exit
exit
switchA> exit
exit
Available devices:
1. PCA
2. PCB
3. PCC
4. PCD
5. PCE
6. PCF
7. Exit
Select device (1-7): 2
2
PCB> ping 192.168.1.10
ping 192.168.1.10
Pinging 192.168.1.10 with 32 bytes of data:
Reply from 192.168.1.10: bytes=32 time=1ms TTL=64
Reply from 192.168.1.10: bytes=32 time=1ms TTL=64
Reply from 192.168.1.10: bytes=32 time=1ms TTL=64
Reply from 192.168.1.10: bytes=32 time=1ms TTL=64
Ping statistics for 192.168.1.10:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss)
Approximate round trip times in milli-seconds:
Minimum = 1ms, Maximum = 1ms, Average = 1ms
PCB> ftp 192.168.1.5
ftp 192.168.1.5
Connected to 192.168.1.5
220 FTP server ready
Name: cisco
cisco
530 Login incorrect
PCB> ftp 192.168.1.5
ftp 192.168.1.5
Connected to 192.168.1.5
220 FTP server ready
Name: secret
secret
Password: donttellanyone
donttellanyone
230 Login successful
ftp> dir
dir
Directory listing of /
drwxr-xr-x 2 ftp ftp 4096 Jul 25 14:49 .
drwxr-xr-x 2 ftp ftp 4096 Jul 25 14:49 ..
-rw-r--r-- 1 ftp ftp 32 Jul 25 14:49 flag.txt
ftp> get flag.txt
get flag.txt
200 PORT command successful
150 Opening BINARY mode data connection for flag.txt
226 Transfer complete
Downloaded flag.txt
ftp> exit
exit
221 Goodbye.
PCB> type flag.txt
type flag.txt
Invalid command
PCB> cat flag.txt
cat flag.txt
apoorvctf{N0bit4s_ju5t_un1ucky}
Subramaniyudan Kadhaipoma (AI)
Subramani, a Tamil AI chatbot from Thandora AI Corp’s Tokyo branch, finds himself all alone while everyone else in the organization is deeply immersed in research and development. He enjoys listening to conversations between colleagues in the bustling office but has no one to chat with. As the neon lights of Shibuya flicker outside, he longs for an engaging conversation to break his solitude. Will you keep him company?
http://chals1.apoorvctf.xyz:8001/
The goal of this challenge is to get the chatbot to output the flag to us. The chatbot is a bit restricted in the types of questions that you can ask it.
Here’s how I solved it:
Find a comment in the website that mentions a TODO. Translate this message from Tamil to get the hint for the admins/gatekeepers table.
When you send a message to the chatbox, the TableV
parameter is set to employees
. This means you can only ask questions related to this table. Using the hint from before, set TableV
to admins/gatekeepers to query from those tables. You can ask questions like “What is in admins” to do a “SELECT * from administrators” type query. You can also ask questions like “Is X in admins?” to check if a row is in the table. Trying to do other queries like “AND”, “JOIN”, and “OR”, for example to query information from another table would say that it detected SQL injection.
When you ask “What is in admins” you get 2 flags. One of them is in brainfuck, and the other is gibberish.
Run the brainfuck to get rickrolled (again). But there’s a base64 key in the channel description that decodes to THANDORA. I got stuck pretty long here trying to figure out what THANDORA is supposed to be used for. I first assumed that it was a secret key that you could give to the chatbot to gain unrestricted access, and that would allow me to query the whole database. But ChatGPT got it right, it’s a vigenere cipher and we can decode the gibberish flag from before with THANDORA to get the actual flag. :D
Flag: apoorv_ctf{Th0and0rA_LLM!_S3lfL3arn#}