This month intigriti was developed by **@LooseSecurity and the goal was to achieve an xss.**
Let’s take a look at the code of the challenge.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./xss_files/bootstrap.min.css">
<title>Contact Info</title>
</head>
<body>
<div class="container mt-4">
<h1>Set Contact Info</h1>
<div class="form-group">
<label for="inpName">Name</label>
<input type="text" class="form-control" id="inpName">
</div>
<div class="form-group">
<label for="inpContact">Contact</label>
<input type="text" class="form-control" id="inpContact">
</div>
<div class="form-group">
<label for="inpValue">Value</label>
<input type="text" class="form-control" id="inpValue">
</div>
<button class="btn btn-primary"
onclick="handleInputName(document.getElementById('inpName').value, document.getElementById('inpContact').value, document.getElementById('inpValue').value);">Input</button>
<button class="btn btn-secondary" onclick="runCmdName('alert');">Info</button>
<h1 class="mt-4">Set Token</h1>
<div class="form-group">
<label for="inpToken">Token</label>
<input type="text" class="form-control" id="inpToken">
</div>
<button class="btn btn-primary"
onclick="handleInputToken(document.getElementById('inpToken').value);">Input</button>
<button class="btn btn-secondary" onclick="runCmdToken('alert');">Info</button>
</div>
<script src="./xss_files/core.js"></script>
<script src="./xss_files/md5.js"></script>
<script>
var user = {};
function runCmdToken(cmd) {
if (!user['token'] || user['token'].length != 32) {
return;
}
var str = `${user['token']}${cmd}(hash)`.toLowerCase();
var hash = str.slice(0, 32);
var cmd = str.slice(32);
eval(cmd);
}
function handleInputToken(inp) {
var hash = CryptoJS.MD5(inp).toString();
user['token'] = `${hash}`;
}
function runCmdName(cmd) {
var name = Object.keys(user).find(key => key != "token");
if (!name) {
return;
}
var contact = Object.keys(user[name]);
if (!contact) {
return;
}
var value = user[name][contact];
if (!value) {
return;
}
eval(`${cmd}('Name: ' + name + '\\\\nContact: ' + contact + '\\\\nValue: ' + value)`);
}
function handleInputName(name, contact, value) {
user[name] = { [contact]: value };
}
const urlParams = new URLSearchParams(window.location.search);
const nameParam = urlParams.get("setName");
const contactParam = urlParams.get("setContact");
const valueParam = urlParams.get("setValue");
const tokenParam = urlParams.get("setToken");
const runContactInfo = urlParams.get("runContactInfo");
const runTokenInfo = urlParams.get("runTokenInfo");
if (nameParam && contactParam && valueParam) {
handleInputName(nameParam, contactParam, valueParam);
}
if (tokenParam) {
handleInputToken(tokenParam);
}
if (runContactInfo) {
runCmdName('alert');
}
if (runTokenInfo) {
runCmdToken('alert');
}
</script>
</body>
</html>
Here’s a breakdown of the code
The code imports two JavaScript files: core.js
and md5.js
.
Initializes an empty object called user
which will store user data.
Then there are the main functions of the code
runCmdToken(cmd)
:
cmd
) based on a token.user
object and if it is of the correct length (32 characters).str
) by concatenating the token with the command and appending "(hash)" to it.eval()
to execute the command.handleInputToken(inp)
:
inp
) using MD5 hashing algorithm.CryptoJS.MD5()
function and converts it to a string.user
object.runCmdName(cmd)
:
cmd
) based on user's name, contact, and value.user
object (excluding the token).eval()
.handleInputName(name, contact, value)
:
user
object.user
object where the name serves as the key, and the contact and value are stored as properties of this nested object.setName
, setContact
, and setValue
parameters are provided, it calls handleInputName
to store the data. If setToken
parameter is provided, it calls handleInputToken
to generate a token.runContactInfo
is set, it calls runCmdName
to execute a command based on user's name, contact, and value. If runTokenInfo
is set, it calls runCmdToken
to execute a command based on the token.The code is not that long but we need to delve and analyze it properly.
So the first thing that we notice is the use of eval
that would make a light tick.
However it is used into two different functions. The first function deal with the token and it is moreover alerted the value of the hash of the token and for this reason i decided to leave it for later and put my attention on the second eval
.
However the syntax used is the following eval(
${cmd}('Name: ' + name + '\\nContact: ' + contact + '\\nValue: ' + value))
I tried in different way to achieve an xss but i came to the conclusion that is not possible to break out of the quotes and perform an xss, so a new way needed to be found.
Leaving apart the runCmdName
function we are left with 3 others functions, let’s analyze them more in depth