๐ Cache It to Win It!
A detailed write-up of the Web challenge 'Cache It to Win It!' from LaCTF - 2025
๐ Challenge Overview
Category Details Additional Info ๐ Event LaCTF - 2025 Event Link ๐ฐ Category Web ๐ ๐ Points 500 Out of 500 total โญ Difficulty ๐ข Easy Personal Rating: 3/10 ๐ค Author burturt Profile ๐ฎ Solves (At the time of flag submission) 22 solve rate ๐ Date 08-02-2025 LaCTF - 2025 ๐ฆพ Solved By mH4ck3r0n3 Team: QnQSec
๐ Challenge Information
Are YOU today’s unlucky contestant in Cache! It! To! Win! It??????? Find out below!
cache-it-to-win-it.chall.lac.tf
Note: do NOT perform any sort of denial-of-service attack against the web server or databases, directly or indirectly.
๐ฏ Challenge Files & Infrastructure
Provided Files
Files:
๐ Initial Analysis
First Steps
Initially, the website appears as follows:
By taking a look at the attached files, I understood that the Flask application has a mechanism to assign unique UUIDs to users and allows them to check their progress to earn a reward (a “flag”). However, some vulnerabilities allow attackers to manipulate the UUIDs and bypass the caching system and the database to speed up the process. The
normalize_uuid
function mishandles the UUIDs, introducing inconsistencies, especially with the use of invisible characters (like zero-width characters). Manipulated UUIDs can pass the normalization and create different variants for the same key:
1 2 3 4 5 6 7 8 9
def normalize_uuid(uuid: str): uuid_l = list(uuid) for i in range(len(uuid)): uuid_l[i] = uuid_l[i].upper() if uuid_l[i] == "-": uuid_l.pop(i) uuid_l.append(" ") return "".join(uuid_l)
I noticed that simply adding a URL-encoded space character
%20
was enough to have a new validUUID
:As we can see, this generates a valid
UUID
, and since itโs a different key, the cache check fails, allowing us to win. I continued adding%20
, but I noticed that a maximum of13
wins can be achieved with this technique, so I started looking for other ways to exploit this vulnerability. In fact, as we can see from the following lines of code:
1 2
def make_cache_key(): return f"GET_check_uuids:{normalize_uuid(request.args.get('uuid'))}"[:64]
The check is done up to a maximum of
64
characters, which is why I was being blocked after13
wins with this method. So, starting to look for other variants, I tried using zero-width characters, like\u200
, and by doing so, I could construct enough variants of the UUID to reach a total of100 wins
. In addition to UUID normalization, there’s another issue that allowed me to exploit this vulnerability, which is that the caching system doesnโt account for changes made in the database, causing inconsistencies. The attacker can manipulate the cache to avoid proper updates and exploit the latency between the two systems.
1 2 3 4 5
@cache.cached(timeout=604800, make_cache_key=make_cache_key) def check(): user_uuid = request.args.get("uuid") run_query("UPDATE users SET value = value + 1 WHERE id = %s;", (user_uuid,)) res = run_query("SELECT * FROM users WHERE id = %s;", (user_uuid,))
The attacker manipulates the cache key to achieve a “cache hit” with outdated data, thus avoiding the proper increment of the counter in the database. This allows the attacker to accumulate wins without respecting the imposed limits. The attacker sends a large number of requests while manipulating the cache to bypass the limits (e.g., using zero-width characters to avoid cache hits). This is possible because the victory counter is incremented without any temporal or logical checks.
๐ฌ Vulnerability Analysis
Potential Vulnerabilities
- Web Cache Poisoning
๐ฏ Solution Path
Exploitation Steps
Initial setup
Now that we understand the type of vulnerability and how to exploit it, we can move on to the exploitation phase.
Exploitation
Obviously, creating
100
UUID variants manually seemed like a bit of a hassle, so I wrote a Python exploit to automate the process.
Flag capture
๐ ๏ธ Exploitation Process
Approach
The exploit generates
99
valid UUID variants and sends them to claim thewin
. Once it reaches 0, it checks the response for the flag and extracts it using a regex, printing it.
๐ฉ Flag Capture
Flag
Proof of Execution
๐ง Tools Used
Tool Purpose Python Exploit
๐ก Key Learnings
New Knowledge
I have learned how to exploit the web cache poisoning vulnerability on unsanitized data.
Skills Improved
- Binary Exploitation
- Reverse Engineering
- Web Exploitation
- Cryptography
- Forensics
- OSINT
- Miscellaneous
๐ References & Resources
Learning Resources
๐ Final Statistics
Metric | Value | Notes |
---|---|---|
Time to Solve | 00:15 | From start to flag |
Global Ranking (At the time of flag submission) | 13/679 | Challenge ranking |
Points Earned | 500 | Team contribution |
Created: 08-02-2025 โข Last Modified: 08-02-2025 Author: mH4ck3r0n3 โข Team: QnQSec