Código complicado para hacer que la memoria sea segura

16

Estoy diseñando un desafío de tarea para los estudiantes que están aprendiendo sobre la seguridad de la memoria y escribiendo el código C seguro. Como parte de esto, estoy buscando una pequeña tarea de programación en la que no sea trivial escribir código C que esté libre de desbordamientos de búfer, errores de matriz fuera de límites y / u otros errores de seguridad de la memoria. ¿Cuál sería un buen ejemplo de tal tarea?

En otras palabras: especifico la funcionalidad deseada; lo implementan en C; y si no tienen cuidado al implementar, existe una gran posibilidad de que su código tenga una vulnerabilidad de seguridad de la memoria. Idealmente, preferiría algo que pueda implementarse de manera concisa (unos pocos cientos de líneas de código, a lo sumo) para mantener la tarea de un tamaño manejable, y sería extraordinario si la tarea fuera de alguna manera industrial o prácticamente relevante o realista o representante de la programación del mundo real.

Para dar un ejemplo de un dominio diferente, implementar una búsqueda binaria en una lista ordenada es un ejemplo clásico de una tarea de programación fácil de especificar donde, si no tiene cuidado al implementarla, existe una gran posibilidad de que tenga algún tipo de error lógico (por ejemplo, un error off-by-one, un bucle infinito en algunas entradas, ese tipo de cosas). ¿Existe alguna buena tarea correspondiente, por seguridad, y específicamente vulnerabilidades de seguridad de la memoria?

    
pregunta D.W. 10.12.2013 - 09:12
fuente

4 respuestas

12

Un ejemplo típico de manejo de búferes no triviales es el análisis de archivos binarios (o paquetes de red) que pueden contener cadenas de longitud arbitraria. (¿Hay algún analizador ASN.1 que no haya tenido errores de desbordamiento de búfer en algún momento?)

Por ejemplo, considere el formato de fragmentos de datos textuales en archivos PNG :

  

La palabra clave y la cadena de texto están separadas por un byte cero (carácter nulo). Ni la palabra clave ni la cadena de texto pueden contener un carácter nulo. La cadena de texto es no terminada en nulo (la longitud del fragmento define el final).

Por lo tanto, la tarea podría ser una herramienta que genere todos los datos textuales en un archivo PNG.

Incluso el texto simple puede no ser tan trivial si necesita manejar líneas largas arbitrarias y, por lo tanto, necesita cambiar el tamaño de un búfer dinámicamente. Por ejemplo:

  

Implemente tail sin parámetros.   (Las líneas pueden ser más largas que cualquier búfer estático. El archivo completo puede ser más grande que la memoria disponible).

    
respondido por el CL. 10.12.2013 - 14:18
fuente
7

Veo muchos problemas cuando las personas necesitan analizar datos de caracteres fuera de las estructuras, especialmente cuando se trata de un búfer que normalmente termina en nulo, pero puede tener el tamaño del búfer sin un terminador.

short canary = 0x5678;
struct customer {
    char name[4];
    char suffix[3];
};
short fencepost = 0x1234;

Haz que llenen al cliente con datos como "Joe" y "Jr". Pídales que muestren todos los datos en este formato exacto:

canary: 0x5678
name: Joe
suffix: Jr
fencepost: 0x1234

Luego haga que llenen al cliente con "John" y "Esq". Su salida debería verse así:

canary: 0x5678
name: John
suffix: Esq
fencepost: 0x1234

Es una tarea común y simple. Esto debería enseñarles que no pueden simplemente ingresar ("Esq") en el búfer, porque matará al canario. Debería exigirles que copien los datos del búfer para anularlo por completo para imprimirlo.

Te recomiendo que pruebes esto primero y compruebes la configuración del compilador. En las versiones anteriores de Visual C ++ de Microsoft, una compilación de depuración se vincularía en una versión de depuración del asignador de memoria que agregaba vallas alrededor de la memoria asignada. Permitiría al depurador informar sobre un error de memoria sobrescrito. No sé si las versiones más recientes todavía lo hacen, pero sé que las versiones de lanzamiento no lo hacen.

Si quieres darles un "por qué", muestran cómo introducir un nombre como Fred @@@@@@@@ puede causar un accidente, y permitir a un hacker para asumir el control del programa.

    
respondido por el John Deters 10.12.2013 - 16:33
fuente
5

es difícil ya que los núcleos de Linux modernos de afaik no tienen pilas ejecutables, por lo que no podrán probar sus programas en una distribución de Linux normal. (Recuerdo que tengo problemas para probar el código que figura en el documento de Alef One en mi máquina debian)

Lo que podrías hacer es proporcionarles una vm personalizada (como maldita Linux vulnerable) que tiene la configuración de seguridad desactivada y pedirles que prueben su código allí.

Más al punto, una solución sería hacer que escriban un programa que obtiene un nombre de archivo como argumento de línea de comando o como entrada del usuario

  • abre el archivo
  • lee alguna configuración de ella
  • lo analiza / busca algo específico
  • inserta la parte relevante en un socket de red
  • otro proceso lee los datos y debe imprimir algunas partes relevantes.

Tu escenario podría ser:

  

Tienes que escribir un programa en c que lea los horarios de los vuelos de las aerolíneas.   desde un archivo provisto por el usuario y lo empuja a través de un socket TCP a   otro proceso que luego lo muestra.

Para darle un toque especial a las cosas, podrías proporcionar una estructura en la que todo tiene que ser manejado.

Es simple, ya que la mayoría del código se puede encontrar en línea (leer de un archivo, escribir en un socket) y los estudiantes solo tienen que hacer el manejo de la memoria

    
respondido por el ndp 16.12.2013 - 17:08
fuente
4

Dependiendo de las restricciones de su plataforma, sugeriría que implementen algunos DCOM .

La implementación de llamadas DCOM involucra muchas áreas problemáticas diferentes: llamadas de red, manejo de interfaz, ordenación de referencias, gestión de vida útil de objetos distribuida, seguridad de memoria compartida y más: si se hace correctamente, también incluye algunas comprobaciones de ACL de bajo nivel y tal. Un montón de pedacitos y estructuras complejas volando alrededor.

Nunca he visto ningún código DCOM, ya sea que llame al cliente o al servidor, NO tengo errores importantes (a menos que se haya implementado en algún lenguaje "seguro", como VB, e incluso entonces es común).

    
respondido por el AviD 23.12.2013 - 10:22
fuente

Lea otras preguntas en las etiquetas