VERE - Web-2 - Notes1
Published at Jan 25, 2025

Here’s my new note-tracking server! GitHub Copilot made most of it, so I’m sure there’s no problems with it.
Your goal (as you should be able to see in the code) is get the admin bot to share the note with you through a POST-based CSRF attack. If it was just GET-based, you could have it visit a link like http://127.0.0.1:1337/share?user=yourusername or something, but that’s not the case. INSTEAD, you have to make it visit a publicly-available website that you own; once they navigate to that site, the webpage the admin bot lands on should automatically fill out a form and submit it (using POST) to http://127.0.0.1:1337/your_path to perform your desired behavior. Note that every time you send a link to the admin bot, it logs into the admin account on 127.0.0.1:1337 first.
If you don’t have a publicly-available web server, look into using something like ngrok with a free account (link).
Don’t be intimidated by the size of the server, you don’t need to worry about the login functionality (although if you can break it props to you I guess). In addition, most of the application understanding should be able to come from simply interacting with the server.
This challenge focuses on exploiting a CSRF vulnerability in a web application to trick an admin bot into sharing a note with the attacker. The attacker must create a malicious webpage to conduct the attack. The admin bot uses POST requests for the /share
endpoint, making it resistant to basic GET-based CSRF attacks.
First Look
The first thing I did was click on the supplied links.
The Notes Server
I was greeted with a blank login screen with a link to register a user. I made a user hesapirate
and logged in. I can now see the home screen, with two links to View notes
and Logout
. Clicking on View notes
brought me to en empty screen that I was hoping would do as it was titled and show me my notes.

I can now see that there are options to Create a note and to Share a note. Creating a note makes that note appear within the Notes
section with a generated ID.

Going to the share note section presents the fields Note ID
and User
. This Note ID
appears to be how the notes are kept distinct, and will likely be the vector I need to have the admin bot share it’s flag note with my user.

The Admin Bot
Visiting the admin bot page presents a field for user input inviting the user to “Have the admin bot visit a page”

Submitting a URL makes the Go
button temporarily turn into Visiting page...
, until this alert pops up on the screen indicating that it performed its function:

Let’s break down the code and see if we can learn anything more about these pages and how they work.
Analyzing the Code
Admin Bot (
admin_bot.js
):- Automate browser actions as if it were a legitimate user.
- Operates under the username
admin
- Visits a URL provided by the user into the admin_bot webpage.
Server (
server.py
):Creates a basic note sharing webpage that allows for logging in, creating and viewing of notes, with unique IDs applied to each specific note.
Implements a
/share
endpoint that requires a POST request with two parameters:note_id
: A 32-character identifier for the note.user
: The recipient’s username.
We can also see that the flag is within the note with these parameters:
"note":FLAG, "user":"admin", "id":"00000000000000000000000000000000",
Validates
note_id
anduser
fields and adds the user to theshared
list if validation passes.
Additional things to note:
- The bot must visit a publicly available page controlled by the attacker.
- The page must trigger a POST request to
http://127.0.0.1:1337/share
from the bot. - Based on the parameters for the note containing the flag, we know that we need to have the bot share it’s note with ID 00000000000000000000000000000000 to our user.
Exploitation
To exploit this notes server, we need to craft a webpage that includes a form targeting the /share
endpoint, prefills the required fields (note_id
and user
), and submits the form automatically upon page load.
In order to achieve this, I wrote an HTML (index.html
) page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSRF Attack</title>
</head>
<body>
<form id="csrfForm" action="http://127.0.0.1:1337/share" method="POST">
<input type="hidden" name="note_id" value="00000000000000000000000000000000">
<input type="hidden" name="user" value="hesapirate">
</form>
<script>
document.getElementById('csrfForm').submit();
</script>
</body>
</html>
My page provides prefilled values for the note_id
and user
fields, set to the desired note id and my own user. The admin bot will visit the page and submit the form, effectively sharing its own note with the flag on it with my user.
I hosted the page on my home server, supplied it a domain from my private DNS server, and provided it to the admin bot. Somehow, though, I wasn’t seeing any results. Realizing this was because my infrastructure revolves around containing everything within my network, and then tunneling my personal traffic through a self-hosted VPN in order to still access it. So, while I could pull up my site and see the HTTP request in my logs, the bot was only seeing a 404 because my personal domain does not exist outside of my own network. The solve would work if I were to host the challenge locally, however, in order to get the real flag I’d need to go public.
I turned to the author’s suggested tool ngrok, learned how to host a public server, and pointed it to my html page.
Using Ngrok, my HTML file can be hosted as follows:
Start a local web server (e.g., Python’s
http.server
):python -m http.server 8080
Start Ngrok:
ngrok http 8080
When I provide the new ngrok URL https://c172-136-36-47-57.ngrok-free.app to the admin bot, the bot logs in, navigates to the provided URL, and submits the form. The
/share
endpoint processes the POST request, sharing the note with my account (hesapirate, which was hardcoded into my html form), and revealing the flag on my dashboard!
vere{csrf_can_work_for_some_POST_requests_too_688e29f4bdb3}