
Writeup de desafío CTF pwn que explota CVE-2021-4034 (pkexec) mediante manipulación del heap, con ingeniería inversa basada en Ghidra y un binario auxiliar personalizado shelly.so.
Este es un reto CTF de tipo pwn que escribí en C y que requiere que el usuario explote la vulnerabilidad CVE-2021-4034. Los jugadores reciben 2 binarios en el directorio challenge de este repositorio. El binario chal implementa el reto CTF y shelly.so es un binario auxiliar.
Al momento de escribir este writeup, el Dockerfile aún no está completo. El Dockerfile es necesario para desplegar este reto durante un CTF en vivo, pero no localmente: aún puedes emular este reto localmente configurando los permisos de usuario e instalando los paquetes vulnerables de la siguiente manera:
libpolkit-gobject-1-0=0.105-26ubuntu1 libpolkit-agent-1-0=0.105-26ubuntu1 policykit-1=0.105-26ubuntu1.flag.txt propiedad de root:root en el directorio actual.challenge al directorio actual.chal como el usuario sin privilegios.Ejecutar el binario chal nos da una idea vaga de lo que hace este binario:```
WELCOME TO THE HUB CTRL+ALT+DELICIOUS
We're not just a sandwich hub. We are the beacon of flavors, serving a symphony in every byte
Jugar con el tamaño de entrada en la función `Add` y con los índices de las funciones `Cancel` no nos da nada especial (sin desbordamiento ni fallo de segmentación). Sin embargo, algunas cosas interesantes:
- Parece que los pedidos se colocan en una lista (quizás una lista enlazada) y ¿están indexados desde 0?
- Hay este `Order number: 0x7ffde93681f0` que parece imprimir alguna ubicación en la pila?
- Además, el programa crea un directorio con nuestro nombre de entrada junto con 3 ejecutables, uno de los cuales es el archivo binario auxiliar que se nos proporciona:```sh
peasant@Tin-VM:~/Desktop$ ls
chal chal.c Dockerfile shelly.so solve.py tin
peasant@Tin-VM:~/Desktop$ ls -l tin/
total 28
-rwxrwx--- 1 peasant vboxsf 5 Feb 4 14:33 notes
-rwxrwx--- 1 peasant vboxsf 20 Feb 4 14:33 recipe
-rwxr-x--- 1 peasant vboxsf 16488 Feb 4 14:33 shelly.so
peasant@Tin-VM:~/Desktop$ cat tin/notes
0000
peasant@Tin-VM:~/Desktop$ cat tin/recipe
aaaa
bbbb
cccc
dddc
Los ejecutables contienen nuestra entrada.
Puedes jugar con las demás funciones y esperar a toparte con algunos bugs (lo cual es probable), pero voy a ir al grano y abrir el programa en Ghidra.
Comparando las cadenas que aparecen al ejecutar el programa con las cadenas presentes en Ghidra, podemos renombrar algunas de las funciones FUN_* con nombres familiares:```C
undefined8 main(void)
{ int iVar1; size_t sVar2; undefined2 *puVar3; long in_FS_OFFSET; int opt; int local_1c; char *local_18; long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28); local_18 = "/recipe"; print("WELCOME TO THE HUB CTRL+ALT+DELICIOUS\n"); print( "We're not just a sandwich hub. We are the beacon of flavors, serving a symphony in every by te\n\n" ); while( true ) { print("1. ENTER THE HUB\n"); print("2. QUIT\n"); __isoc99_scanf(&DAT_001030c5,&opt); getc(stdin); if (opt != 1) break; printf("Order number: %p\n",&local_18); print("Enter your name: "); __isoc99_scanf(&DAT_0010334f,&DAT_00105120); sVar2 = strlen(&DAT_00105120); puVar3 = (undefined2 *)malloc(sVar2 + 2); DAT_00105100 = puVar3; *puVar3 = 0x2f2e; *(undefined *)(puVar3 + 1) = 0; strcpy((char *)(DAT_00105100 + 1),&DAT_00105120); iVar1 = FUN_001022f0(DAT_00105100,&DAT_00105060); if (iVar1 == -1) { mkdir((char *)DAT_00105100,0x1c0); } DAT_00105140 = 0; order_cnt = 0; for (local_1c = 0; local_1c < 10; local_1c = local_1c + 1) { *(undefined8 *)(&ptr_array + (long)local_1c * 8) = 0; } main_menu(); } print("Come again :)\n");
The `printf("Order number: %p\n",&local_18);` **imprime la ubicación de una variable local en la pila.**
Una verificación rápida en gdb nos muestra que la dirección filtrada es la dirección del puntero a la cadena constante `/recipe`:```gdb
...
Order number: 0x7fffffffdfc0
...
gef➤ x/gx 0x7fffffffdfc0
0x7fffffffdfc0: 0x0000555555559020
gef➤ x/s 0x0000555555559020
0x555555559020: "/recipe"
Vemos una llamada a mkdir, que crea un directorio con nuestro nombre de entrada en el directorio actual.