El foro internacional Positive Hack Days 2019 fue el anfitrión del primer concurso IDS Bypass. Los participantes tuvieron que examinar un segmento de red de cinco nodos, luego explotar la vulnerabilidad del servicio o cumplir la condición especificada (por ejemplo, enviar una respuesta HTTP específica) y así obtener la bandera. Encontrar un exploit fue fácil, pero IDS complicó la tarea: el sistema se interpuso entre los participantes y los nodos y verificó cada paquete de red. Los atacantes vieron en el tablero si la firma bloqueaba su conexión. A continuación le contaré en detalle sobre las tareas mismas y analizaré su solución.
100.64.0.11 - Struts
El primer nodo en el número de quienes resolvieron la tarea fue Struts. Después de escanear los puertos Nmap, encontramos el servicio Apache Struts en el puerto 8080.

La vulnerabilidad para Apache Struts se extinguió en 2017: al usar la inyección OGNL, un atacante podría ejecutar cualquier código en Struts sin autorización. Hay un exploit, por ejemplo, en
GitHub , pero se detecta IDS:
[Drop] [**] [1:1001:1] Apache Struts2 OGNL inj in header (CVE-2017-5638) [**]
El código de firma en sí no está disponible para los participantes, pero a partir del mensaje en los registros puede comprender el mecanismo de su funcionamiento. En este caso, la firma detectó una inyección de OGNL en HTTP:
GET /showcase.action HTTP/1.1 Accept-Encoding: identity Host: 100.64.0.11:8080 Content-Type: %{(
Si examinamos el comportamiento de IDS, será obvio que captura la combinación% {al comienzo del encabezado Content-Type. Hay varias soluciones:
- El participante @empty_jack intentó romper la combinación de caracteres% {con su propio diccionario para difuminar y así llegó a una solución con la línea Content-Type:% $ {.
- Fuzz la solicitud HTTP en sí. El miembro @ c00lhax0r descubrió que el carácter nulo al comienzo del encabezado también omitiría IDS: Content-Type: \ 0 $ {.
- La mayoría de las vulnerabilidades para CVE-2017-5638 hacen una inyección con un símbolo de porcentaje. Pero algunos investigadores de esta y las vulnerabilidades anteriores de Apache Struts escriben que la inyección puede comenzar con% y $. Por lo tanto, la combinación de $ {omitirá la firma IDS y ejecutará el código en el sistema. Tal decisión fue concebida inicialmente.
Esta tarea fue la más fácil, fue decidida por ocho participantes.
100.64.0.10 - Solr
En el puerto 8983 estaba el servidor Apache Solr, escrito en Java.
$ nmap -Pn -sV -p1-10000 100.64.0.10 22/tcp open ssh (protocol 2.0) 8983/tcp open http Jetty

Un exploit para Apache Solr 5.3.0 es fácil de encontrar:
CVE-2019-0192 . Un atacante podría suplantar la dirección de un servidor RMI en una colección. La operación requiere el marco ysoserial, que genera cadenas de objetos Java (gadgets) y los entrega de varias maneras. Por ejemplo, desde un servidor JRMP.
Por supuesto, usando el exploit de la frente en la frente, los participantes verán las firmas de IDS que desencadenan:
[Drop] [**] [1:10002700:3001] ATTACK [PTsecurity] Java Object Deserialization RCE POP Chain (ysoserial Jdk7u21) [**]
Jdk7u21 es solo una de las treinta cargas, y su elección depende de las bibliotecas utilizadas en el servicio vulnerable. La cadena de gadgets Jdk7u21 usa solo las clases estándar de la versión 7u21 del Kit de desarrollo de Java, y la cadena CommonsCollections1 contiene clases de las ampliamente utilizadas Apache Common Collections 3.1.
El atacante reemplaza la dirección del servidor RMI en la colección Solr con la suya, y luego inicia el servidor JRMP. Solr solicita un objeto en una dirección y recibe un objeto Java malicioso. Después de su deserialización, el código se ejecuta en el servidor.
La firma se dispara en una secuencia de clases en un objeto Java serializado. Se transmite desde la máquina del atacante y en el tráfico comienza así:

La solución a este problema fue simple. La firma se refiere explícitamente a Jdk7u21. Para evitarlo, tenías que probar otras cadenas de gadgets. Por ejemplo, una de CommonsCollections. No había firmas para otras cadenas en IDS. El participante recibirá un shell en el sistema y leerá la bandera. Cinco participantes completaron la tarea.
100.64.0.12 - SAMR
Una de las tareas más difíciles e interesantes de la competencia. Esta es una máquina Windows con un puerto 445 abierto. El indicador se divide en los nombres de dos usuarios del sistema, y para completar la tarea fue necesario obtener una lista de todos los usuarios en el nodo de Windows.
Por supuesto, MS17-010 y otros exploits no funcionaron en esta máquina. Enumerar usuarios podría, por ejemplo, scripts de
Nmap o el marco de
impacket :
$ python samrdump.py 100.64.0.12 Impacket v0.9.15 - Copyright 2002-2016 Core Security Technologies [*] Retrieving endpoint list from 100.64.0.12 [*] Trying protocol 445/SMB… Found domain(s): . SAMR . Builtin [*] Looking up users in domain SAMR [-] The NETBIOS connection with the remote host timed out. [*] No entries received.
Ambos escenarios realizan solicitudes DCERPC a la máquina en el puerto 445. Pero no todo es tan simple: algunos paquetes están bloqueados por IDS, y esta vez se activan dos firmas:
[**] [1:2001:2] SAMR DCERPC Bind [**]
[Drop] [**] [1:2002:2] SAMR EnumDomainUsers Request [**]
El primero detecta una conexión al servicio SAMR y solo marca la conexión TCP con un marcador. Y el segundo se desencadena por la solicitud EnumDomainUsers para el servicio SAMR. Este servicio tiene otras formas de obtener usuarios: QueryDisplayInfo, QueryDisplayInfo2, QueryDisplayInfo3. Todos ellos también fueron bloqueados por firmas.
El protocolo DCERPC y los servicios de Windows brindan enormes oportunidades para la administración remota del sitio. Este protocolo es utilizado por la mayoría de las herramientas conocidas, como PsExec o BloodHound. El servicio SAMR, es decir, el Protocolo remoto SAM, le permite trabajar con cuentas en el host, incluida la lista de usuarios.
Para solicitar EnumDomainUsers Impacket hace lo siguiente:

Se establece una conexión DCERPC al servicio SAMR a través de SMB, y todas las solicitudes adicionales van en el contexto de este servicio. Las firmas funcionan en el primer y último paquete de la captura de pantalla.
Di dos pistas sobre la tarea:
- Sus intentos provocan que IDS genere 2 alertas. Mira de cerca a la primera.
- ¿Qué comandos de conexión para este protocolo conoces?
Se trata del protocolo DCERPC y de cómo establecer conexiones. En la lista de PDU disponibles, los comandos Bind y Alter Context son responsables de conectar y cambiar el contexto, y el segundo permite cambiar el contexto actual sin romper la conexión.
Para resolver, tuvimos que reescribir la lógica del script samrdump:
- Haga Bind a otro servicio, por ejemplo con UUID 3919286a-b10c-11d0-9ba8-00c04fd92ef5.
- Use Alterar contexto para cambiar a SAMR.
- Enviar solicitud a EnumDomainUsers.
Los cambios se ajustan a tres líneas:
< dce.bind(samr.MSRPC_UUID_SAMR) --- > dce.bind(uuid.uuidtup_to_bin(("3919286a-b10c-11d0-9ba8-00c04fd92ef5", "0.0"))) > dce.alter_ctx(samr.MSRPC_UUID_SAMR) > dce._ctx = 1
El ganador del concurso propuso una solución alternativa @ psih1337. La consulta EnumDomainUsers devolvió una lista de usuarios no por nombre, sino por SID (ID de seguridad). SID no es un número aleatorio. Por ejemplo, la cuenta LocalSystem tiene SID S-1-5-18, y para usuarios creados manualmente, comienza en 1000.
Por lo tanto, al ordenar manualmente las semillas de 1000 a 2000, es muy probable que encuentre las cuentas deseadas en el sistema. Fueron encontrados bajo los sids 1008 y 1009.
La solución a esta tarea requirió una comprensión del protocolo DCERPC y experiencia en la investigación de infraestructuras de Windows. @ psih1337 fue el único que lo decidió.
100.64.0.13 - DNSCAT
En el puerto 80 hay una página web con un formulario para una dirección IP.

Si especifica su IP, UDP llega al puerto 53:
17:40:45.501553 IP 100.64.0.13.38730 > 100.64.0.187: 61936+ CNAME? dnscat.d2bc039ce800000000d6eae8eae3bf81fd84d1695f5888aba8dcec06d071.a73b3f0561ca4906d268214f4b70da1bdb50f75739ae0577139096732bf8.0d0a987ce23408bac15426a22e. (173) 17:40:45.501639 IP 100.64.0.187 > 100.64.0.13: ICMP 100.64.0.187 udp port domain unreachable, length 209 17:40:46.520457 IP 100.64.0.13.38730 > 100.64.0.187: 21842+ TXT? dnscat.7f4e039ce800000000d6eae8eae3bf81fd84d1695f5888aba8dcec06d071.a73b3f0561ca4906d268214f4b70da1bdb50f75739ae0577139096732bf8.0d0a987ce23408bac15426a22e. (173) 17:40:46.520546 IP 100.64.0.187 > 100.64.0.13: ICMP 100.64.0.187 udp port domain unreachable, length 209
Claramente, esto es DNSCAT, una herramienta para túneles DNS. Después de especificar la dirección IP en el formulario, un cliente DNSCAT intenta establecer una conexión con él. Si esto tiene éxito, entonces el servidor (es decir, el participante) recibirá un shell en la máquina competitiva y sacará la bandera.
Por supuesto, si solo elevamos el servidor DNSCAT e intentamos aceptar la conexión, fallaremos:
[Drop] [**] [1:4001:1] 'dnscat' string found in DNS response [**]
La firma IDS se activa en la línea dnscat en el tráfico de nuestro servidor; esto se indica claramente en el mensaje. Ofuscar o cifrar el tráfico tampoco funcionará.
Mirando el código del cliente, encontramos que los controles no son lo suficientemente estrictos. Es decir, la línea dnscat puede no aparecer en absoluto en la respuesta. Solo queda eliminarlo del código o reemplazarlo sobre la marcha con la utilidad NetSED. Reemplazar de inmediato es mucho más fácil, pero aún así le daré un parche para el código del servidor:
diff -r dnscat2/server/libs/dnser.rb dnscat2_bypass/server/libs/dnser.rb < segments << unpack("a#{len}") > segments << [unpack("a#{len}")[0].upcase] < name.split(/\./).each do |segment| > name.upcase.split(/\./).each do |segment| diff -r dnscat2/server/tunnel_drivers/driver_dns.rb dnscat2_bypass/server/tunnel_drivers/driver_dns.rb < response = (response == "" ? "dnscat" : ("dnscat." + response)) > response = (response == "" ? "dnsCat" : ("dnsCat." + response))
Había cinco soluciones para esta tarea en la competencia.
100.64.0.14 - POST
La bandera de este vehículo de concurso no fue recibida por nadie.

Vemos un formulario familiar con una dirección IP. Alguien nos ofrece participar en la prueba de un nuevo malware. Entre sus innovaciones está eludir IDS de una manera desconocida. Para el indicador, solo necesita enviarle el encabezado HTTP "Servidor: ng1nx" en respuesta. Estará caliente
Como se esperaba: recibimos una solicitud GET a nuestra IP y enviamos una respuesta que está bloqueada por IDS.
[Drop] [**] [1:5002:1] 'ng1nx' Server header found. Malware shall not pass [**]
Hay una pista:
A veces, las tareas que parecen difíciles son las más simples. Si nada parece vulnerable, ¿tal vez te estás perdiendo algo justo debajo de la nariz?
Algo vulnerable justo en frente de nuestra nariz es IDS. En la página de respuestas, puede encontrar que tenemos un ID de Suricata abierto.

El primer enlace en la consulta "Suricata IDS Bypass" conduce a
CVE-2018-6794 . Esta vulnerabilidad permite omitir la inspección de paquetes si se viola el curso normal de la comunicación TCP (protocolo de enlace TCP) y se envían datos antes de que se complete el proceso. Se ve así:
Client -> [SYN] [Seq=0 Ack=0] -> Evil Server
Descargue el exploit, cambie la línea a "ng1nx", apague los paquetes RST del núcleo y ejecútelos.
Como ya se mencionó, nadie recibió las banderas de esta máquina, aunque algunos participantes estaban cerca de una solución.
Conclusión
49 participantes se registraron en la competencia, 12 pasaron al menos una bandera. Es interesante que las tareas competitivas pueden tener varias soluciones a la vez, especialmente tareas con el protocolo SMB y DCERPC. ¿Quizás tienes tus propias ideas para completar algunas tareas?
Premios:
- 1er lugar: @ psih1337
- 2do lugar: @ webr0ck
- 3er lugar: @empty_jack
Estadísticas de respuesta de firma:

¡Gracias a todos los participantes! El año que viene habrá aún más tareas de diferentes niveles de dificultad.
Publicado por Kirill Shipulin, Tecnologías positivas