redpwnCTF - tux fanpage

Posted on June 25, 2020* in ctf-writeups

Challenge

My friend made a fanpage for Tux; can you steal the source code for me?

Site: tux-fanpage.2020.redpwnc.tf

We're also given the source code:

Local File Inclusion

When we open the site we're greeted by a wonderfully-designed site. The URL also includes a path parameter: https://tux-fanpage.2020.redpwnc.tf/page?path=index.html. Looking at the source code shows us that the path is used to load a file from the file system after a series of checks:

//Prevent directory traversal attack
function preventTraversal(dir){
    if(dir.includes('../')){
        let res = dir.replace('../', '')
        return preventTraversal(res)
    }

    //In case people want to test locally on windows
    if(dir.includes('..\\')){
        let res = dir.replace('..\\', '')
        return preventTraversal(res)
    }
    return dir
}

//Get absolute path from relative path
function prepare(dir){
    return path.resolve('./public/' + dir)
}

//Strip leading characters
function strip(dir){
    const regex = /^[a-z0-9]$/im

    //Remove first character if not alphanumeric
    if(!regex.test(dir[0])){
        if(dir.length > 0){
            return strip(dir.slice(1))
        }
        return ''
    }

    return dir
}

There's no clear way to bypass these checks.

Express.js Query Parsing

Express, by default, uses the npm package qs to decode query parameters.

qs can parse certain query parameters into strings and objects. However, the parameters we choose need to pass the validation. Using an object fails when reaching preventTraversal because includes is not a function on objects. Using an array works, but ../ is still removed from the array in preventTraversal

Nested Arrays

Using a nested array bypasses the 'includescheck because a string cannot equal an array (even in Javascript). This leads to the final solution:https://tux-fanpage.2020.redpwnc.tf/page?path[0]=a&path[1][1]=../../../index.js`, and we find the flag:

flag{tr4v3rsal_Tim3}