¿Cuáles son los riesgos / vulnerabilidades de seguridad que todo programador C debe tener en cuenta? [cerrado]

13

Existen muchos riesgos de seguridad por tener un contacto cercano con el hardware en lugar de usar API bien probadas y probadas de lenguajes de programación de alto nivel. Es mucho más fácil causar un desbordamiento del búfer en C que en un lenguaje como Java.

¿Cuáles son los riesgos o vulnerabilidades (por ejemplo, desbordamientos de búfer) que todos los programadores de C deben tener en cuenta (vulnerabilidades de IE relevantes para los programadores de C)? ¿A qué problemas podrían conducir estos? ¿Cómo evitarlos y cuáles son los errores comunes que hacen que estos ocurran en los programas?

Anto
fuente
¿Qué pasa con esta lista: owasp.org/index.php/Category:OWASP_Top_Ten_Project ¿Qué más se necesita que esto?
S.Lott
2
@ S.Lott: Parece que se trata mucho de problemas de seguridad en el desarrollo web. Parece que hay más recursos sobre eso en general de lo que realmente estoy pidiendo, parece.
Anto
@Anto: actualice la pregunta para distinguir entre todos los recursos sobre seguridad y la seguridad que está preguntando.
S.Lott
@ S.Lott: No estoy seguro de lo que quieres decir. Pido la seguridad que es de importancia para la mayoría de los programadores de C, es decir, cosas como desbordamientos de memoria y otras cosas que son posibles en C
Anto
@Anto: "Parece que hay más recursos en eso [seguridad web?] En general de lo que realmente estoy pidiendo" Parece decir que estás preguntando acerca de alguna seguridad que no sea seguridad web. ¿Cierto? Si es así, actualice la pregunta para explicar lo que está buscando. ¿Falso? Entonces está preguntando acerca de la seguridad web, en cuyo caso, ¿por qué no se menciona la lista OWASP en su pregunta?
S.Lott

Respuestas:

13

Los desbordamientos del búfer son grandes. Nada en C se verifica por rango de forma predeterminada, por lo que es muy fácil sobrescribir un búfer. Hay una función de biblioteca estándar gets(), que no se puede evitar que desborde el búfer, y casi nunca se debe usar.

Existen algunas técnicas de nivel de implementación para impedir la explotación, como codificar bloques de almacenamiento dinámico, pero eso no detendrá el desbordamiento del búfer en los búferes locales, que a menudo pueden hacer cosas interesantes como cambiar la dirección a la que volverá una función.

No hay una buena solución general en C. Muchas funciones de la biblioteca tienen versiones que limitarán la cantidad que escribirán. aunque calcular eso puede ser torpe. Hay un software que puede detectar desbordamientos del búfer de almacenamiento dinámico en la prueba, siempre que se ejecute la prueba adecuada, y el desbordamiento de la pila a menudo aparecerá como un bloqueo en la prueba. Aparte de eso, es una cuestión de codificación cuidadosa y revisión de código.

Un problema relacionado es el problema de escribir en un búfer demasiado pequeño por un carácter, olvidando que una cadena C que tiene una longitud de n caracteres requiere n + 1 caracteres en la memoria, debido al '\0'terminador. Si el atacante puede almacenar una cadena sin el terminador, cualquier función de C que espere una cadena continuará procesándose hasta que llegue a un byte cero, lo que podría resultar en copiar o generar más información de la deseada (o golpear la memoria protegida para un ataque de DOS ) La solución, nuevamente, es la concientización, la atención y las revisiones de código.

Hay otro riesgo con la printf()familia. Si alguna vez escribe char * str; ... printf(str);, se está preparando para problemas si strcontiene un '%' cuando se imprime. La %ndirectiva de formato permite printf()escribir en la memoria. La solución es printf("%s", str);o puts(str);. (Además, use el C99 en snprintf()lugar de sprintf()).

El uso de enteros sin signo, particularmente como índices de bucle, puede causar problemas. Si asigna un pequeño valor negativo a un sin signo, obtendrá un gran valor positivo. Eso puede socavar cosas como procesar solo N instancias de algo, o en funciones limitadas como strncpy(). Examine todos los enteros sin signo. Es posible que desee evitar unsigned short, ya que un valor grande en uno de esos se convertirá en un valor positivo grande en un int.

No olvides que un carácter constante, en C, es en realidad un int. Escribir algo así char c; while((c = getchar()) != EOF) ...puede fallar fácilmente, ya EOFque no será representable en a char.

Hay muchos más errores característicos de C en los que puedo pensar, pero estos podrían causar problemas de seguridad.

David Thornley
fuente
No hay necesidad de usar printf("%s", str)una cuerda desnuda cuando puts(str)haga el mismo trabajo.
Blrfl
@Blrfl pero putsagrega un carácter de nueva línea mientras printfque no lo hace.
derecha el
También podría hacer fputs(str, stdout), que no lo hace.
Blrfl
En cuanto al desbordamiento de enteros: el uso de ints firmados no es una solución, ya que desbordarlos causará UB. La única solución (dolorosa) es probar formalmente que nunca se desbordará o comprobar en tiempo de ejecución (pero comprobar correctamente, lo que también es complicado sin desbordar en la comprobación).
sleske
@DavidThornley: C11 y C ++ 14 estándar eliminado función gets () de la biblioteca estándar debido a su peligrosidad.
Destructor
5

Algunos de los riesgos específicos de C incluyen: desbordamientos de búfer , formateo de ataques de cadena y desbordamientos de enteros .

Nemanja Trifunovic
fuente
1
No hay nada específico de C sobre los desbordamientos del búfer: cualquier lenguaje con punteros puede tener esto. Los desbordamientos de enteros se aplican a casi cualquier idioma, y ​​también pueden ocurrir fácilmente en el código administrado.
Steve
1
@ Steve, en realidad no son los punteros los que causan ese problema, sino cómo el lenguaje no impone los límites de la matriz.
Doug T.
2
@Steve la pregunta no era preguntar sobre cosas que solo conciernen a C, sino algo que los programadores de C deberían tener en cuenta.
AttackingHobo
1
@Steve: C es inusualmente susceptible a desbordamientos del búfer, en parte debido a la falta de soporte para la verificación de rangos y al número de funciones de biblioteca que felizmente desbordarán los búferes para usted.
David Thornley
Entiendo que la pregunta es sobre C en particular, pero creo que vale la pena aclarar en caso de que la respuesta se lea fuera de contexto que estos riesgos son más generales. En particular, los desarrolladores de código administrado son (en mi humilde opinión) demasiado complacientes con la seguridad, y los desbordamientos de enteros en particular afectan la mayoría de los idiomas.
Steve
4

Aquí hay un riesgo fácil de pasar por alto que puede causar problemas que llevará horas solucionar.

Considere el siguiente código, que se compilará sin problemas.

if(lpstr_current_state = CONST_EMERGENCY_STATE_HOLY_CRAP)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}

Cuando verifica si lpstr_current_stateestá dentro CONST_EMERGENCY_STATE_HOLY_CRAP, en realidad está asignando. Es mejor poner siempre la variable constante a la izquierda. Cuando coloca la constante a la izquierda, el compilador fallará porque no puede asignar un valor a una variable.

if(CONST_EMERGENCY_STATE_HOLY_CRAP = lpstr_current_state)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}

Entonces puedes decirte fácilmente a ti mismo: "Mierda, eso podría haber sido malo", mientras arreglas el código para leer ...

if(CONST_EMERGENCY_STATE_HOLY_CRAP == lpstr_current_state)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}
Kristofer Hoch
fuente
77
Es fácil para un compilador atrapar y marcar como advertencia, a diferencia de otros problemas. Desafortunadamente, no todos los compiladores lo hacen fácil.
David Thornley
2
Eso puede suceder en lenguajes que no sean C, cualquier lenguaje que use =y ==.
FrustratedWithFormsDesigner
3
Esto tampoco es realmente una vulnerabilidad de seguridad, es un error.
Chris Pitman
1
Estas se llaman condiciones de Yoda.
2
@Kristofer Hoch: Si vamos a llamar a cualquier posible error C, y considerarlo aquí, vamos a necesitar un foro mucho más grande.
David Thornley
0

Solo hay un riesgo de seguridad: el hecho de que haya personas externas que harán todo lo posible para detectar cualquier vulnerabilidad en su software y explotarlo para su propio beneficio. Todo lo demás se sigue de allí.

Entonces, cuando piensas que "nadie en su sano juicio lo haría ...", entonces debes pensar de inmediato "excepto que alguien que quiera hackear las computadoras de otras personas haría exactamente eso".

La mayor consecuencia es que cada vez que reacciona a eventos externos (por ejemplo, procesando datos entregados desde el exterior), debe asumir que estos datos estaban bajo el control de su peor enemigo.

gnasher729
fuente
Si bien estoy de acuerdo con los párrafos dos y tres, culpar al atacante es un poco pesado en mis ojos. Siempre se necesitan dos para un ataque exitoso: un programador que se equivoca y un atacante que atrapa al programador en el acto. Sin embargo, la vulnerabilidad de seguridad existe antes de que el atacante pueda explotarla. Y por eso, se debe culpar al programador.
cmaster - reinstalar a monica el