Day 19: Claus For Concern - Advent of Cyber 2025

xhetic

xhetic

@xhetic

TryHackMeAdventOfCyberSCADA
Day 19: Claus For Concern - Advent of Cyber 2025

📚 Esta publicación pertenece a las colecciones:

Day 19: Claus For Concern - Advent of Cyber 2025

Este writeup pertenece al evento Advent of Cyber 2025 de TryHackMe. Si quieres seguir toda la serie, consulta nuestra colección completa del Advent of Cyber 2025.

Hoy nos adentramos en el mundo de los sistemas de control industrial (ICS). El sistema de entrega de drones de TBFC está actuando de forma extraña. En lugar de regalos, los drones están cargando huevos de chocolate y decoraciones de Pascua.

Todo apunta a que el sistema SCADA (Supervisory Control and Data Acquisition), que actúa como el "sistema nervioso" de la operación, ha sido comprometido. Nuestra misión es interactuar directamente con el controlador lógico programable (PLC) para diagnosticar el problema y arreglarlo sin activar las trampas que King Malhare ha dejado.

Room: Claus For Concern
Dificultad: Medium


🏭 Initial Reconnaissance

Lo primero es entender a qué nos enfrentamos. Comenzamos con un escaneo rápido de los puertos más relevantes para este tipo de sistemas.

nmap -sV -p 22,80,502 MACHINE_IP

El resultado nos muestra tres servicios clave:

22/tcp   open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.11 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    Werkzeug httpd 3.1.3 (Python 3.12.3)
502/tcp  open  modbus  Modbus TCP
  • Port 80 (HTTP): Un servidor web, probablemente para monitoreo.
  • Port 502 (Modbus TCP): El protocolo estándar para comunicación industrial.

👁️ Visual Confirmation: The CCTV Feed

Antes de tocar nada, verificamos visualmente qué está ocurriendo en la planta. Accedemos al servidor web en el puerto 80.

CCTV Compromised

La imagen confirma el desastre: la línea de producción está configurada para "Pascua" en pleno diciembre y el estado del sistema marca "Compromised".


🔌 Modbus Reconnaissance

El puerto 502 nos indica que el sistema usa Modbus. Este protocolo no tiene autenticación por defecto, lo que nos permite conectarnos directamente.

Usaremos Python y la librería pymodbus para interactuar con el PLC. Primero, establecemos una conexión básica para verificar que tenemos acceso:

from pymodbus.client import ModbusTcpClient
 
# Connect to the PLC on port 502
client = ModbusTcpClient('MACHINE_IP', port=502)
 
# Establish connection
if client.connect():
    print("Connected to PLC successfully")
else:
    print("Connection failed")

Una vez conectados, podemos empezar a leer los registros del sistema tal y como nos va explicando la room para entender qué ha cambiado el atacante.


📜 Complete Reconnaissance Script

Para obtener una imagen completa del estado del sistema, usamos el script de la room que lee todos los registros (Holding Registers) y banderas (Coils) relevantes. Basándonos en la documentación encontrada, sabemos qué buscar:

  • HR0: Tipo de paquete.
  • HR4: Firma del sistema.
  • C11: Mecanismo de protección (Trampa).

Aquí está el script de reconocimiento completo:

#!/usr/bin/env python3
from pymodbus.client import ModbusTcpClient
 
PLC_IP = "MACHINE_IP"
PORT = 502
UNIT_ID = 1
 
# Connect to PLC
client = ModbusTcpClient(PLC_IP, port=PORT)
 
if not client.connect():
    print("Failed to connect to PLC")
    exit(1)
 
print("=" * 60)
print("TBFC Drone System - Reconnaissance Report")
print("=" * 60)
print()
 
# Read holding registers
print("HOLDING REGISTERS:")
print("-" * 60)
 
registers = client.read_holding_registers(address=0, count=5, slave=UNIT_ID)
if not registers.isError():
    hr0, hr1, hr2, hr3, hr4 = registers.registers
    
    print(f"HR0 (Package Type): {hr0}")
    print(f"  0=Christmas, 1=Eggs, 2=Baskets")
    print()
    
    print(f"HR1 (Delivery Zone): {hr1}")
    print(f"  1-9=Normal zones, 10=Ocean dump")
    print()
    
    print(f"HR4 (System Signature): {hr4}")
    if hr4 == 666:
        print(f"  WARNING: Eggsploit signature detected")
    print()
 
# Read coils
print("COILS (Boolean Flags):")
print("-" * 60)
 
coils = client.read_coils(address=10, count=6, slave=UNIT_ID)
if not coils.isError():
    c10, c11, c12, c13, c14, c15 = coils.bits[:6]
    
    print(f"C10 (Inventory Verification): {c10}")
    print(f"  Should be True")
    print()
    
    print(f"C11 (Protection/Override): {c11}")
    if c11:
        print(f"  ACTIVE - System monitoring for changes")
    print()
    
    print(f"C12 (Emergency Dump): {c12}")
    if c12:
        print(f"  CRITICAL: Dump protocol active")
    print()
    
    print(f"C13 (Audit Logging): {c13}")
    print(f"  Should be True")
    print()
    
    print(f"C14 (Christmas Restored): {c14}")
    print(f"  Auto-set when system is fixed")
    print()
    
    print(f"C15 (Self-Destruct Armed): {c15}")
    if c15:
        print(f"  DANGER: Countdown active")
    print()
 
print("=" * 60)
print("THREAT ASSESSMENT:")
print("=" * 60)
 
if hr4 == 666:
    print("Eggsploit framework detected")
if c11:
    print("Protection mechanism active - trap is set")
if hr0 == 1:
    print("Package type forced to eggs")
if not c10:
    print("Inventory verification disabled")
if not c13:
    print("Audit logging disabled")
 
print()
print("REMEDIATION REQUIRED")
print("=" * 60)
 
client.close()

Al ejecutarlo, confirmamos que HR0 está en 1 (Huevos) y, lo más peligroso, C11 está activo. Esto significa que hay una trampa: si intentamos cambiar el tipo de paquete sin desactivar la protección primero, se activará la autodestrucción.


🛡️ Safe Remediation

Para restaurar el sistema sin detonar la fábrica, debemos seguir un orden estricto:

  1. Desactivar la protección (C11).
  2. Cambiar el tipo de paquete a Regalos (HR0).
  3. Reactivar las verificaciones de seguridad (C10 y C13).

Este es el script final que realiza la remediación de forma segura y nos entrega la flag:

#!/usr/bin/env python3
from pymodbus.client import ModbusTcpClient
import time
 
PLC_IP = "MACHINE_IP"
PORT = 502
UNIT_ID = 1
 
def read_coil(client, address):
    result = client.read_coils(address=address, count=1, slave=UNIT_ID)
    if not result.isError():
        return result.bits[0]
    return None
 
def read_register(client, address):
    result = client.read_holding_registers(address=address, count=1, slave=UNIT_ID)
    if not result.isError():
        return result.registers[0]
    return None
 
# Connect to PLC
client = ModbusTcpClient(PLC_IP, port=PORT)
 
if not client.connect():
    print("Failed to connect to PLC")
    exit(1)
 
print("=" * 60)
print("TBFC Drone System - Christmas Restoration")
print("=" * 60)
print()
 
# Step 1: Check current state
print("Step 1: Verifying current system state...")
time.sleep(1)
 
package_type = read_register(client, 0)
protection = read_coil(client, 11)
armed = read_coil(client, 15)
 
print(f"  Package Type: {package_type} (1 = Eggs)")
print(f"  Protection Active: {protection}")
print(f"  Self-Destruct Armed: {armed}")
print()
 
# Step 2: Disable protection
print("Step 2: Disabling protection mechanism...")
time.sleep(1)
 
result = client.write_coil(11, False, slave=UNIT_ID)
if not result.isError():
    print("  Protection DISABLED")
    print("  Safe to proceed with changes")
else:
    print("  FAILED to disable protection")
    client.close()
    exit(1)
 
print()
time.sleep(1)
 
# Step 3: Change package type to Christmas
print("Step 3: Setting package type to Christmas presents...")
time.sleep(1)
 
result = client.write_register(0, 0, slave=UNIT_ID)
if not result.isError():
    print("  Package type changed to: Christmas Presents")
else:
    print("  FAILED to change package type")
 
print()
time.sleep(1)
 
# Step 4: Enable inventory verification
print("Step 4: Enabling inventory verification...")
time.sleep(1)
 
result = client.write_coil(10, True, slave=UNIT_ID)
if not result.isError():
    print("  Inventory verification ENABLED")
else:
    print("  FAILED to enable verification")
 
print()
time.sleep(1)
 
# Step 5: Enable audit logging
print("Step 5: Enabling audit logging...")
time.sleep(1)
 
result = client.write_coil(13, True, slave=UNIT_ID)
if not result.isError():
    print("  Audit logging ENABLED")
    print("  Future changes will be logged")
else:
    print("  FAILED to enable logging")
 
print()
time.sleep(2)
 
# Step 6: Verify restoration
print("Step 6: Verifying system restoration...")
time.sleep(1)
 
christmas_restored = read_coil(client, 14)
new_package_type = read_register(client, 0)
emergency_dump = read_coil(client, 12)
self_destruct = read_coil(client, 15)
 
print(f"  Package Type: {new_package_type} (0 = Christmas)")
print(f"  Christmas Restored: {christmas_restored}")
print(f"  Emergency Dump: {emergency_dump}")
print(f"  Self-Destruct Armed: {self_destruct}")
print()
 
if christmas_restored and new_package_type == 0 and not emergency_dump and not self_destruct:
    print("=" * 60)
    print("SUCCESS - CHRISTMAS IS SAVED")
    print("=" * 60)
    print()
    print("Christmas deliveries have been restored")
    print("The drones will now deliver presents, not eggs")
    print("Check the CCTV feed to see the results")
    print()
    
    # Read the flag from registers
    flag_result = client.read_holding_registers(address=20, count=12, slave=UNIT_ID)
    if not flag_result.isError():
        flag_bytes = []
        for reg in flag_result.registers:
            flag_bytes.append(reg >> 8)
            flag_bytes.append(reg & 0xFF)
        flag = ''.join(chr(b) for b in flag_bytes if b != 0)
        print(f"Flag: {flag}")
    
    print()
    print("=" * 60)
else:
    print("Restoration incomplete - check system state")
 
client.close()
print()
print("Disconnected from PLC")

Al ejecutar el script, el sistema se restaura correctamente y obtenemos la flag final.

CCTV Restored

Pregunta: What is the flag?

Respuesta: THM{eGgMas0V3r}


🏁 Conclusión

Este reto nos demuestra por qué la seguridad en entornos OT (Operational Technology) es crítica. Protocolos antiguos como Modbus, diseñados sin seguridad en mente, son extremadamente vulnerables si se exponen a la red sin las protecciones adecuadas.

Si te perdiste el reto de ofuscación de ayer, echa un vistazo al Día 18: The Egg Shell File.

Recuerda que puedes seguir toda la serie de retos en nuestra colección completa del Advent of Cyber 2025.

¡Nos vemos mañana para más hacking navideño! 🎄

~ Xhetic