2009-05-15 23 views
55

Estoy buscando averiguar por qué strncpy se considera inseguro. ¿Alguien tiene algún tipo de documentación sobre esto o ejemplos de un exploit que lo usa?¿Por qué strncpy es inseguro?

+4

Yo tenía entendido que strcpy era insegura y que strncpy fue la versión segura de ello. –

+26

Sin embargo, no hay _s en el nombre. No se puede asegurar sin un _s ... – Shog9

+2

Si usa C++, simplemente no lo use y use std :: string. – lothar

Respuesta

35

Eche un vistazo a this site; es una explicación bastante detallada. Básicamente, strncpy() no requiere terminación NUL, y por lo tanto es susceptible a una variedad de exploits.

+1

buen punto. Entonces, incluso con strncpy, asegúrese de que el buffer termine con un '\ 0'. – rampion

+13

+1, pero es bueno tener en cuenta que strncpy solo es inseguro cuando te olvidas de agregar manualmente el terminador nulo. Si tiene problemas para recordarlo, considere una función de envoltura, que siempre establece el carácter final en '\ 0' después de llamar a strncpy. – ojrac

+0

@ojrac, creo que el contenedor se llama strncpy_s(), al menos para los usuarios del tiempo de ejecución C de Microsoft. También hay _wcsncpy_s() para los entusiastas del charco ancho. – RBerteig

6

Para usar strncpy de forma segura, uno debe (1) pegar manualmente un carácter nulo en el búfer de resultados, (2) saber que el búfer termina con un nulo de antemano, y pasar (longitud-1) a strncpy, o 3) sepa que el búfer nunca se copiará utilizando ningún método que no limite su longitud a la longitud del búfer.

Es importante tener en cuenta que strncpy llenará de cero todo el contenido del búfer más allá de la cadena copiada, mientras que otras variantes strcpy de longitud limitada no lo harán. En algunos casos, esto puede ser una pérdida de rendimiento, pero en otros casos puede ser una ventaja de seguridad. Por ejemplo, si se usa strlcpy para copiar "supercalifragilisticexpalidocious" en un búfer y luego para copiar "it", el búfer contendrá "it^ercalifragilisticexpalidocious ^" (usando "^" para representar un byte cero). Si el búfer se copia a un formato de tamaño fijo, los datos adicionales pueden etiquetarse junto con él.

11

El problema original es que strcpy(3) no era un memory-safe operation, por lo que un atacante podría suministrar una cadena más larga que el búfer que sobrescribiría el código en la pila, y si se arreglara cuidadosamente, podría ejecutar código arbitrario del atacante.

Pero strncpy(3) tiene otro problema, ya que no proporciona la terminación nula en todos los casos en el destino. (Imagine una cadena fuente más larga que el búfer de destino.) Las operaciones futuras pueden esperar cadenas C terminados conforme entre búferes de igual tamaño y un mal funcionamiento aguas abajo cuando el resultado se copia a un tercer búfer.

Usar strncpy (3) es mejor que strcpy (3) pero cosas como strlcpy (3) son mejores.

4

La pregunta se basa en una premisa "cargada", que hace que la pregunta en sí no sea válida.

La conclusión es que strncpy no se considera inseguro y nunca se ha considerado inseguro. Las únicas afirmaciones de "inseguridad" que se pueden atribuir a esa función son las afirmaciones generales de la inseguridad general del modelo de memoria C y el lenguaje C en sí mismo. (Pero obviamente ese es un tema completamente diferente).

En el ámbito de lenguaje C la creencia equivocada de algún tipo de "inseguridad" inherente a strncpy se deriva del patrón de dudosa generalizada de utilizar strncpy para "copia cadena de seguridad", es decir, algo esta función no hacer y nunca ha sido destinado para. Tal uso es de hecho altamente propenso a errores. Pero incluso si coloca un signo de igualdad entre "altamente propenso a errores" e "inseguro", sigue siendo un problema de uso (es decir, una falta de problema educativo) no un problema de strncpy.

Básicamente, se puede decir que el único problema con strncpy es una denominación desafortunada, lo que hace que los programadores novatos asumen que ellos entienden lo que hace esta función en lugar de una lectura de la especificación. Si se mira el nombre de la función, un programador incompetente asume que strncpy es una "versión segura" de strcpy, mientras que en realidad estas dos funciones no están relacionadas.

Se puede hacer exactamente el mismo reclamo contra el operador de división, por ejemplo.Como la mayoría de ustedes sabe, una de las preguntas más frecuentes sobre el lenguaje C es "Asumí que 1/2 se evaluará a 0.5, pero en su lugar obtuve 0. ¿Por qué?" Sin embargo, no afirmamos que el operador de la división sea inseguro solo porque los principiantes del lenguaje tienden a malinterpretar su comportamiento.

Por otro ejemplo, no llamamos a las funciones del generador de números pseudoaleatorio "inseguras" solo porque los programadores incompetentes a menudo se sorprenden desagradablemente por el hecho de que su salida no es realmente aleatoria.

Así es exactamente con la función strncpy. Así como a los programadores principiantes les lleva tiempo aprender qué hacen realmente los generadores de números pseudoaleatorios, les lleva tiempo aprender qué hace realmente strncpy. Se necesita tiempo para aprender que strncpy es una función conversión, destinado a convertir cero terminados cadenas a cadenas de ancho fijo. Toma tiempo aprender que strncpy no tiene absolutamente nada que ver con "la copia segura de cadenas" y no se puede usar con ese propósito.

Concedido, normalmente un estudiante de idiomas necesita más tiempo para aprender el propósito de strncpy que para resolver las cosas con el operador de la división. Sin embargo, esta es una base para cualquier reclamo de "inseguridad" contra strncpy.

P.S. El documento CERT vinculado en la respuesta aceptada está dedicado exactamente a eso: demostrar las inseguridades del típico abuso incompetente de strncpy funciona como una versión "segura" de strcpy. No se pretende en modo alguno afirmar que strncpy sea de alguna manera inseguro.

+2

Cuando la gente dice "' strncpy' es inseguro "lo que quieren decir es" No tiene un [pozo de éxito] (http://blogs.msdn.com/b/brada/archive/2003/10/02/ 50420.aspx) ". Cual es verdad. –

0

La peor situación se produce cuando la memoria de búfer de origen y de destino se superpone entre sí. Así que evite el uso de strncpy cuando sienta que puede haber una superposición de situaciones en su programa. En lugar de strncpy puede usar la función memmove en el escenario de superposición.

A continuación describo un ejemplo simple que describe la estructura en el escenario de superposición.

#include <stdio.h> 
    #include <string.h> 
    int main() { 

    char aszMessage[10] ="12345"; //Source Buffer 
    short siLen=4; // Length of byte you want to copy 


    strncpy(aszMessage + 2,aszMessage+1,siLen);//Here memory overlap 

    printf("\n\n\tMessage = %s\n",aszMessage); 



    return 0; 
} 

Aquí estoy aceptando, la salida debe ser 122.345 pero en este caso la salida es 122222, que es el mayor escenario de repliegue de strncpy.

Este problema se puede resolver utilizando la función memove.

#include <stdio.h> 
#include <string.h> 
int main() { 

char aszMessage[10] ="12345"; //Source Buffer 
short siLen=4; // Length of byte you want to copy 


memmove(aszMessage + 2,aszMessage+1,siLen);//Here memory overlap 

printf("\n\n\tMessage = %s\n",aszMessage); 


return 0; 
} 

Ahora estoy recibiendo de salida deseo 122345.

Para más detalles se puede ver este enlace http://aticleworld.com/how-to-use-strncpy-and-how-to-write-your-own-strncpy/

+1

Lo siento Rad Lexus en el futuro, evitaré volver a hacerlo. –

Cuestiones relacionadas