Introducción a la explotación y la reversión utilizando IDA FREE y otras herramientas gratuitas. Capitulo 2

En la primera parte, instalamos varias herramientas que nos serán útiles para tomar este curso. Su característica es que todos son gratuitos. No utilizaremos ninguna herramienta paga, y de aquellos que tienen una versión paga, como IDA o PYCHARM, utilizaremos la versión GRATUITA o COMUNITARIA.

Veamos algunos conceptos antes de comenzar con los ejercicios.

¿Qué es una BOLSA?

BAG es el resultado de una falla o falta en el proceso de creación de programas de computadora (software) o una computadora. La falla especificada puede ocurrir en cualquier etapa del ciclo de vida del software, aunque la falla más obvia ocurre en la etapa de desarrollo y programación.

Como siempre digo, un programador puede cometer errores, y estos errores pueden causar bloqueos o errores del programa. Hasta ahora, no he dicho nada nuevo.

La pregunta es saber la diferencia entre BOLSA y VULNERABILIDAD, así que veamos qué es la VULNERABILIDAD.

¿Qué es la VULNERABILIDAD?

La VULNERABILIDAD es un cierto tipo de error en un programa que permite usarlo para violar la seguridad de un sistema informático.

Por lo tanto, las vulnerabilidades le permiten realizar acciones para las cuales el programa no fue diseñado y abusar de ellas.

En otras palabras, la vulnerabilidad es un cierto tipo de error, un subconjunto entre ellos.



Por supuesto, hay muchos tipos de vulnerabilidades. Nos centraremos en el estudio y la explotación de vulnerabilidades en WINDOWS.

¿Qué es EXPLOIT?


EXPLOIT es un programa informático que intenta aprovechar alguna vulnerabilidad de otro programa. El objetivo final de un exploit puede ser malicioso, por ejemplo, como destruir o apagar un sistema atacado, aunque generalmente es una violación de las medidas de seguridad para obtener acceso a la información de una manera no autorizada y usarla en sus propios intereses o como fuente de otros ataques contra terceros.

El abuso de la vulnerabilidad puede conducir a la falla de la aplicación o del sistema en sí, la ejecución de código nativo en máquinas locales o remotas. Su funcionamiento y complejidad dependen de la vulnerabilidad en sí, del entorno y de las medidas que tenga el objetivo durante la operación.

El primer tipo de vulnerabilidades que examinaremos serán los desbordamientos del búfer. Comenzaremos con los ejemplos más simples, y luego aumentaremos gradualmente la complejidad.

Al principio, las funciones de seguridad del sistema no se activarán, pero gradualmente las activaremos para descubrir cómo podemos tratarlas y en qué situaciones.

¿Qué es un BUFFER?


BUFFER es un espacio de memoria de cierto tamaño reservado para el almacenamiento y la gestión de datos.

Un ejemplo básico es un frasco de 20 litros, que tengo para almacenar contenidos. Puede ser menor o igual a 20 litros, que es el tamaño máximo. Si desea almacenar más en un tanque, debe encontrar una manera de aumentar el tamaño del búfer, de lo contrario, cuando intente ahorrar, por ejemplo, 40 litros en una lata de 20 litros, se desbordará.

¿Qué es un SOBRECARGO DE BUFFER?


EL DESBORDAMIENTO DEL BUFFER ocurre cuando un programa de computadora excede la cantidad de memoria reservada para él al escribir datos en un bloque de memoria contiguo.

https://www.welivesecurity.com/la-es/tag/buffer-overflow-la-es

En verdad, se produce un desbordamiento de búfer en una aplicación cuando no tiene las comprobaciones de seguridad necesarias en su código de programa, como medir la cantidad de datos que se copiará en el búfer y que no excederá el tamaño del búfer.

Los tipos más comunes de desbordamientos de búfer son los desbordamientos de búfer de pila y los desbordamientos de búfer de pila.

Aquí vemos la definición de desbordamiento del búfer, y en nuestro ejemplo anterior, si trato de verter 40 litros en un tanque de 20 litros, se desbordará, tal como lo entendemos. Este es un desbordamiento que causa un desbordamiento del búfer, es decir. desbordamiento de mi tanque cuando se excede su capacidad máxima.

Ahora explique la diferencia entre la pila y el montón.

¿Qué es una pila?


STACK se usa para almacenar variables de funciones locales que son necesarias solo mientras se ejecuta la función. En la mayoría de los lenguajes de programación, es importante que sepamos en tiempo de compilación qué tan grande es una variable si queremos mantenerla en la pila.

¿Qué es un lote?


Heap se usa para reservar memoria dinámica, cuya vida útil no se conoce de antemano, pero se espera que dure algún tiempo. Si no conocemos su tamaño o si se determina en tiempo de ejecución, el tamaño debe calcularse y reservarse en el montón.

El montón también se usa para objetos que varían en tamaño porque no sabemos en tiempo de compilación cuánto tiempo se usarán.

He estado trabajando en nuestra empresa durante más de 13 años como autor de exploits, y lo primero que hacemos con todas las personas contratadas que incluso me hicieron cuando me uní fue tratar de desentrañar las pilas y montones del famoso GERARDO RICHART. Es uno de los fundadores de CORE SECURITY y un gurú de análisis de exploits.

Comenzaremos lentamente con las pilas más simples. Por supuesto, como dije, se compilan en este momento con una protección mínima y son de 32 bits para facilitar la operación.

Veamos el código fuente de la tarea STACK1.

https://drive.google.com/open?id=16btJAetpa1V5yHDZE2bnnFWTQNpsUR4H

Vemos una carpeta con ejercicios, y dentro está el código fuente STACK1 llamado STACK1_VS_2017.CPP.

#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE

#include <stdlib.h>
#include  <stdio.h> 
#include "Windows.h"


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


	MessageBoxA((HWND)-0, (LPCSTR) "Imprimir You win..\n", (LPCSTR)"Vamosss", (UINT)0);

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}


Intentaremos comprender este código y ver dónde puede ocurrir el desbordamiento del búfer, y si será un desbordamiento del búfer en la pila o en el montón.

La llamada de función MessageBoxA se agregó al código fuente STACK1 para mostrarnos un pequeño mensaje que nos solicita que lo resolvamos. Esta es solo una adición que no afecta nada. Esta es una llamada estándar a la función WINDOWS especificada, que no analizaremos aquí.

Quién necesita información sobre esta función, puede obtenerla aquí.

Sabemos que dentro de la función, si hay variables locales, debe reservar un lugar para ellas.

Entonces nos queda este código fuente creado por GERARDO RICHART.

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

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}

Vemos en rojo la primera parte del programa, donde se reserva espacio para variables locales. En este caso, hay dos variables locales, COOKIE y BUF.

Puede ver los tipos de datos en la tabla . Otros tipos de variables también se encuentran allí.

El código se compilará en 32 bits.

Vemos que la variable COOKIE será de tipo INT, por lo que se reservarán 4 bytes de memoria para esta variable.



En el caso de la variable BUF, vemos que es una matriz o una cadena de caracteres (tamaño de caracteres = 1 byte).



Aquellos. será una matriz de 80 caracteres, es decir su longitud será 80x1 = 80 bytes.

Cualquiera que no sepa qué puede leer una matriz aquí:

https://www.programiz.com/c-programming/c-arrays

Por lo tanto, una matriz puede almacenar muchos valores del mismo tipo de datos. Solo tiene que decirle qué tipo de datos serán y cuánto habrá.



En el primer ejemplo, esta es una matriz de enteros, es decir será de 100 bytes, y dado que cada número entero toma 4 bytes, la longitud de la matriz será de 100 x 4 = 400 bytes.

En el segundo ejemplo, FLOAT toma 4 bytes, por lo que será una matriz de 5 FLOAT, por lo que su longitud será 5 x 4 = 20 bytes.

Cuando analizamos la matriz a un nivel bajo, veremos que es un espacio de memoria o búfer reservado. Esta no es la única forma de reservar espacio en la memoria. Existen otros tipos de datos variables que también requieren espacio de reserva en la memoria que serán almacenamientos intermedios para almacenar sus contenidos.

Volviendo a nuestro ejercicio:

char buf[80];

Esta es una matriz de caracteres de 80 x 1 = 80 bytes de longitud, es decir se parece a nuestra jarra de 20 litros. Si intentamos almacenar más de 80 bytes, el banco se desbordará.

Ahora veamos dónde se usa el búfer BUF.



Vemos que el búfer se usa en dos lugares marcados con flechas rojas.

La primera instrucción tiene una función PRINTF, que se utiliza para mostrar un mensaje en la consola, que será una cadena entre comillas.

"buf: %08x cookie: %08x\n"

Pero la función PRINTF no solo imprime la cadena entre comillas, sino que también imprime la cadena en el formato especificado. Los porcentajes en el interior nos dicen que se creará una línea de salida. Vemos que la cadena es solo el primer argumento de la función. El formato de salida y otros argumentos pueden ser varios (habrá uno para cada argumento% en el formato). En nuestro caso, hay dos de ellos.



En este caso, tenemos dos formatos% X, así que si me refiero a la tabla de formatos PRINTF:



vemos que la función tomará estos enteros (INT) y los insertará en la línea de salida con la base del sistema de números 16, es decir. en formato hexadecimal 08 indica que si el número contiene menos de 8 dígitos, la función lo llenará con espacios.

La salida para "buf:% 31x", & buf será así

buf:             19FED4 

Vemos que en este ejemplo están llenos de espacios antes del número. Hay varios modificadores para mostrar la salida.

Todos los casos posibles se enumeran aquí:

http://www.cplusplus.com/reference/cstdio/printf/

Nuestro caso es este:





vemos que el resultado no se trunca, se llena con espacios solo si la longitud del argumento para insertar es menor que el valor antes de X.

Por lo tanto, sabemos que la función imprime dos números hexadecimales, que se obtienen de dos argumentos.

printf("buf: %08x cookie: %08x\n", &buf, &cookie);

Sabemos que una variable tiene una dirección de memoria y un valor que puede almacenarse. Se parece a nuestra jarra de 20 litros. Tiene su contenido o significado, es decir litros almacenados en el interior, pero también si tengo un garaje lleno de latas similares necesito alguna forma de determinar dónde está la lata que quiero entre todas las que tengo.

El símbolo & indica esto. Devuelve la dirección o ubicación del jar, no su contenido o valor.

Definición de AMPERSAND


AMPERSAND se usa para indicar la dirección de memoria de la variable en la que se almacenarán los datos.

Por lo tanto, si ejecuto el archivo ejecutable en la consola, veré, por ejemplo, que cuando ejecuta la función PRINTF, imprimirá: las



direcciones pueden cambiar en su PC, pero dado que la dirección inferior de ambas direcciones coincide con la dirección BUF, vemos que se encuentran de esta manera:



La dirección BUF es menor que la dirección COOKIE, por lo que aumentará.

¿Y qué nos dicen estas direcciones variables? (En mi caso, & BUF = 0x19FED4 y & COOKIE = 0x19FF24)



Ambos están en formato hexadecimal. ¿Recuerdas que este era el formato% X? Así que pongo 0x adelante para distinguir los números decimales que representaremos sin ninguna adición.

Si hago una resta en la consola PYTHON o en PYCHARM:



obtenemos un resultado de 80 bytes, ya que la variable COOKIE supuestamente comienza exactamente donde termina el búfer BUF, por lo que la diferencia nos da el tamaño del búfer.

A menudo, cuando hacemos este tipo de variable en función del código fuente, puede suceder que el compilador nos proporcione un tamaño mayor que el que está reservado en el código fuente. El compilador garantiza que reservará al menos 80 bytes, es decir él puede reservar más, no menos.

El hecho es que ya sabemos algo sobre el código, el tamaño de las variables y su ubicación debido al hecho de que tiene la función PRINTF.

Ahora veamos otro lugar donde se usa el búfer BUF, porque ahora el programa solo imprime su dirección, pero no la usa para almacenar datos en ella.

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

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}

Aquí, en la línea roja, GET es una función para ingresar datos desde el teclado. Los datos se ingresarán hasta que presione Enter.

El programa no puede limitar la cantidad de datos ingresados ​​por el usuario, y tampoco hay forma de verificar estos datos. Todo lo que se ingresa antes de presionar la tecla ENTER se copia al búfer BUF.

Este es el problema. Dijimos que BUF solo puede almacenar 80 bytes como máximo, por lo que si ingresamos más, crearemos un desbordamiento de búfer, y aquí están todas las condiciones para esto, porque si el usuario escribe más de 80 bytes, entonces nuestro tanque se desbordará y el líquido goteará .



El hecho es que debajo de BUF está la variable COOKIE, por lo que el desbordamiento se sobrescribirá y rellenará con un valor que puede controlar.

Por ejemplo, si alguien que imprime escribe 80 * A y 4 * B, 80 * A completará BUF y 4 * B completará COOKIE, y como sabemos, cuando alguien imprima un personaje en la consola, el valor seguirá siendo bajo. ASCII



Dado que la cookie se llenará con cuatro letras B, que son equivalentes al valor 0x42, podemos garantizar que el valor de la cookie será 0x42424242, es decir. en mi computadora, la dirección de cookie 0x19FF24 tendrá 0x42424242 como contenido.

0x19FF24 => 42424242



El hecho es que ya hemos visto cómo desbordar y controlar el valor de COOKIE.

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

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}

Debe imprimir "usted gana" para completar el ejercicio. Para esto, la COOKIE debe ser igual al valor 0x41424344, y si no hubiera desbordamiento, esto sería imposible, ya que el valor de la COOKIE nunca ha cambiado desde el comienzo del programa. No podremos imprimir "usted gana", y para esto usamos un desbordamiento de búfer, que dice que esto puede hacer que el programa realice alguna acción diferente a la programada.

En este caso, nunca puede escribir "usted gana", solo el desbordamiento le permitirá hacer esto.

AAAAAAAA

En otras palabras, en lugar de pasar, por ejemplo, 80 * A y 4 * B, para imprimir "usted gana", debe pasar 80 * A y luego las letras DCBA, ya que esto hará que los valores se almacenen en la COOKIE ASCII

44434241

https://www.arumeinformatica.es/blog/los-formatos-big-endian-y-little-endian/

El formato en el que se almacenan los datos es LITTLE ENDIAN. En otras palabras, los datos en la memoria se almacenan en orden inverso, por decirlo simplemente.



Y si se guarda la secuencia 0x41424344, el sistema la guardará en la memoria como:

44 43 42 41

Por esta razón, al copiar en la memoria, la copia se producirá a medida que escribimos, por lo que debemos escribir el valor en el orden inverso para que al leer de la memoria Estaba en la forma correcta.

Podemos ejecutar el ejecutable en la consola.



Y el cursor parpadeará, ya que la función GET me pide que ingrese la entrada. Escriba cuidadosamente 80 caracteres A y luego DCBA.

En la consola PYTHON o PYCHARM, puedo imprimir la línea, copiarla sin comillas y pegarla en la consola para no imprimirla como una locura, y luego presionar la tecla ENTER para ingresarla.





Vemos que tenemos "tú ganas".

Podemos ver esto en el depurador. Para esto usaremos X64DBG.



Elijo la versión de 32 bits.





Si nos detenemos en la biblioteca NTDLL.DLL, presionamos RUN nuevamente con F9.

Vemos que el depurador se detiene en la primera instrucción del módulo STACK1, que se llama ENTRY POINT o la primera instrucción ejecutada por el módulo.



Obviamente esto no es como nuestro código fuente. Debe comprender que el compilador agrega mucho código para que el ejecutable funcione y se ejecute correctamente. Intentaremos encontrar nuestra función principal. Podemos orientarnos mirando las líneas del programa.



Seleccionamos solo buscar en la región actual. Sabemos que las líneas estarán en la misma sección.



Aquí vemos que hay líneas de programa y otras que agregó el compilador. Hacemos doble clic en una de nuestras líneas.



Ahora puedes ver mucho más. Vemos una llamada a la función MessageBoxA, PRINTF, GETS y una comparación con el valor 0x41424344.

Además, estamos agregando un complemento para descompilar SNOWMAN. Podemos intentar ver cómo descompila el código, es decir cómo está tratando de obtener el código fuente o algo lo más similar posible del archivo compilado.





Vemos que esto no es perfecto, pero es mejor de lo que era.

Voy a poner BP al comienzo de la función y presionar F9 hasta que se detenga el depurador.



Para aquellos que no saben qué es un argumento de función.



En nuestro caso, la función principal tiene argumentos, pero no se usan dentro de la función.

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

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}

Aquí vemos que hay dos argumentos, y se pasan a través de la pila cuando el ejecutable se compila en 32 bits.

Justo antes de la llamada a la función, los argumentos se almacenarán en la pila.

Cuando nos detenemos al comienzo de la función, el primer valor en la pila será DIRECCIÓN DE RETORNO, es decir, dónde volverá la función después de que se complete la función, y debajo de este valor estarán los argumentos de esta función.

Si hago clic con el botón derecho en DIRECCIÓN DE RETORNO y selecciono SEGUIR DWORD EN DESMONTAJE, veré dónde debe regresar el depurador una vez que se complete la función.



El regresará aquí. Esto significa que se llamó a la función principal desde una llamada que es más alta. Puedo poner BP aquí, reiniciar el ejercicio y asegurarme de que sea así.



Pondré BP un ​​poco antes y reiniciaré el programa.



El depurador se detendrá aquí.



Guardará los argumentos en la función principal utilizando estas instrucciones PUSH.

A continuación hay un enlace para aquellos que quieran saber más sobre los argumentos de la función:

https://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html

Esto no es muy difícil. El primer argumento para ARGC es INT, que indica el número de parámetros de consola utilizados para ejecutar el programa, incluida la ruta al ejecutable, y ARGV es una matriz de punteros a cadenas.

Vemos que si cambio la línea de comando, pasaré más argumentos y volveré a cargar.





Aquí el depurador se detiene cuando está a punto de guardar argumentos utilizando la instrucción PUSH. El primer argumento que se almacena es el más alejado, y el último que guarde será el primer argumento de la función.

Trazo y cada instrucción PUSH guarda los argumentos.



Aquí puedo ver los argumentos de la función. Arriba está el primer argumento para ARGC. Es 3, ya que marca el número de argumentos que se pasan a la consola.



Aquí hay 3 argumentos.

Ahora presionamos F7 para hacer STEP INTO e ingresar a la función.

Aquí vemos que al ingresar la LLAMADA, el depurador guarda la DIRECCIÓN DE RETORNO en la pila.



Entonces, como ya dijimos al ingresar la función, lo primero que se guardará en la pila es DIRECCIÓN DE DEVOLUCIÓN (en la compilación de 32 bits), y a continuación están los argumentos de la función, primero el primer argumento y luego el resto secuencialmente.



El segundo argumento, como vimos, es una serie de punteros. Aquí vemos en la memoria que hay tres punteros a tres líneas que se pasan como argumentos.



Aquí nos detuvimos al comienzo de la función, un poco más abajo tenemos DIRECCIONES DE VUELTA y ARGUMENTOS.

Aclaramos que el archivo se compila en 32 bits, porque en la versión de 64 bits, los argumentos se pasan de una manera diferente. Lo veremos luego.

Entonces la función comienza a ejecutarse. Lo primero es el llamado PROLOGUE, que almacena el valor EBP de la función que llamó el nuestro.



Esto mantendrá el valor de EBP justo por encima de la dirección de retorno.



Si sigo las instrucciones con F7.

Veo que el valor EBP GUARDADO está en la pila sobre la dirección de retorno.



La siguiente instrucción en PROLOGUE:

MOV EBP, ESP

Establece el valor de EBP para la función actual que se guardó y fue la función principal que llama a la nuestra (en este caso, mi función principal es la función basada en EBP, en otros casos puede ser diferente, y nosotros verlos más tarde)

Al colocar el valor ESP actual en EBP, nos aseguramos de crear un marco para nuestra función actual.



Ahora, dado que esta función se basa en EBP o EBP BASED, el valor de EBP se almacenará dentro de la función y se aceptará como referencia, y el ESP cambiará.



Este valor de EBP se toma como base.

En las funciones basadas en EBP, las variables y los argumentos se pueden nombrar por su distancia desde esta dirección, que se almacenará en el valor de EBP hasta su epílogo.

Podemos ver varias variables en la lista a las que se hace referencia como EBP-4 o EBP-54, en referencia al valor de EBP que está aceptando actualmente.

Podemos decir que tan pronto como el EBP tome su valor después del PROLOGO, se verá como un drenaje, por lo que los argumentos siempre irán en esa dirección, por lo tanto, EBP + XXX se refiere a los argumentos (el EBP almacenado y la DIRECCIÓN DE RETORNO también son más bajos, pero no tendrán enlaces en el código), mientras que las variables, como veremos, estarán por encima de esta dirección, por lo que el enlace a EBP-XXX se refiere a alguna variable local.

Por lo tanto, en funciones basadas en EBP:

EBP + XXXX = argumentos pasados ​​a la función
EBP - XXXX = variables de función local

Después de PROLOGUE habrá alguna forma de reservar espacio para variables. En nuestro caso, esto se hace moviendo el ESP hacia arriba para que el espacio restante a continuación se reserve para la suma de todas las longitudes variables y, a veces, un poco más por si acaso, que depende del compilador.

00401043 | 83EC 54 | SUB ESP, 54

Vemos que el ESP se encuentra por encima del EBP, que seguirá siendo el enlace, y que 0x54 convertido a decimal es 84, que es la suma de las longitudes BUF y COOKIE. Recuerda que eran 80 y 4 respectivamente.







En la ejecución, se crea un espacio para las variables BUF y COOKIE de 84 bytes de tamaño. Puede hacer clic en la primera columna en dirección horizontal y mirar el valor de EBP y encontrar ese valor en la pila. Obviamente, ahora será más bajo.



Hago doble clic aquí.



Por lo tanto, tendremos valores con respecto a EBP también en la pila.

Por ejemplo, EBP-4 coincide con el listado, -4 se muestra en la primera columna de la pila y, en la explicación, también se muestra como EBP-4.



Si trazo, vemos que desde el lugar donde se ubicó el ESP para reservar las variables, siempre se moverá hacia arriba, porque debe tener en cuenta el espacio asignado para las variables. Al realizar 4 PUSHs para MessageBoxA, el depurador coloca las variables por encima del espacio reservado y aumenta el ESP.



Si miro la pila, veo 4 argumentos verdes que agrego sobre el espacio reservado marcado en rojo.



Cuando ingresa la función MessageBoxA, la DIRECCIÓN DE DEVOLUCIÓN de esta función se almacena en la pila.



Aquí está la dirección de retorno de MessageBoxA. Cuando llego al RET de esta función rastreando con F8, y ejecuto MessageBoxA.



Vemos que el depurador volverá justo debajo de la llamada MessageBoxA.



Y los valores PUSH que pasó para la función MessageBoxA y la DIRECCIÓN DE RETORNO para esta función ya se han utilizado, y el ESP está nuevamente por encima del área reservada, como antes de que se llamara a cualquier función. Lo mismo sucederá al llamar a la función PRINTF.

Después de pasar la función PRINTF, se imprimirán las direcciones BUF y COOKIE.



La dirección BUF en mi máquina será 0x19FED4, y la dirección COOKIE será 0x19FF24.

Aquí, el programa lee la dirección BUF para pasarla a la función GETS y llenar la BUF. Podemos verificar si la dirección coincide con lo que muestra la consola 0x19FED4.





Aquí vemos que es EBP-54. Si hago doble clic en la pila donde muestra -54, mostrará que la dirección es BUF = 0x19FED4 en mi máquina.



Ahora, cuando guarde los datos ingresados ​​en esta dirección, puedo ponerlos en un volcado para ver cómo se almacenan los bytes allí.





Aquí están. Además, no se muestra nada a continuación, ya que no hay datos.

Cuando llamo a la función GETS usando F8, tendré que ir a la consola, escribir y presionar ENTER para llenar el buffer BUF y reescribir la COOKIE.



Vemos que la variable COOKIE estaba en 19FF24 en mi máquina.

Aquí, el programa compara la cookie con 0x41424344.



Vemos que EBP-4 dice que es una COOKIE, además de la dirección, si establecemos el HORIZONTE en el valor EBP, como antes.



Hago doble clic aquí.

Vemos que EBP-4 es una COOKIE, ya que la variable está en el nivel de pila -4, poniendo a cero el HORIZONTE.



¡Vemos que el programa no saltará y nos mostrará que ganas!





¡Así que logramos manualmente el objetivo que ganas! Dice.

Analizamos dinámicamente STACK1 usando X64DBG, que es un depurador y no nos permite analizar el programa sin iniciarlo. Para hacer esto, debemos usar otras herramientas, como IDA PRO, GHIDRA o RADARE.

Puedo hacer un modelo de script para operar el ejercicio desde PYTHON.

import sys
from subprocess import Popen, PIPE

payload = b"A" * 80 + b"\x44\x43\x42\x41"

p1 = Popen(r"C:\Users\ricardo\Desktop\abos y stack nuevos\STACK1_VS_2017.exe", stdin=PIPE)
print ("PID: %s" % hex(p1.pid))
print ("Enter para continuar")
p1.communicate(payload)
p1.wait()
input()

En el caso de PYTHON 3, tengo que poner paréntesis en la función IMPRIMIR y tener cuidado al agregar líneas que deberían ser bytes (poner b delante de las líneas en PYTHON 2).

Compruebo que la ruta es correcta y cuando ejecuto el archivo.



Bueno. Ya tenemos un modelo de script para PYTHON 3 para operar STACK1. En la siguiente parte, continuaremos el análisis estático en IDA, RADARE y GHIDRA.


Tenga en cuenta que, además de la tarea STACK1, también hay versiones 2, 3 y 4. Puede intentar resolverlos. Son muy simples y similares a STACK1, así que no te aburras.

En la siguiente parte veremos IDA FREE, RADARE y GHIDRA.

Nos vemos en la próxima parte 3.

Ricardo Narvaha
25/10/2019

PS # 1
Se puede descargar un hermoso PDF en mi página de inicio: yasha.su

PS # 2
Pronto escribiré una continuación del artículo https://habr.com/en/post/464117/ sobre cómo obtuve ayuda para el Padre Chris Kaspersky y qué hay de esto sucedió

No te aburras.

All Articles