Skip to main content

Day 5: Naughty or Nice

challenge description
All the Santa's nice elves have been added to the naughty list by the wicked elves and Santa is mad! 
He asked you to hack into the admin account of the Naughty or Nice portal and retrieve the magic flag
that will let Santa finally banish the evil elves from the north pole!

Peeking at the source

Once again, it is great that the source code is provided. From the source code, we see a lot of content.

Database

The database was my first look into potential vulnerabilities to see if there are any methods which string concatenation is used so that it can be an easy win using SQL injections. However, it seems like the database SQL commands are all rather secure.

Routes

The routes show some potential areas of abuse. However, the AuthMiddleware seems to be checking for the username to be admin everytime a sensitive operation is performed. Hence, the first line of attack would be to upgrade the privilege to admin.

What's next?

Perhaps its time to try poking with the actual webpage.

Landing page

A great list of elves. It seems like we can register and login as any account other than admin.

After registering, we have to find someway to become an admin...

Denied admin page

Looking at the source, the JWT handler seems suspicious...

helpers/JWTHelper.js
    // <snip>
async sign(data) {
data = Object.assign(data, {pk:publicKey});
return (await jwt.sign(data, privateKey, { algorithm:'RS256' }))
},
async verify(token) {
return (await jwt.verify(token, publicKey, { algorithms: ['RS256', 'HS256'] }));
}
// <snip>

Why did it allow HS256 to verify? RS256 requires both a public and private key but HS256 only require a single password! In this case, if we are to change the algorithm to HS256, the publickey will be used as the secret and we can potentially forge a token!

Even better, the public key is provided as part of the key! Giving away the secrets for free! Such christmas spirit!

JWT

By taking the public key and putting it into a file formatted nicely, replacing all \n with new lines and base64 encoding it, we put it into jwt.io and obtain a new key with the username as admin and algorithm changed to HS256.

Forging token

Replacing the old token and voila!

Admin dashboard

What's next? Looking at the source code, it seems like nunjucks is used. Immediately, this reminds of Server Side Template Injection (SSTI)!

A closer look at the source reveals that the main page is actually vulnerable to it.

Helper/CardHelper.js
card = `
{% extends "card.html" %}
{% block card %}
<div class="card">
<div class="card-page cart-page-front">
<div class="card-page cart-page-outside"></div>
<div class="card-page cart-page-inside">
<p><span class='nheader green'>Nice List</span>
${NiceNames}
</p>
</div>
</div>
<div class="card-page cart-page-bottom">
<p><span class='nheader red'>Naughty List</span>
${NaughtyNames}
</p>
</div>
</div>
{% endblock %}
`;

It is simply putting the names there without any form of sanitisation. Following an online guide, we can inject custom code to perform arbitrary code injection!

Exploit

Changing the elf name to {{range.constructor("return global.process.mainModule.require('child_process').execSync('cat /flag.txt')")()}}, we get the flag!

Flag revealed

Flag

HTB{S4nt4_g0t_ninety9_pr0bl3ms_but_chr1stm4s_4in7_0n3}