CSRF Reflected Alert (pwn.college)

Summary

We pivot a CSRF into a reflected XSS by sending the victim to /ephemeral?msg=..., which reflects msg directly into HTML. The attacker page at http://hacker.localhost:1337/ auto-navigates the victim to a URL containing <script>alert("PWNED")</script>, causing the alert to fire in http://challenge.localhost.


Start

The challenge provides two binaries:

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

  • ./victim launches a headless browser and visits the attacker site at http://hacker.localhost:1337/

We run:

cd /challenge
./server &

Finding the sink

The login page only shows a POST form:

curl -s http://challenge.localhost | rg -n "form|input|name="
            <form action=login method=post>
              Username:<input type=text name=username>
              Password:<input type=text name=password>
              <input type=submit name=submit value=Login>
            </form><hr>

That suggests the reflected GET is somewhere else. We discover routes and sinks by inspecting the server binary:

This reveals:

So /ephemeral?msg=... reflects msg into the response HTML without escaping.

Quick confirmation:


The sink (/ephemeral)

The handler effectively behaves like:

Because msg is inserted directly into HTML, it is a classic reflected XSS sink.


The CSRF pivot

We control http://hacker.localhost:1337/. The victim bot visits that URL automatically. We can use that page to force a GET request to:

That makes the victim browser execute the script on the target origin.


Avoiding the pitfall

Embedding <script>...</script> inside a <script> tag will terminate the attacker page's own script early.

Fix: build the closing tag dynamically:


Final attacker page

We serve this as /tmp/index.html so it is reachable at http://hacker.localhost:1337/:

Host it:


Triggering the victim

In another terminal:

The victim:

  1. Logs into http://challenge.localhost

  2. Visits http://hacker.localhost:1337/

  3. Gets redirected to /ephemeral?msg=...

  4. Executes the reflected XSS

Result: alert("PWNED").

Last updated

Was this helpful?