stringtranslate.com

Código Shell

En el ámbito de la piratería informática , un shellcode es un pequeño fragmento de código utilizado como carga útil en la explotación de una vulnerabilidad de software . Se denomina "shellcode" porque normalmente inicia un shell de comandos desde el que el atacante puede controlar la máquina comprometida, pero cualquier fragmento de código que realice una tarea similar puede llamarse shellcode. Debido a que la función de una carga útil no se limita simplemente a generar un shell, algunos han sugerido que el nombre shellcode es insuficiente. [1] Sin embargo, los intentos de reemplazar el término no han ganado una amplia aceptación. El shellcode se escribe comúnmente en código de máquina .

Al crear un código shell, generalmente es deseable hacerlo pequeño y ejecutable, lo que permite que se lo use en la mayor variedad posible de situaciones. [2] En el código ensamblador, la misma función se puede realizar de múltiples maneras y existe cierta variedad en las longitudes de los códigos de operación que se pueden usar para este propósito; los buenos escritores de códigos shell pueden usar estos pequeños códigos de operación para crear códigos shell más compactos. [3] Algunos han alcanzado el tamaño más pequeño posible manteniendo la estabilidad. [4]

Tipos de shellcode

El shellcode puede ser local o remoto , dependiendo de si le da a un atacante control sobre la máquina en la que se ejecuta (local) o sobre otra máquina a través de una red (remoto).

Local

Un atacante que tiene acceso limitado a una máquina, pero puede explotar una vulnerabilidad (por ejemplo, un desbordamiento de búfer ) en un proceso con mayores privilegios de esa máquina, utiliza el shellcode local . Si se ejecuta correctamente, el shellcode le proporcionará al atacante acceso a la máquina con los mismos privilegios que el proceso objetivo.

Remoto

El shellcode remoto se utiliza cuando un atacante quiere atacar un proceso vulnerable que se ejecuta en otra máquina en una red local , intranet o red remota . Si se ejecuta con éxito, el shellcode puede proporcionar al atacante acceso a la máquina de destino a través de la red. Los shellcodes remotos normalmente utilizan conexiones de socket TCP/IP estándar para permitir que el atacante acceda al shell en la máquina de destino. Dicho shellcode se puede clasificar en función de cómo se configure esta conexión: si el shellcode establece la conexión, se denomina "shell inverso" o shellcode de conexión inversa porque el shellcode se conecta de nuevo a la máquina del atacante. Por otro lado, si el atacante establece la conexión, el shellcode se denomina bindshell porque el shellcode se vincula a un puerto determinado en la máquina de la víctima. Hay un shellcode peculiar llamado bindshell random port que omite la parte de vinculación y escucha en un puerto aleatorio que el sistema operativo pone a disposición . Debido a eso, el bindshell random port se convirtió en el shellcode bindshell estable más pequeño para x86_64 disponible hasta la fecha. Un tercer tipo, mucho menos común, es el shellcode de reutilización de sockets . Este tipo de shellcode se utiliza a veces cuando un exploit establece una conexión con el proceso vulnerable que no se cierra antes de que se ejecute el shellcode. El shellcode puede entonces reutilizar esta conexión para comunicarse con el atacante. El shellcode de reutilización de sockets es más elaborado, ya que el shellcode necesita averiguar qué conexión reutilizar y la máquina puede tener muchas conexiones abiertas. [5]

Se puede utilizar un cortafuegos para detectar conexiones salientes realizadas mediante shellcode de conexión inversa, así como conexiones entrantes realizadas mediante bindshells. Por lo tanto, pueden ofrecer cierta protección contra un atacante, incluso si el sistema es vulnerable, al impedir que el atacante se conecte al shell creado por el shellcode. Una de las razones por las que a veces se utiliza el shellcode de reutilización de sockets es que no crea nuevas conexiones y, por lo tanto, es más difícil de detectar y bloquear.

Descargar y ejecutar

Descargar y ejecutar es un tipo de shellcode remoto que descarga y ejecuta algún tipo de malware en el sistema de destino. Este tipo de shellcode no genera un shell, sino que le indica a la máquina que descargue un determinado archivo ejecutable de la red, lo guarde en el disco y lo ejecute. Hoy en día, se usa comúnmente en ataques de descarga automática , donde una víctima visita una página web maliciosa que a su vez intenta ejecutar dicha descarga y ejecutar shellcode para instalar software en la máquina de la víctima. Una variación de este tipo de shellcode descarga y carga una biblioteca . [6] [7] Las ventajas de esta técnica son que el código puede ser más pequeño, que no requiere que el shellcode genere un nuevo proceso en el sistema de destino y que el shellcode no necesita código para limpiar el proceso objetivo, ya que esto lo puede hacer la biblioteca cargada en el proceso.

Escenificado

Cuando la cantidad de datos que un atacante puede inyectar en el proceso de destino es demasiado limitada para ejecutar directamente un código shell útil, es posible ejecutarlo en etapas. Primero, se ejecuta un pequeño fragmento de código shell (etapa 1). Luego, este código descarga un fragmento más grande de código shell (etapa 2) en la memoria del proceso y lo ejecuta.

Búsqueda de huevos

Esta es otra forma de shellcode por etapas , que se utiliza si un atacante puede inyectar un shellcode más grande en el proceso pero no puede determinar en qué parte del proceso terminará. Se inyecta un shellcode pequeño de búsqueda de huevos en el proceso en una ubicación predecible y se ejecuta. Luego, este código busca el shellcode más grande (el huevo ) en el espacio de direcciones del proceso y lo ejecuta. [8]

Tortilla

Este tipo de shellcode es similar al shellcode de búsqueda de huevos , pero busca múltiples bloques pequeños de datos ( huevos ) y los recombina en un bloque más grande (la tortilla ) que se ejecuta posteriormente. Esto se utiliza cuando un atacante solo puede inyectar una cantidad de bloques pequeños de datos en el proceso. [9]

Estrategia de ejecución de Shellcode

Un exploit inyectará comúnmente un shellcode en el proceso objetivo antes o al mismo tiempo que explota una vulnerabilidad para obtener control sobre el contador del programa . El contador del programa se ajusta para que apunte al shellcode, después de lo cual se ejecuta y realiza su tarea. La inyección del shellcode se realiza a menudo almacenándolo en datos enviados a través de la red al proceso vulnerable, suministrándolo en un archivo que es leído por el proceso vulnerable o a través de la línea de comandos o el entorno en el caso de exploits locales.

Codificación de Shellcode

Dado que la mayoría de los procesos filtran o restringen los datos que se pueden inyectar, a menudo es necesario escribir un código shell que permita estas restricciones. Esto incluye hacer que el código sea pequeño, sin valores nulos o alfanumérico . Se han encontrado varias soluciones para sortear estas restricciones, entre ellas:

Dado que la detección de intrusiones puede detectar firmas de códigos shell simples que se envían a través de la red, a menudo se codifican, se autodescifran o se vuelven polimórficos para evitar su detección.

Codificación porcentual

Los exploits que apuntan a los navegadores comúnmente codifican el código shell en una cadena de JavaScript usando codificación de porcentaje , codificación de secuencia de escape " \uXXXX " o codificación de entidad . [10] Algunos exploits también ofuscan aún más la cadena de código shell codificada para evitar su detección por IDS .

Por ejemplo, en la arquitectura IA-32 , así es como NOPse verían dos instrucciones (sin operación), la primera sin codificar:

90 NOP90 NOP

Esta instrucción se utiliza en diapositivas NOP .

Código de shell sin valores nulos

La mayoría de los códigos shell se escriben sin el uso de bytes nulos porque están destinados a ser inyectados en un proceso de destino a través de cadenas terminadas en nulo . Cuando se copia una cadena terminada en nulo, se copiará hasta el primer nulo incluido, pero los bytes posteriores del código shell no se procesarán. Cuando se inyecta código shell que contiene nulos de esta manera, solo se inyectará una parte del código shell, lo que lo hace incapaz de ejecutarse correctamente.

Para producir un shellcode sin valores nulos a partir de un shellcode que contiene bytes nulos , se pueden sustituir las instrucciones de máquina que contienen ceros por instrucciones que tengan el mismo efecto pero que no contengan valores nulos. Por ejemplo, en la arquitectura IA-32 se podría sustituir esta instrucción:

B8 01000000 MOV EAX,1 // Establezca el registro EAX en 0x00000001

que contiene ceros como parte del literal ( 1se expande a 0x00000001) con estas instrucciones:

33C0 XOR EAX,EAX // Establece el registro EAX en 0x0000000040 INC EAX // Aumentar EAX a 0x00000001

que tienen el mismo efecto pero toman menos bytes para codificar y están libres de nulos.

Código de shell alfanumérico e imprimible

Un shellcode alfanumérico es un shellcode que consiste en caracteres ASCII o Unicode alfanuméricos, o que se ensambla a sí mismo durante su ejecución en caracteres ASCII o Unicode completamente alfanuméricos , como 0–9, A–Z y a–z. [11] [12] Este tipo de codificación fue creada por piratas informáticos para ocultar código de máquina funcional dentro de lo que parece ser texto. Esto puede ser útil para evitar la detección del código y permitir que el código pase a través de filtros que eliminan caracteres no alfanuméricos de las cadenas (en parte, dichos filtros fueron una respuesta a los exploits de shellcode no alfanuméricos). Un tipo similar de codificación se llama código imprimible y usa todos los caracteres imprimibles (0–9, A–Z, a–z, !@#%^&*() etc.). Una variante igualmente restringida es el código ECHOable que no contiene ningún carácter que no sea aceptado por el comando ECHO . Se ha demostrado que es posible crear shellcode que parezca texto normal en inglés. [13] La escritura de código alfanumérico o imprimible requiere una buena comprensión de la arquitectura del conjunto de instrucciones de la(s) máquina(s) en la(s) que se va a ejecutar el código. Se ha demostrado que es posible escribir código alfanumérico que sea ejecutable en más de una máquina, [14] constituyendo así un código ejecutable de arquitectura múltiple .

En determinadas circunstancias, un proceso de destino filtrará cualquier byte del shellcode inyectado que no sea un carácter imprimible o alfanumérico . En tales circunstancias, el rango de instrucciones que se pueden utilizar para escribir un shellcode se vuelve muy limitado. Rix publicó una solución a este problema en Phrack 57 [11] en la que demostró que era posible convertir cualquier código en código alfanumérico. Una técnica que se utiliza a menudo es crear un código automodificable, porque esto permite que el código modifique sus propios bytes para incluir bytes fuera del rango normalmente permitido, ampliando así el rango de instrucciones que puede utilizar. Utilizando este truco, se puede crear un decodificador automodificable que inicialmente utiliza sólo bytes en el rango permitido. El código principal del shellcode se codifica, también utilizando sólo bytes en el rango permitido. Cuando se ejecuta el shellcode de salida, el decodificador puede modificar su propio código para poder utilizar cualquier instrucción que necesite para funcionar correctamente y luego continúa decodificando el shellcode original. Después de decodificar el shellcode, el decodificador le transfiere el control, por lo que puede ejecutarse normalmente. Se ha demostrado que es posible crear un código shell arbitrariamente complejo que parezca texto normal en inglés. [13]

Código de shell de prueba Unicode

Los programas modernos utilizan cadenas Unicode para permitir la internacionalización del texto. A menudo, estos programas convertirán las cadenas ASCII entrantes a Unicode antes de procesarlas. Las cadenas Unicode codificadas en UTF-16 utilizan dos bytes para codificar cada carácter (o cuatro bytes para algunos caracteres especiales). Cuando una cadena ASCII ( Latin-1 en general) se transforma en UTF-16, se inserta un byte cero después de cada byte en la cadena original. Obscou demostró en Phrack 61 [12] que es posible escribir shellcode que pueda ejecutarse correctamente después de esta transformación. Existen programas que pueden codificar automáticamente cualquier shellcode en shellcode alfanumérico a prueba de UTF-16, basados ​​en el mismo principio de un pequeño decodificador automodificable que decodifica el shellcode original.

Plataformas

La mayoría del shellcode está escrito en código de máquina debido al bajo nivel en el que la vulnerabilidad que se está explotando le da a un atacante acceso al proceso. Por lo tanto, el shellcode a menudo se crea para apuntar a una combinación específica de procesador , sistema operativo y paquete de servicio , llamada plataforma . Para algunos exploits, debido a las restricciones impuestas al shellcode por el proceso objetivo, se debe crear un shellcode muy específico. Sin embargo, no es imposible que un shellcode funcione para múltiples exploits, paquetes de servicio, sistemas operativos e incluso procesadores. [15] [16] [17] Tal versatilidad se logra comúnmente creando múltiples versiones del shellcode que apuntan a las diversas plataformas y creando un encabezado que se ramifica a la versión correcta para la plataforma en la que se ejecuta el código. Cuando se ejecuta, el código se comporta de manera diferente para diferentes plataformas y ejecuta la parte correcta del shellcode para la plataforma en la que se ejecuta.

Análisis de Shellcode

El shellcode no se puede ejecutar directamente. Para analizar lo que intenta hacer un shellcode, se debe cargar en otro proceso. Una técnica de análisis común es escribir un pequeño programa en C que contenga el shellcode como un búfer de bytes y luego usar un puntero de función o usar un ensamblador en línea para transferirle la ejecución. Otra técnica es usar una herramienta en línea, como shellcode_2_exe, para incrustar el shellcode en un husk ejecutable prefabricado que luego se puede analizar en un depurador estándar. También existen herramientas de análisis de shellcode especializadas, como el proyecto sclog de iDefense que se lanzó originalmente en 2005 como parte del Malcode Analyst Pack. Sclog está diseñado para cargar archivos de shellcode externos y ejecutarlos dentro de un marco de registro de API. También existen herramientas de análisis de shellcode basadas en emulación, como la aplicación sctest que es parte del paquete multiplataforma libemu. Otra herramienta de análisis de shellcode basada en emulación, construida alrededor de la biblioteca libemu, es scdbg que incluye un shell de depuración básico y funciones de informes integradas.

Véase también

Referencias

  1. ^ Foster, James C.; Price, Mike (12 de abril de 2005). Sockets, Shellcode, Porting, & Coding: Exploits de ingeniería inversa y codificación de herramientas para profesionales de la seguridad. Libros de ciencia y tecnología de Elsevier. ISBN 1-59749-005-9.
  2. ^ Anley, Chris; Koziol, Jack (2007). Manual del shellcoder: descubrimiento y explotación de agujeros de seguridad (2.ª ed.). Indianápolis, Indiana, UA: Wiley. ISBN 978-0-470-19882-7.OCLC 173682537  .
  3. ^ Foster, James C. (2005). Ataques de desbordamiento de búfer: detección, explotación, prevención . Rockland, MA, EE. UU.: Syngress. ISBN 1-59749-022-9.OCLC 57566682  .
  4. ^ "Tiny Execve sh - Lenguaje ensamblador - Linux/x86". GitHub . Consultado el 1 de febrero de 2021 .
  5. ^ BHA (6 de junio de 2013). "Shellcode/Socket-reuse" (Reutilización de shellcode/socket) . Consultado el 7 de junio de 2013 .
  6. ^ SkyLined (11 de enero de 2010). "Se ha publicado el shellcode de descarga y carga de biblioteca". Archivado desde el original el 23 de enero de 2010. Consultado el 19 de enero de 2010 .
  7. ^ "Descargar y cargar el shellcode de la biblioteca para Windows x86". 11 de enero de 2010. Consultado el 19 de enero de 2010 .
  8. ^ Skape (9 de marzo de 2004). "Búsqueda segura en el espacio de direcciones virtuales de procesos" (PDF) . nologin . Consultado el 19 de marzo de 2009 .
  9. ^ SkyLined (16 de marzo de 2009). "w32 SEH omelet shellcode". Skypher.com. Archivado desde el original el 23 de marzo de 2009. Consultado el 19 de marzo de 2009 .
  10. ^ "Se ha detectado una gran cantidad de patrones no escapados en JavaScript". Archivado desde el original el 3 de abril de 2015.
  11. ^ ab rix (11 de agosto de 2001). "Escritura de códigos shell alfanuméricos ia32". Phrack . 0x0b (57). Phrack Inc. #0x0f de 0x12. Archivado desde el original el 8 de marzo de 2022 . Consultado el 26 de mayo de 2022 .
  12. ^ ab obscou (13 de agosto de 2003). "Building IA32 'Unicode-Proof' Shellcodes". Phrack . 11 (61). Phrack Inc. #0x0b de 0x0f. Archivado desde el original el 26 de mayo de 2022 . Consultado el 29 de febrero de 2008 .
  13. ^ ab Mason, Joshua; Small, Sam; Monrose, Fabian; MacManus, Greg (noviembre de 2009). English Shellcode (PDF) . Actas de la 16.ª conferencia de la ACM sobre seguridad informática y de las comunicaciones. Nueva York, NY, EE. UU. pp. 524–533. Archivado (PDF) desde el original el 26 de mayo de 2022 . Consultado el 10 de enero de 2010 .(10 páginas)
  14. ^ "Explicación del shellcode alfanumérico de 64 bits y arquitectura múltiple (x86)". Blackhat Academy. Archivado desde el original el 21 de junio de 2012.
  15. ^ eugene (11 de agosto de 2001). "Arquitectura que abarca shellcode". Phrack . Phrack Inc. #0x0e de 0x12. Archivado desde el original el 9 de noviembre de 2021 . Consultado el 29 de febrero de 2008 .
  16. ^ nemo (13 de noviembre de 2005). «OSX - Shellcode multiarquitectura». Divulgación completa . Archivado desde el original el 26 de mayo de 2022. Consultado el 26 de mayo de 2022 .
  17. ^ Cha, Sang Kil; Pak, Brian; Brumley, David ; Lipton, Richard Jay (8 de octubre de 2010) [4 de octubre de 2010]. Programas independientes de la plataforma (PDF) . Actas de la 17.ª conferencia de la ACM sobre seguridad informática y de las comunicaciones (CCS'10). Chicago, Illinois, EE. UU.: Carnegie Mellon University , Pittsburgh, Pensilvania, EE. UU. / Georgia Institute of Technology , Atlanta, Georgia, EE. UU., págs. 547–558. doi :10.1145/1866307.1866369. ISBN . 978-1-4503-0244-9. Archivado (PDF) del original el 26 de mayo de 2022 . Consultado el 26 de mayo de 2022 .[1] (12 páginas) (Véase también: [2])

Enlaces externos