csrf xss cookie (pwn.college)

Summary

We chain CSRF -> reflected XSS -> cookie theft. The victim bot always visits http://hacker.localhost:1337/, so we host an attacker page at / that redirects the victim to /ephemeral?msg=... with a <script> payload. That payload runs on http://challenge.localhost, reads document.cookie (not HttpOnly), and exfiltrates the admin cookie back to our server. We then replay the cookie to view the admin post (the flag).


Start

The challenge ships two binaries:

  • ./server runs the Flask app at http://challenge.localhost

  • ./victim launches the headless admin bot

Run the server:

cd /challenge
./server &

Understand the goal from server code

Key facts from server:

  1. Admin credentials are derived from the flag:

db.execute("""CREATE TABLE users AS SELECT "admin" AS username, ? as password""", [flag[-20:]])
  1. Successful login sets the cookie:

response.set_cookie('auth', username+"|"+password)
  1. Admin's flag post is already in the posts table:

If we can steal the admin cookie (auth=admin|<last_20_of_flag>), we can request / as admin and see the flag.


The reflected XSS sink

/ephemeral reflects a GET parameter directly into HTML:

That means:

is a reflected XSS sink. just like the previous challenge


Two-layer JavaScript plan

We need two scripts:

  1. Outer JS on http://hacker.localhost:1337/ -> constructs the payload and navigates the victim to /ephemeral?msg=....

  2. Inner JS inside the reflected XSS -> runs in challenge.localhost, steals document.cookie, and sends it back.

Because </script> inside a <script> tag breaks parsing, we split the closing tag:

We also URL-encode the payload to avoid special characters (+, <, >, spaces) breaking the URL.


Final attacker page

This page redirects the victim to the XSS URL:

Save it as /tmp/index.html so it is served at http://hacker.localhost:1337/:

Host it:


Trigger the victim

Expected server logs:

The /leak 404 is fine; the request still appears in the log.


From the http.server log, take the leaked cookie (URL-encoded):

Decode the cookie using CyberChef or any URL decoding website

Then reuse it:

You'll see the admin post (the flag).i'


Timeline view

Last updated

Was this helpful?