Prologue

An online CTF competition by ACSC, this competition is qualification for competing in ICC for ASIA category.

Transclude of login-web.tar.gz

Write Up

TL;DR Solution

The player sends array with guest value in username, the role check is strict-comparison of string “guest”, but the input is an array with guest value. This happen because there’s no check for type.

Detailed Explanation

Initial Analysis

We were given a simple server-side nodejs.

// ./app.js
// 8< -- snip - snip -- >8
const USER_DB = {
    user: {
        username: 'user', 
        password: crypto.randomBytes(32).toString('hex')
    },
    guest: {
        username: 'guest',
        password: 'guest'
    }
};
// 8< -- snip - snip -- >8
 
app.post('/login', (req, res) => {
    const { username, password } = req.body; //[1]
    if (username.length > 100) return res.send('Username is too long');
 
    const user = USER_DB[username]; //[2]
    if (user && user.password == password) {
        if (username === 'guest') { //[3]
            res.send('Welcome, guest. You do not have permission to view the flag');
        } else {
            res.send(`Welcome, ${username}. Here is your flag: ${FLAG}`);
        }
    } else {
        res.send('Invalid username or password');
    }
});
 
// 8< -- snip - snip -- >8

We can control the username, and password variable. And there’s no type check in this variable. Which mean, we can input a an object or array [1].

After that, the variable username is being used as key to access credentials in USER_DB variable [2]. So, when we input guest it will access the credentials with key guest. Our goals is to have access a non-guest user. But the password of user is being randomized and impossible to brute-force.

In javascript, when we access a key of object, the key input will be do a pre-processing into .toString() first.

Exploitation

Fortunately, our input doesn’t sanitized, and we can input an array in variable username [1]. By sending an guest array in requests, the username variable is an array and it will do a role check, a strict-comparison with string guest. Which mean it will return a false

FLAG: ACSC{y3t_an0th3r_l0gin_byp4ss}