Pentesting con PowerShell: Cómo desactivar y saltarse AMSI (Anti Malware Scan Interface) #pentest #PowerShell
Cuando se utiliza Powershell para llevar a cabo acciones de post-explotación en un prueba de Ethical Hacking en el que hay que vulnerar la seguridad de un Windows 10 podemos encontrarnos con ciertos problemas a la hora de ejecutar ciertos scripts. Es muy común intentar descargar directamente a memoria un script con Mimikatz, con un código que nos permita hacer pass the hash o hacer un volcado de hashes y que aparezca un mensaje en rojo en la Powershell que nos diga “This script contains malicious content and has been blocked…”.
Esto es lo que se denomina AMSI o Anti Malware Scan Interface. El trabajo que tiene AMSI es el de procesar las entradas a la Powershell o escanear y bloquear cualquiera acción que sea sospechoso de poder ser malo. Powershell tenía el “beneplácito” de poder ejecutar cualquier cosa y era un vector, cada vez más, interesante para que el código malicioso se ejecutase. Por esta razón, Microsoft puso el foco en esto y lanzó AMSI. En resumen, AMSI utiliza la detección basada en cadenas para determinar si un código es malo o no en Powershell.
Es aquí donde surge el juego del bypass a AMSI. Hoy en día, podemos decir, que AMSI es capaz de detectar la gran mayoría de scripts de pentesting escritos en Powershell que son públicos. De nuevo comento que es aquí donde comienza el juego del bypass a AMSI.
Ya hemos visto esto a lo largo de la historia: el malware que es detectado por el antivirus, cambia de forma y ya no es detectado, y volvemos al bucle por parte del antivirus. Un método que salta la protección del UAC, la protección de AppLocker. Y desde hace ya un tiempo AMSI. Para ejemplificar que AMSI existe y está ahí, podemos verlo en la Figura 2. Es una consola de Powershell en un debbugger.
Primer paso. Entendiendo AMSI
En este primer ejemplo vamos a ver cómo una palabra está prohibida en la Powershell. Si escribimos ‘amsiutils’ en la Powershell nos saldrá un mensaje en rojo diciéndonos que ha sido bloqueada la ejecución. Evita esa palabra en cualquier script.
Evitar la detección de cadenas es sencillo, ya que utilizando la codificación adecuada o dividiendo en trozos, tal y como se puede observar en la siguiente imagen, se puede evitar o eludir la protección.
Esto al final acabará dependiendo de la versión de compilación de Windows 10 que se esté ejecutando, es decir, Microsoft pondrá esfuerzos en ir tapando este tipo de técnicas de evasión e irán apareciendo nuevas técnicas. Es decir, no estaremos ante las primeras, ni las últimas, técnicas para hacer un bypass de AMSI.
Como ejemplo podemos hablar de varias maneras de ejecutar el código “prohibido” una vez se reconstruye. La primera es utilizando Base64 para poder evadir la detección de cadenas:
La segunda vía sencilla es utilizar XOR para engañar a AMSI. Cifrar y descifrar puede ser una técnica efectiva, ya que necesita una mayor abstracción para su detección.
Estas técnicas son para evitar detecciones de cadenas de una forma ‘Get Around’. Realmente no se quiere eso cuando hablamos de un bypass de AMSI. Lo que se pretende es poder ejecutar el script tal cual, sin tener que jugar con la ofuscación de las cadenas o de los caracteres. Se quiere ejecutar el script en el estado en el que AMSI lo bloquea.
Una de las técnicas utilizadas en los últimos meses y que será válida en función de la compilación de Windows 10 es la del parcheo de memoria o Memory Patching. Este es el verdadero bypass. Eso sí, tenemos que tener claro que lo que se realiza es la desactivación de AMSI.
Funcionamiento del bypass de AMSI
AMSI tiene diversas funciones que son ejecutadas antes de cualquier código de Powershell, desde Powershell 3.0 en adelante. Para pasar por alto, es decir, hacer un bypass, completamente y ejecutar el código se necesita parchear en memoria para desactivarlo completamente. Otro tipo de técnica es parchear el contador del buffer del scan de AMSI, con el objetivo de que lea 0 caracteres de entrada, en vez de leer los N caracteres que el usuario o el proceso introduce en Powershell.
Para utilizar la técnica de parcheo en memoria y desactivar AMSI se puede utilizar un código en C# para compilarlo y lograr una DLL. Esta DLL aplicará dicha técnica y AMSI quedará deshabilitado. Como es lógico, esta técnica puede funcionar o no, ya que las actualizaciones van tapando vías.
Para simplificar el proceso se puede encontrar una función de Powershell llamada Bypass-AMSI. Esta función implementa la carga del código de la DLL en Base64. El problema puede radicar en que AMSI lo detecte como algo malicioso.
La función es sencilla. Aquí se puede probar a utilizar y que todo funcione directamente en memoria o si AMSI lo detecta como función maliciosa habría que probar la técnica de generar la DLL e importarla desde el proceso de Powershell.
En el siguiente ejemplo, se puede ver cómo cargamos la DLL que implementa el código de Memory Patching para AMSI. Se intenta ejecutar el código malicioso de la variable $v y obtenemos el bloqueo de AMSI.
Al ejecutar el método “Disable()” se está parcheando en memoria y logrando desactivar AMSI. Entonces, probamos a ejecutar el código que se almacena en la variable y obtenemos la ejecución, sin necesidad de modificar el código u ofuscarlo.
Conclusión
Sin duda el estudio e investigación en AMSI es interesante y traerá más de una noticia en los próximos meses. Microsoft mejora la seguridad de algo tan importante como Powershell, pero siempre habrá que buscar los huecos para que esa seguridad mejore. El juego del gato y del ratón.
Autor: Pablo González Pérez (@pablogonzalezpe), escritor de los libros "Metasploit para Pentesters", "Hacking con Metasploit: Advance Pentesting" "Hacking Windows", "Ethical Hacking", "Got Root" y “Pentesting con Powershell”, Microsoft MVP en Seguridad y Security Researcher en el equipo de "Ideas Locas" de la unidad CDO de Telefónica.
Figura 1: Pentesting con PowerShell: Cómo desactivar y saltarse AMSI (Anti Malware Scan Interface) |
Esto es lo que se denomina AMSI o Anti Malware Scan Interface. El trabajo que tiene AMSI es el de procesar las entradas a la Powershell o escanear y bloquear cualquiera acción que sea sospechoso de poder ser malo. Powershell tenía el “beneplácito” de poder ejecutar cualquier cosa y era un vector, cada vez más, interesante para que el código malicioso se ejecutase. Por esta razón, Microsoft puso el foco en esto y lanzó AMSI. En resumen, AMSI utiliza la detección basada en cadenas para determinar si un código es malo o no en Powershell.
Es aquí donde surge el juego del bypass a AMSI. Hoy en día, podemos decir, que AMSI es capaz de detectar la gran mayoría de scripts de pentesting escritos en Powershell que son públicos. De nuevo comento que es aquí donde comienza el juego del bypass a AMSI.
Figura 2: AMSI en el debugger |
Ya hemos visto esto a lo largo de la historia: el malware que es detectado por el antivirus, cambia de forma y ya no es detectado, y volvemos al bucle por parte del antivirus. Un método que salta la protección del UAC, la protección de AppLocker. Y desde hace ya un tiempo AMSI. Para ejemplificar que AMSI existe y está ahí, podemos verlo en la Figura 2. Es una consola de Powershell en un debbugger.
Primer paso. Entendiendo AMSI
En este primer ejemplo vamos a ver cómo una palabra está prohibida en la Powershell. Si escribimos ‘amsiutils’ en la Powershell nos saldrá un mensaje en rojo diciéndonos que ha sido bloqueada la ejecución. Evita esa palabra en cualquier script.
Figura 3: Palabra prohibida |
Evitar la detección de cadenas es sencillo, ya que utilizando la codificación adecuada o dividiendo en trozos, tal y como se puede observar en la siguiente imagen, se puede evitar o eludir la protección.
Figura 4: Detección "evadida" con concatenación |
Esto al final acabará dependiendo de la versión de compilación de Windows 10 que se esté ejecutando, es decir, Microsoft pondrá esfuerzos en ir tapando este tipo de técnicas de evasión e irán apareciendo nuevas técnicas. Es decir, no estaremos ante las primeras, ni las últimas, técnicas para hacer un bypass de AMSI.
Como ejemplo podemos hablar de varias maneras de ejecutar el código “prohibido” una vez se reconstruye. La primera es utilizando Base64 para poder evadir la detección de cadenas:
1. Se crea una variable con el texto que se quiere ejecutar. Se puede utilizar el truco anterior de separar los strings para lograrlo.
2. Una vez se tiene almacenado el código en una variable se utiliza la conversión a base64: $b = [Convert]::ToBase64String([Text.encoding]::UTF8.GetBytes($varCode))
3. En este punto se tiene en la variable $b el código. Ahora, vamos a convertir de nuevo el código y será mostrado sobre la Powershell: [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($b))
Figura 5: Bypass con uso de Base64 |
La segunda vía sencilla es utilizar XOR para engañar a AMSI. Cifrar y descifrar puede ser una técnica efectiva, ya que necesita una mayor abstracción para su detección.
Figura 6: Evasión con XOR |
Estas técnicas son para evitar detecciones de cadenas de una forma ‘Get Around’. Realmente no se quiere eso cuando hablamos de un bypass de AMSI. Lo que se pretende es poder ejecutar el script tal cual, sin tener que jugar con la ofuscación de las cadenas o de los caracteres. Se quiere ejecutar el script en el estado en el que AMSI lo bloquea.
Una de las técnicas utilizadas en los últimos meses y que será válida en función de la compilación de Windows 10 es la del parcheo de memoria o Memory Patching. Este es el verdadero bypass. Eso sí, tenemos que tener claro que lo que se realiza es la desactivación de AMSI.
Funcionamiento del bypass de AMSI
AMSI tiene diversas funciones que son ejecutadas antes de cualquier código de Powershell, desde Powershell 3.0 en adelante. Para pasar por alto, es decir, hacer un bypass, completamente y ejecutar el código se necesita parchear en memoria para desactivarlo completamente. Otro tipo de técnica es parchear el contador del buffer del scan de AMSI, con el objetivo de que lea 0 caracteres de entrada, en vez de leer los N caracteres que el usuario o el proceso introduce en Powershell.
Para utilizar la técnica de parcheo en memoria y desactivar AMSI se puede utilizar un código en C# para compilarlo y lograr una DLL. Esta DLL aplicará dicha técnica y AMSI quedará deshabilitado. Como es lógico, esta técnica puede funcionar o no, ya que las actualizaciones van tapando vías.
Para simplificar el proceso se puede encontrar una función de Powershell llamada Bypass-AMSI. Esta función implementa la carga del código de la DLL en Base64. El problema puede radicar en que AMSI lo detecte como algo malicioso.
Figura 7: Función Bypass-AMSI |
La función es sencilla. Aquí se puede probar a utilizar y que todo funcione directamente en memoria o si AMSI lo detecta como función maliciosa habría que probar la técnica de generar la DLL e importarla desde el proceso de Powershell.
En el siguiente ejemplo, se puede ver cómo cargamos la DLL que implementa el código de Memory Patching para AMSI. Se intenta ejecutar el código malicioso de la variable $v y obtenemos el bloqueo de AMSI.
Figura 8: Desactivación de AMSI con parcheo en memoria |
Al ejecutar el método “Disable()” se está parcheando en memoria y logrando desactivar AMSI. Entonces, probamos a ejecutar el código que se almacena en la variable y obtenemos la ejecución, sin necesidad de modificar el código u ofuscarlo.
Conclusión
Sin duda el estudio e investigación en AMSI es interesante y traerá más de una noticia en los próximos meses. Microsoft mejora la seguridad de algo tan importante como Powershell, pero siempre habrá que buscar los huecos para que esa seguridad mejore. El juego del gato y del ratón.
Autor: Pablo González Pérez (@pablogonzalezpe), escritor de los libros "Metasploit para Pentesters", "Hacking con Metasploit: Advance Pentesting" "Hacking Windows", "Ethical Hacking", "Got Root" y “Pentesting con Powershell”, Microsoft MVP en Seguridad y Security Researcher en el equipo de "Ideas Locas" de la unidad CDO de Telefónica.
No hay comentarios:
Publicar un comentario