MyFirstBlog
Datos del reto
| Campo | Valor |
|---|---|
| CTF | Batman's Kitchen CTF |
| Reto | MyFirstBlog |
| Categoría | Web |
| Flag | bkctf{k3ys_in_th3_l0ck5} |
Descripción del reto
Era un blog personal simple. Había una entrada "borrada" que seguía siendo accesible y un endpoint de adjuntos que recibía nombres de archivo por parámetro. La resolución salía de combinar esas dos pistas.
Reconocimiento
En la portada había enlaces a /blog/1, /blog/2 y /blog/4, así que la ruta que faltaba era /blog/3. En esa ruta aparecía una entrada marcada como eliminada, pero el HTML seguía enseñando información útil.
Había dos detalles importantes.
- Un comentario que decía que para los documentos de la carpeta
otherhacía falta una API key. - Un
<object>que cargaba un PDF con esa clave en la URL.
/attachment?file=resume.pdf&apiKey=906392d25b3bd7d3af491799f89f6620
Además, el sitio ya usaba /attachment?file=... para servir recursos estáticos, así que el parámetro file era el primero que tenía sentido probar para un path traversal.
Análisis
Sin la API key, intentar cosas como file=/flag.txt o file=../../../flag.txt devolvía 403. Pero una vez encontrada la clave, el comportamiento cambiaba. El servidor sí permitía acceder a archivos de la carpeta other y el valor de file no estaba bien restringido.
Si el backend resolvía rutas partiendo de other/<archivo> sin limpiar correctamente los ../, entonces se podía salir del directorio esperado y acabar leyendo /flag.txt.
La entrada "borrada" no solo dejaba ver contenido antiguo, sino también la clave necesaria para abrir el endpoint vulnerable.
Resolución
Con la API key expuesta, solo hacía falta pedir el endpoint así.
curl -s "http://34.186.135.240:30000/attachment?file=../../../flag.txt&apiKey=906392d25b3bd7d3af491799f89f6620"
La respuesta devolvía directamente el contenido de la flag.
Flag
bkctf{k3ys_in_th3_l0ck5}