2011-09-05 8 views
10

Quiero comprender la diferencia exacta entre estos dos tipos de ataque. De lo que he leído:Diferencia entre - desbordamiento de búfer y regreso al ataque de libc

Desbordamiento de búfer: sobrescribe la dirección ret en la pila para apuntar a otra sección del código donde se inserta el código malicioso. De manera efectiva, aquí tenemos que modificar el código fuente del programa para realmente llevar a cabo el ataque.

Volver a Libc Aquí, en lugar de modificar el código fuente, se utilizan las llamadas a la función de tiempo de ejecución proporcionadas por la biblioteca C (por ejemplo, abrir un shell). Aquí los parámetros usados ​​para la llamada de función también se pasan en el búfer de sobrescritura, terminando después de la parte ret de la pila.

¿Es la anterior una descripción precisa?

Y otra pregunta relacionada: ¿sería posible tener un ataque de desbordamiento del búfer sin modificar realmente el código fuente del programa original? Probablemente si escribimos un nuevo programa y permitimos que modifique ciertas secciones de la memoria (que es la nueva dirección ret en la pila corrupta del programa original). Por otra parte, creo que esto podría no ser posible debido a la protección de la memoria ofrecida entre los procesos en el kernel.

Respuesta

12

En el clásico ataque de desbordamiento de búfer, el búfer de pila que se desbordó se rellenó con el código de máquina que se ejecutará (llamado shellcode, porque normalmente invoca un proceso de shell) y la nueva dirección de retorno. La nueva dirección de retorno se diseñaría para apuntar hacia atrás dentro del mismo buffer desbordado. Obviamente, esto requiere saber o adivinar la dirección de ese buffer de pila en el proceso atacado. En aquellos días, el diseño de la memoria de los procesos era típicamente muy determinista: el atacante podía predecir bastante bien la ubicación del búfer de la pila (especialmente si sabían exactamente qué versión del software de destino estaba siendo atacada). Para mejorar las posibilidades de éxito cuando hubo algunas suposiciones involucradas, el shellcode activo a menudo iba precedido de una gran cantidad de código de máquina ejecutable que no realizaba ninguna operación útil, llamada "NOP sled" o "NOP slide", donde "NOP" es el nombre típico de una instrucción de código de máquina que realiza "Sin operación". Volver a un punto en cualquier parte del trineo NOP tendría el efecto deseado.

Un exploit "return-to-libc", por otro lado, no hace que el proceso secuestrado regrese directamente al shellcode. En cambio, hace que el proceso regrese, uno por uno, al comienzo de una cadena de funciones de la biblioteca. Estas funciones de biblioteca pueden realizar directamente las operaciones que desea el atacante, pero más comúnmente se usarán para ejecutar indirectamente el código de shell del atacante.

0

Bueno, en realidad, en un ataque de bufferoverflow, inserta el código malicioso al anular el puntero de ret. No necesita modificar nada para esto, así que como conclusión, no puedo ver la diferencia entre los dos ataques mencionados.

Por ejemplo:

char* str[5];
cin << str;

Esto es código que puede ser exploided, si un usuario inserta una cadena de más de 5 caracteres, todo en la pila que sigue será sobrescrito. Y debido a que el ret-ptr es "más bajo" en la pila, puede anularlo, si obtiene la distancia correcta. Su intención al anular es dejar que apunte al comienzo de su entrada, en la que inserta código malicioso (ensamblador), que se ejecutará tan pronto como se llame al ret-ptr y se ejecute el "salto".

4

La parte de sobreescribir una dirección ret se comparte entre ambos ataques. Como lo indica la respuesta anterior, solía simplemente regresar al código de ensamblaje que había escrito. Este código de ensamblaje generaría, por ejemplo, un shell de usuario raíz.

En ninguno de los ataques 'sobreescribe' el código fuente. Al visualizarlo desde una perspectiva de ensamblaje, el código fuente está en el segmento .text y siempre ha estado protegido contra escritura (o al menos todo el tiempo que yo sepa). Lo que solía aprovechar era escribir código que previamente había ensamblado en segmentos de memoria, y luego saltar a este código. El código generalmente se ubicaba en o cerca del 'segmento de pila', y al desbordar lo que elijas sobrecargar, redirigirías el tráfico desde la dirección ret (por ejemplo) allí. Otros lugares de ataque incluían una variable ambiental que previamente había creado y rellenado con su shellcode; o también el montón, o punteros de función, o el PLT. El código así insertado usualmente usaría la llamada al sistema() para ejecutar lo que se deseaba, pero para esto, debe poder 'ejecutar' en áreas de memoria (o hacer que las entradas de reubicación que pretenda usar sean declaradas escribibles).

La diferencia entre los dos ataques es que una vez que la memoria se había hecho en gran medida no ejecutable, el tipo de ataque a (desbordamiento de la pila) estaba bastante jodido. Un intento de eludir este tipo de ataque fue, mientras escribía, para acceder directamente a las funciones de la biblioteca compartida directamente; también, ya no era necesario escribir su código primero en el segmento de la pila o en otro lugar y ejecutarlo allí. Sin embargo, creo que los ataques de tipo libc también están parcheados en gran medida por ahora; No tengo los detalles a mano; y tal vez estoy equivocado.

Si desea ver cómo se frustran estos ataques en estos días, o al menos leer sobre algunas ideas clave, google 'Smashing the Stack in 2011' (o 2010) para comenzar.

+0

¿Podría explicar a qué se refiere con hacer que la memoria sea ejecutable (o no ejecutable). Y la otra duda (parte de mi pregunta original) es: creo que un código C no tendría acceso a todas las partes de la memoria principal. Entonces, ¿cómo se determina dónde se coloca el código de ensamblaje malicioso en la memoria? Porque creo que para la mayoría de las regiones de la memoria, solo marcaría un error de segmentación cuando regrese allí. – Hari

+0

El núcleo del código de exploit que insertaba normalmente estaba usando y la función de estilo familiar de exec(). Esto significa que, al alimentarlo con los parámetros adecuados, podría tenerlo, por ejemplo, generar un shell/bin/sh como el usuario raíz. Esto es * ejecutar * un programa, y ​​ya no puedes. Hay muchas medidas de seguridad diferentes, pero esta sería descrita, por ejemplo, en – gnometorule

+0

http://en.wikipedia.org/wiki/NX_bit – gnometorule

4

, diría desbordamiento de memoria intermedia es una clase de error de programación y retorno a libc es una técnica de explotación. Lo mejor es no mezclar los conceptos.

Por ejemplo, puede utilizar retorno a libc explotar un desbordamiento de memoria intermedia vulnerabilidad. O puede utilizar otras técnicas como volver a .text, o regresar a shellcode. Por el contrario, también puede utilizar para volver a libc para explotar otros errores como cadena de formato también.

Cuestiones relacionadas