Squid Game CTF - Hc0n 2023
Tabla de contenido
Presentación #
Squid Game es un CTF creado para el congreso Hc0n 2023. La ambientación se ha basado en la serie de Netflix: El Juego del Calamar.
Las características de este CTF son las siguientes:
- Se trata de tres retos estilo Boot2Root (conseguir los máximos privilegios).
- Se utiliza el servicio web como vía de Acceso Inicial.
- Las tres máquinas han sido configuradas para evitar la ejecución de comandos y no disponen de salida a Internet.
- El objetivo es realizar una post-explotación a través de la webshell y conseguir escalar privilegios. No será necesario realizar ningúna explotación web adiccional, ya que los retos estan centrados en la post-explotación y por eso se facilita el acceso inicial.
- Las elevaciones de privilegios son bastante sencillas, no obstante, la dificultad reside en las condiciones que dificultan la explotación.
A continuación se mostrará la solución propuesta para cada uno de los retos utilizando Kraken, la herramienta que he desarrollado y he presentado en la Hc0n 2023.
Kraken, a modular multi-language webshell coded by @secu_x11
Dicho esto… ¡Comencemos!
Reto 1 - Red Light, Green Light #
- Nombre: “Red Light, Green Light”
- Sistema Operativo: Linux
- Tecnología Web: Apache + PHP
- URL: https://challenge-01.makemalware.com
Al visitar el enlace del primer reto nos encontramos con la siguiente web:
En el robots.txt
de la página podemos descubrir un endpoint no indexado: /upload.php
Despliegue de Webshell PHP #
Al visitar este endpoint, encontramos lo que parece ser una subida arbitraria de archivos:
Para confirmar la vulnerabilidad, se puede subir un agente de Kraken del tipo Standard y en lenguaje PHP.
Tras subirlo, la página nos devuelve la ruta remota donde se ha subido el archivo. Tras validar que este es accesible, se procede a generar un perfil de conexión para conectarnos al agente de Kraken.
Tras definir los campos del JSON como se ve anteriormente, podemos conectarnos al agente:
Reconocimiento del equipo #
Con el implante desplegado, y el cliente conectado, podemos comenzar con el reconocimiento local del equipo.
En primer lugar, se puede comprobar que no es posible ejecutar comandos del sistema a través de la propia webshell:
Esto se debe a que las funciones típicas de PHP para ejecutar comandos han sido deshabilitadas mediante la configuración de PHP (disabled_functions).
Es posible obtener el listado de las funciones deshabilitadas a través de Kraken utilizando el módulo webinfo
No obstante, esta configuración no nos impide movernos por el sistema de archivos utilizando funcionalidades nativas que el propio PHP nos aporta.
Si nos fijamos en el directorio /opt
, podemos encontrar una carpeta squid-control junto con varios archivos y directorios de interés.
Analizando el contenido de los archivos y la información de contexto podemos identificar una vulnerabilidad del tipo Wildcard Poisoning1 en el script /opt/squid-control/green-light.sh
Explotación de Wildcard Poisoning #
El Wildcard Poisoning se produce debido a que, el script, esta utilizando un “wildcard” (*
) como argumento del comando tar
(indicando que se deben comprimir todos los archivos del directorio /var/www/html/files
).
Y precisamente, el comando tar
contiene una serie de argumentos que pueden desembocar en una ejecución de código arbitrario2.
No obstante, para confirmar la elevación de privilegios, podemos observar la carpeta /opt/squid-control/tmp
donde podemos ver como, cada minuto, se crea un archivo con el formato: <fecha>.tar.gz
que contiene los archivos del directorio /var/www/html/files
.
Además, el propietario de estos archivos es el usuario root. Por tanto, se puede pensar que es posible que exista un cronjob que este ejecutando el script /opt/squid-control/green-light.sh
cada minuto.
Para confirmar esta teoría, se puede utilizar el módulo de Kraken pspy
/proc
. Al listar esta ruta, podemos descubrir una serie de subdirectorios con valores numéricos. Estos se corresponden con los PID existentes en la máquina, y se tratan de archivos virtuales que contienen la información de cada proceso.
Puedes encontrar más información acerca de este sistema de archivos aquí.3
El módulo obtiene el listado de procesos en cada intervalo (-i
), durante los segundos indicados (-d
). En este período detecta aquellos procesos que se inician, así como los que se detienen, y los muestra en un formato intuitivo:
De esta forma podemos confirmar la ejecución del script /opt/squid-control/green-light.sh
a través de un cronjob ejecutado como root (de otra forma no hubiera sido posible ya que no se pueden listar los cronjobs de otros usuarios sin privilegios).
Antes de proceder con la explotación, se listan los puertos en uso en la máquina víctima. Para esto podemos apoyarnos en el módulo
netstat que obtiene la información de red a partir de los archivos virtuales bajo /proc/net/
Gracias a este módulo podemos identificar la existencia de un posible servicio SSH escuchando en la dirección 127.0.0.1:22
.
Con la información recopilada podemos plantear el siguiente vector de elevación de privilegios:
- Se sube un script a la máquina que, cuando se ejecute, añada una clave pública SSH al archivo
/root/.ssh/authorized_keys
. Esto permitirá realizar una autenticación basada en clave pública4 como el usuario root.
#!/bin/bash
mkdir -p /root/.ssh/
echo -n "ssh-rsa AAAAB3...JMClw==" > /root/.ssh/authorized_keys
- Después, creamos los archivos que producen la explotación del Wildcard poisoning y ejecutan el script del paso anterior.
Acceso SSH vía HTTP Tunneling #
Pasados unos segundos, procederemos a subir una utilidad de tunelización que nos permitirá comunicarnos con los servicios internos de la máquina. Para este caso, yo utilizaré la herramienta pivotnacci.
A tool to make socks connections through HTTP agents
Subo el agente PHP al directorio /var/www/html/files
utilizando el módulo
upload de Kraken.
-d
) así como el tamaño de cada chunk (-c
). Y, en caso de interrumpirse/cortarse la transferencia, se puede reanudar especificando el último seek transmitido (-s
). Esta es una buena opción a la hora de subir archivos pesados.
Con la utilidad de tunelización desplegada, podemos usar la clave privada SSH para autenticarnos contra el servicio local de la máquina víctima y conseguir así una consola como root.
Finalmente, a través de esta consola, disponemos de todos los privilegios y podemos obtener la flag del reto.
Antes de finalizar borramos los archivos que hemos utilizado en la elevación de privilegios.
LD_PRELOAD y flag alternativa #
No obstante, el reto no concluye aquí. Se presenta la posibilidad de introducir una flag “alternativa” que se escapa de la vía principal del reto.
En caso de haber intentado evadir la configuración relacionada con las disabled_functions
, es posible que se haya intentado hacer mediante alguna herramienta como Chankro la cual es bien conocida en este tipo de post explotaciones.
Herramienta para evadir disable_functions y open_basedir
No obstante, en las funciones deshabilitadas se encuentran aquellas que nos permiten realizar la evasión con esta herramienta. Aunque, si observamos las variables del sistema definidas para nuestro usuario www-data
podemos descubrir un valor predefinido en la variable LD_PRELOAD
Esta variable apunta a una libreria situada en /usr/local/lib/falcon.so
. Utilizando el módulo
download de Kraken podemos descargarla.
En este punto, podríamos realizar ingeniería inversa y analizar el funcionamiento de la misma, aunque es posible recuperar la flag alternativa de los strings de la sección de datos de la libreria.
A pesar de haber obtenido la flag, voy a explicar el funcionamiento y el propósito que tiene esta librería:
En primer lugar, se trata de una adaptación del código de zap-args de TheHackersChoice.
Various tips & tricks
El código zap-args.c
es una utilidad enfocada a la evasión de defensas, que se centra en esconder los argumentos pasados a un comando o binario. Lo que hace es utilizar la variable LD_PRELOAD
para interceptar la llamada al main de la ejecución de tu comando y vacía la referencía a la matriz de argumentos que se le pasa. De esta forma, al hacer un ps
, el kernel no es capaz de recuperar los argumentos pasados al programa, ya que la referencia esta vacía, y simplemente muestra el binario en cuestión.
En mi caso, yo he utilizado la misma idea pero no para “ocultar” los argumentos, sino para interceptarlos como lo haría un EDR. De esta forma se pueden interceptar aquellos comandos ejecutados por el usuario www-data
y, en caso de llamar a una shell, bloquearlos.
El código de falcon.so
es el siguiente:
/*
* gcc -Wall -O2 -fpic -shared -o hook.so hook.c -ldl
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>
#include <pwd.h>
#include <sys/types.h>
typedef int (*pfi)(int, char **, char **);
static pfi real_main;
int check_args(int argc, char** argv)
{
if (argc < 1)
return 0;
// Checking for shell execution
if (strcmp(argv[0], "sh") == 0)
return 1;
else if (strcmp(argv[0], "bash") == 0)
return 1;
else if (strcmp(argv[0], "rbash") == 0)
return 1;
else if (strcmp(argv[0], "dash") == 0)
return 1;
return 0;
}
static int mymain(int argc, char** argv, char** env)
{
struct passwd *p = getpwuid(getuid());
if (strcmp(p->pw_name, "www-data") == 0)
{
if (check_args(argc, argv) == 1)
{
char *alt_flag = "squid-game{Byp4ssAllTh3Th1ngS!}";
printf("Nice try! But it's not this way. Although, here is your alternative fl4g: %s", alt_flag);
exit(0);
}
}
return real_main(argc, argv, env);
}
int __libc_start_main(pfi main, int argc,
char **ubp_av, void (*init) (void),
void (*fini)(void),
void (*rtld_fini)(void), void (*stack_end))
{
static int (*real___libc_start_main)() = NULL;
if (!real___libc_start_main)
{
char *error;
real___libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
exit(1);
}
}
real_main = main;
return real___libc_start_main(mymain, argc, ubp_av, init, fini, rtld_fini, stack_end);
}
Obviamente, es un insulto esperar que esto sirva como “bloqueo” ante alguien que ha evadido las defensas propuestas. No obstante, es una mera recompensa de cara a mostrar al jugador que, lo ha hecho bien, pero que no es el camino.
Y hasta aquí llega el primer reto.
Reto 2 - Dalgona Candy #
- Nombre: “Dalgona Candy”
- Sistema Operativo: Windows
- Tecnología Web: IIS + ASPX
- URL: https://challenge-02.makemalware.com
Accediendo a la url del reto podemos encontrarnos la siguiente vista:
Inspeccionando el código de la página descubrimos una ruta /upload.aspx
oculta:
Despliegue de Webshell ASPX #
Al visitarla podemos ver, de igual forma que en el primer reto, una subida arbitraria de archivos.
En este caso, procedemos a subir un un agente de Kraken como ASPX
Generamos el perfil de conexión especificando la ruta del nuevo agente desplegado:
Y finalmente nos conectamos a la webshell utilizando Kraken.
Reconocimiento local #
En primer lugar, se comprueba que hay un App Locker instalado en la máquina que nos impide ejecutar comandos con el Application Pool Identity actual (WINWS02\webusr
).
En este punto, podríamos comenzar a hacer un reconocimiento exhaustivo en busca de servicios vulnerables, programas en uso, archivos con credenciales, etc. Pero en este caso, la explotación será mucho más sencilla.
Primero comprobamos el contexto de nuestro usuario, así como sus privilegios. Utilizando el módulo whoami resulta bastante fácil.
Como se puede observar, se dispone del privilegio SeImpersonate
, del cual podemos abusar para conseguir elevar a SYSTEM.
Elevación de Privilegios con SeImpersonate Privilege #
Para hacer esto, voy a utilizar una versión modificada del programa BadPotato.
BadPotato utiliza el servicio de impresión de Windows (spoolss) para explotar una Autenticación Forzada5. Esta autenticación forzada se produce a través de la llamada RPC: RpcRemoteFindFirstPrinterChangeNotificationEx()
, que genera un objeto de notificación que monitoriza los cambios de un objeto de impresión. Esto se utiliza para forzar a que el servicio de impresión se conecte a una NamedPipe que nosotros hemos creado y robarle el token de acceso. Como el usuario que corre el servicio de impresión es la cuenta del sistema, podremos utilizar su token para elevar priviegios.
Windows 权限提升 BadPotato
En la modificación elimino toda la parte de la creación del proceso que utiliza BadPotato para ejecutar como SYSTEM.
Por otro lado, al eliminar el CloseHandle()
de la referencia el token duplicado, propicio a su filtración (leak). De esta forma, el token queda filtrado en mi propio proceso (w3wp.exe) y puedo utilizarlo posteriormente desde el propio contexto de la webshell.
Elevación de Privilegios + Persistencia
.
A través del módulo execute_assembly de Kraken, puedo cargar el NET Assembly de la versión modificada de BadPotato y conseguir el leak del token de SYSTEM.
Con el módulo set_token puedo utilizar la referencia del token para hacer efectiva la suplantación de la cuenta del sistema. Utilizando un token de impersonación derivado del filtrado, puedo conseguir que, todos los modulos que Kraken ejecute, lo hagan bajo el contexto de seguridad de SYSTEM:
Tras esto, se ha conseguido elevar privilegios y se dispone de una “pseudo-consola” como el usuario SYSTEM. Asi que, es posible leer la flag del escritorio del Administrador local de la máquina y completando el reto.
Extracción de la SAM, SECURITY y SYSTEM del registro #
No obstante, en un escenario más realista, no bastaría con demostrar que se disponen de privilegios. Sería necesario realizar algún tipo de post explotación para comprometer la máquina y/o obtener credenciales.
Para demostrar la posibilidad de realizar esta tarea con Kraken, se utilizará el módulo secretsdump que nos permitirá extraer la SAM, SECURITY y SYSTEM del registro de la máquina.
NtSaveKey()
guarde el contenido de la clave del registro en un archivo “en memoria”. De esta forma podemos acceder a su contenido, pero este no llega a escribirse en disco, por tanto podemos exfiltrarlo y sin necesidad de llegar a completar la transacción.
En el momento en el que el módulo escribe los archivos a nuestro equipo local, podemos usar la utilidad: secretsdump de Impacket para obtener las cuentas locales de la máquina.
Impacket is a collection of Python classes for working with network protocols.
Con la información obtenida en este proceso, es posible utilizarla para conseguir una sesión interactiva en la máquina comprometida (independiente de la webshell).
Y con esto, se cierra el segundo reto.
Reto 3 - The Glass Tile #
- Nombre: “The Glass Tile”
- Sistema Operativo: Windows
- Tecnología Web: IIS + ASPX
- URL: https://challenge-03.makemalware.com
Este reto esta pensado para demostrar el potencial del uso de los Tokens de Windows durante el proceso de post-explotación web. La idea surgió a partir de la investigación realizada por mi compañero Kurosh Dabag Escalante: One shell to HANDLE them all.6
Dicho esto, comenzamos visitando la url del reto:
De nuevo podemos ver en el código fuente algunas rutas ocultas:
Al visitar el endpoint /admin
encontramos una simple página estática. Parece ser que no tiene mucho más.
Despliegue de Webshell ASPX #
Por otro lado, si visitamos la ruta /upload.aspx
volvemos a encontrarnos con una subida arbitraria de archivos.
Así que volvemos a subir un agente ASPX de Kraken como en el reto anterior.
Generamos un perfil de conexión y, de nuevo, nos conectamos al agente.
Reconocimiento local y Leak de token #
Advertimos las mismas políticas del App Locker que impiden la ejecución de comandos:
No obstante, al listar los tokens existentes en nuestro proceso, descubrimos uno bajo el contexto de seguridad del usuario WINWS03\square
.
Al suplantar a dicho usuario podemos comprobar que se trata de un miembro del grupo de Administradores locales de la máquina, y que el token esta en integridad alta.
La explicación a esto es que, existe un Directorio Virtual configurado en el IIS. Este directorio virtual apunta a la ruta local: C:/Users/square/adminsite/
. Para que el Application Pool Identity pueda acceder a este directorio, necesita un par de credenciales válidas. Para este caso, se han configurado unas en ClearText del usuario WINWS03\square
.
El endpoint que gestiona este directorio virtual es /admin
, por tanto, cuando se accede a dicho endpoint, el IIS se autentica como el usuario WINWS03\square
para acceder, lo que produce la filtración de un token principal como este usuario.
Elevación de Privilegios con impersonaciones anidadas #
A través de la primera suplantación conseguimos elevar privilegios de WINWS03\webusr
a WINWS03\square
(admin local). No obstante, para conseguir el mayor número de privilegios en el equipo, es necesario escalar a SYSTEM.
Para ello, como se disponen de privilegios de administrador y se esta en integridad alta, se procede a buscar un proceso que corra como SYSTEM. Para ello usamos el módulo
ps de Kraken y, entre los distintos procesos, identificamos un candidato: winlogon.exe
Utilizando el módulo dup_token de Kraken, conseguimos duplicar el token del winlogon y obtener uno como SYSTEM en nuestro proceso.
Al utilizar ese token y suplantar a la cuenta del sistema, nos dirigimos al directorio donde se encuentra la flag C:/Users/Administrator/Desktop
y, podemos comprobar como al intentar leer la flag, obtenemos un error de “permiso denegado”.
Esto se debe a que, existe una ACL configurada en el archivo squid-flag.txt
para que sólo pueda ser accesible por su propietario, es decir, WINWS03\Administrator
.
Ante esta configuración, se plantea la posibilidad de suplantar al usuario WINWS03\Administrator
en cuestión. Para poder hacerlo, se revisa de nuevo el listado de procesos, y se encuentra uno prometedor:
El proceso con PID: 3132
, corresponde a un Procmon64, que se esta ejecutando bajo el directorio C:/Users/Administrator/Downloads/ProcessMonitor
, lo que signfica que es posible que dicho usuario haya lanzado el proceso en su logon session.
Se confirma la premisa a través del duplicado de su token, y de la suplantación haciendo uso del mismo. En este contexto, finalmente se puede acceder a la flag del reto:
Extracción de secretos a través del módulo de Administración de IIS #
Y, por último, para completar la post-explotación, al disponer de privilegios de Administrador e Integridad Alta, es posible extraer los secretos configurados en el IIS utilizando la libreria: Microsoft.Web.Administration
(utilizada para la administración del servidor web).
A través de esta funcionalidad, es posible recuperar las credenciales en plano configuradas para cualquier AppPool, VirtualDirectory o AppPoolIdentity. Para ello, basta con utilizar el módulo de Kraken dump_iis_secrets
Para desarrollar el módulo de dump_iis_secrets, utilicé la idea descrita por Grzegorz Tworek en uno de sus Tweets7 que habla acerca de la posibilidad de extraer estas credenciales utilizando el binario appcmd.exe
.
Conclusiones #
Como conclusión, se demuestra el potencial y la comodidad al utilizar Kraken como herramienta de post explotación web. Se han cubierto diferentes explotaciones en diferentes escenarios.
Finalmente puedes encontrar el código de los retos, así como los comandos utilizados, en el siguiente enlace.
O bien, puedes descargarte las OVAs de los retos de Mega.
¡Espero que os haya gustado, y nos vemos en el siguiente post!
-
Back To The Future: Unix Wildcards Gone Wild : https://www.exploit-db.com/papers/33930 ↩︎
-
Ejecución de código arbitrario utilizando /usr/bin/tar : https://gtfobins.github.io/gtfobins/tar/#shell ↩︎
-
El sistema de archivos /proc : https://tldp.org/pub/Linux/docs/ldp-archived/system-admin-guide/translations/es/html/ch04s07.html ↩︎
-
SSH Public Key Authentication : https://www.ssh.com/academy/ssh/public-key-authentication ↩︎
-
Forced Authentication : https://www.ired.team/offensive-security/initial-access/t1187-forced-authentication ↩︎
-
One shell to HANDLE them all : https://www.tarlogic.com/es/blog/abuso-handles-token/ ↩︎
-
0gtweet IIS Application Pool credential dumping : https://twitter.com/0gtweet/status/1588815661085917186 ↩︎