Red de conocimiento informático - Conocimiento informático - Cómo escribir tu propio exploit de desbordamiento de búfer

Cómo escribir tu propio exploit de desbordamiento de búfer

1 Cómo hacerlo. ¿Se ha producido un desbordamiento del buffer?

El llamado desbordamiento del búfer, traducido como desbordamiento del búfer en chino, significa que el búfer utilizado es demasiado pequeño y no puede acomodarlo.

Tantas cosas, todas las cosas superfluas salieron. Es como si un tanque de agua no pudiera contener tanta agua y se desbordaría si lo viertes con demasiada fuerza.

Entonces, ¿por qué deberíamos utilizar buffers durante la programación? La respuesta sencilla es actuar como una estación de transferencia para el procesamiento de datos.

El mecanismo de llamada a funciones en lenguaje C en 2.2. UNIX y explotación de desbordamiento de buffer.

1) Imagen del proceso en memoria.

Asumimos que existe un programa cuya secuencia de llamada a funciones es la siguiente.

principal(...)- gt; func_1(...)- gt; función_2(...)- gt; función_3(...)

Es decir: la función principal llama a la función func_1; llama a la función func_2;

Cuando el sistema operativo carga un programa en la memoria, la imagen del proceso correspondiente en la memoria se muestra en la siguiente figura.

(Dirección alta de memoria)

-

|...|...Omite algunas áreas que no necesitamos preocuparnos.

-

| cadena SHELL| - cadena argv| p> - /

| argc (número de argumentos de la línea de comando)|/

-

| Marco de pila de la función principal| de función | -func _ Marco de pila de 3 funciones | Pila (stack)

........................ .. .......... /

| /

....../

| p> ........................................ /

|Montón|/

-

|Datos no inicializados (BSS)|Área de datos no inicializados (BSS)

-

|Datos de inicialización |Área de datos de inicialización

-

Texto|Área de texto

-

(dirección de memoria baja)

Lo que debe explicarse aquí es:

I) A medida que aumenta el número de capas de llamadas a funciones, el marco de la pila de funciones se extiende hasta la dirección inferior de la memoria bloque por bloque. A medida que disminuye el número de llamadas a funciones en el proceso, es decir, cada llamada a función regresa, los marcos de la pila se descartarán uno por uno y se sangrarán las direcciones altas de la memoria. El tamaño del marco de pila de cada función varía según la naturaleza de la función, que está determinada por el número de variables locales de la función.

Ii) El uso dinámico de la memoria por parte del proceso se produce en el montón. Es decir, a medida que aumenta la cantidad de memoria asignada dinámicamente al proceso por el sistema, el montón puede expandirse a direcciones altas o bajas, dependiendo de las diferentes implementaciones de CPU. Pero en términos generales, crece hacia direcciones más altas en la memoria.

Iii) En el caso de que el crecimiento de los datos o la pila BSS agote la memoria libre asignada al proceso por el sistema, el proceso será bloqueado y reprogramado por el sistema operativo con un módulo de memoria más grande.

(Aunque no tiene nada que ver con exploit, es bueno saberlo)

Iv) El marco de pila de la función contiene los parámetros de la función (son los parámetros de la función llamada colocados en el marco de pila de ¿La función que llama o la función llamada? (dependiendo de la implementación de diferentes sistemas), sus variables locales y los datos necesarios para restaurar el marco de pila de la función que llama (es decir, el marco de pila anterior), incluida la dirección de la siguiente. instrucción de ejecución de la función que llama.

v) El área de datos no inicializados (BSS) se utiliza para almacenar variables estáticas del programa. Esta parte de la memoria se inicializa a cero. El área de datos de inicialización se utiliza para almacenar datos de inicialización en el archivo ejecutable. Estas dos áreas se denominan colectivamente área de datos.

Vi) El texto (área de texto) es un área de solo lectura y cualquier intento de escribir en esta área resultará en un error ilegal en el segmento. El área de texto es compartida por varios procesos que ejecutan el archivo ejecutable. El área de texto almacena el código del programa.

2) El marco de pila de la función.

El marco de pila que se establece cuando se llama a una función contiene la siguiente información:

I) La dirección de retorno de la función. Si la dirección de retorno se almacena en el marco de pila de la función que llama o en el marco de pila de la función llamada depende de la implementación de diferentes sistemas.

Ii) La información del marco de la pila de la función que llama, es decir, la parte superior e inferior de la pila.

Iii) El espacio asignado para las variables locales de la función

Iv) El espacio asignado para los parámetros de la función llamada depende de la implementación de diferentes sistemas.

3) Utilizar desbordamiento de buffer.

Se puede ver en la estructura del marco de pila de la función:

Debido a que la asignación de memoria de las variables locales de una función ocurre en el marco de la pila, si definimos un búfer en un variable de búfer de función, entonces el espacio de memoria ocupado por esta variable de búfer está en el marco de pila establecido cuando se llama a la función.

Porque las operaciones potenciales en el búfer (como copiar una cadena) van desde la dirección baja en la memoria hasta la dirección alta, y la dirección de retorno de la llamada a la función almacenada en la memoria a menudo está en el búfer (dirección alta) Arriba: esto está determinado por las características de la pila, que proporciona condiciones para la sobrescritura de las direcciones de retorno de funciones. Cuando tenemos la oportunidad de llenar el búfer con algo más grande que el tamaño del búfer objetivo, podemos sobrescribir la dirección de retorno de la función almacenada en el marco de la pila de funciones para que el flujo de ejecución del programa cambie según nuestras intenciones. En otras palabras, el proceso está bajo nuestro control. Podemos dejar que el proceso cambie el flujo de ejecución original y ejecute el código que preparamos.

Este es el defecto en la arquitectura informática de von Norman.

El siguiente es un diagrama esquemático de la utilización del desbordamiento del búfer:

I) La dirección de operación de la función en el búfer de cadena es generalmente de la dirección baja a la dirección alta.

Por ejemplo: strcpy(s, "AAA...";

s s 1 s 2 s 3...

- - - - - .

(dirección de memoria baja) | a | a | p>

Ii) Dirección de retorno de la función de sobrescritura

/| ...|(dirección de memoria)

/ -

Marco de pila de la función de llamada | 41414141 |

\ -

\ | 0x 41414141 |La dirección de retorno de la función que llama.

\ -

/| ......|

/ - s 8

/| 0x 41414141 |

/ - s 4

Marco de pila de función llamada | 0x 41414141 |

\ - s

\ |

\ -

\| ......|

....................

|...|(dirección de memoria baja)

Nota: El valor del código ASCII hexadecimal del carácter A es 0x41.

Iii) Como se puede ver en la figura anterior, si reescribimos la dirección de retorno de la función que llama con una dirección a la que el proceso puede acceder en lugar de 0x414141, y esta dirección resulta ser la entrada al código que preparamos, luego el proceso ejecutará nuestro código. De lo contrario, si se utiliza la dirección de un segmento que es inaccesible para el proceso, provocará que el proceso se bloquee: un volcado de núcleo con falla de segmentación, si esta dirección tiene datos de instrucciones de máquina no válidos, provocará un error de instrucción no válida, y por lo tanto; en.

4) Cuando el buffer está en el área de montón o área BBS.

I) Si el espacio de memoria del búfer se obtiene mediante una aplicación dinámica en la función (como una aplicación que usa la función malloc()), entonces solo se asigna una memoria que apunta a la aplicación en el montón en el marco de pila del puntero de función al espacio. En este caso, el desbordamiento se produce en el montón y sobrescribir la dirección de retorno de la función correspondiente parece casi imposible. La posibilidad de utilizar esta situación depende de la situación específica, pero no es imposible.

Ii) Si el búfer se define como estático en la función, entonces la ubicación del espacio de memoria del búfer está en el área no inicializada (BBS), similar a la ubicación en el montón, por lo que puede utilizarse. Pero también hay un caso especial, es decir, se puede usar para sobrescribir el puntero de función, permitiendo que el proceso llame a la función correspondiente más tarde y se convierta en el código que especificamos.

3. ¿Qué se puede ganar utilizando el desbordamiento del búfer?

Como se puede ver en lo anterior, el uso del desbordamiento del búfer nos permite reescribir el contenido de la memoria relevante y la dirección de retorno de la función, cambiando así el proceso de ejecución del código y permitiendo que el proceso se ejecute. el código que hemos preparado.

Sin embargo, el proceso se ejecuta como el usuario con el que estamos conectados actualmente. ¿Qué pasaría si pudiéramos ejecutar el código que preparamos? Todavía no podemos romper la configuración de permisos del sistema para el usuario actual, ni podemos hacer cosas más allá de los permisos.

En otras palabras, si queremos utilizar el desbordamiento del búfer para obtener mayores privilegios, debemos utilizar algunas funciones del sistema.

Para UNIX, hay dos funciones disponibles.

1) Esquemas SUID y SGID

UNIX permite a otros usuarios ejecutar archivos ejecutables con el ID de usuario o el ID de grupo de usuarios del propietario del archivo cambiando los atributos del archivo ejecutable. se logra configurándolo en SUID o SGID. Es decir, si un archivo ejecutable tiene un SUID o SGID configurado, cuando otros usuarios del sistema ejecutan el archivo, equivale a ejecutar el archivo como usuario propietario o grupo de usuarios. Si el propietario del ejecutable es root y el archivo tiene un SUID configurado, entonces si el ejecutable tiene una vulnerabilidad de desbordamiento de búfer disponible, podemos usarlo para ejecutar nuestro código preparado como root. No hay nada más atractivo que generar un SHELL con estado de superusuario root para nosotros, ¿no?