~/blog/2025-11-30-writeup-metared-ez-pickle.md
[writeup]Writeup MetaRed CTF 2025 — EZ Pickle
Descripción del reto
El challenge nos entregaba un Flask muy compacto que recibía un parámetro data por POST, lo decodificaba en base64 y lo pasaba directamente a pickle.loads(). La descripción decía: “Solo te dejé un input. ¿Qué tan malo puede ser?”. Bastante malo, como veremos.
| |
Análisis inicial
pickle.loads() con input controlado por el usuario es una vulnerabilidad de manual: cuando Python deserializa un objeto, puede invocar __reduce__, lo que abre la puerta a ejecución arbitraria.
Solución
Construimos un payload que ejecuta cat /flag.txt y nos devuelve el resultado en la respuesta. Por simplicidad, redirigimos la salida a /tmp/out y la leemos con un segundo request a otro endpoint vulnerable de path traversal:
| |
Al ejecutar el script obtenemos la flag.
Flag
Conclusiones
Este fue un reto perfecto para iniciar al equipo júnior: combina un vector clásico (pickle insecure deserialization) con una segunda vulnerabilidad menor (path traversal en static/). En producción, nunca uses pickle con input no confiable. Alternativas seguras: json, msgpack o pydantic con validación estricta.
Recursos recomendados: OWASP Insecure Deserialization, Python pickle documentation — Warning.