Lógica doble valor (400)
La página tiene un buscador con un filtro de seguridad muy estricto. Parece que no te deja buscar nada sensible. Sin embargo, hay un pequeño fallo de lógica en la forma en que el servidor procesa tu petición. ¿Puedes engañar al filtro y hacer que busque la flag sin que se dé cuenta?
La flag está en /flag.txt
Descargar contenedor Docker del desafío
Análisis inicial
Se nos presenta una página web con un campo de búsqueda.

Según el mensaje, la flag está en /flag.txt. Voy a ver qué pasa si intento buscar ese archivo directamente.
Recibimos el siguiente error:
Consulta inválida. Has usado una palabra prohibida.
Examinando el código fuente
Vamos a ver la estructura del servidor.
.
├── app.js
├── docker-compose.yml
├── Dockerfile
├── flag.txt
├── index.html
└── style.css
El archivo app.js es el servidor web. Vamos a ver su contenido.
La siguiente función comprueba si en el texto pasado como parámetro hay alguna palabra prohibida:
const is_safe = (input) => {
const forbidden_words = ['flag', 'etc', 'passwd', '..', '/', '%'];
for (const word of forbidden_words) {
if (input.includes(word)) {
console.log(`Petición bloqueada por la palabra clave: ${word}`);
return false;
}
}
return true;
};
¿Desde dónde se llama a esta función? Revisando el código, vemos que se utiliza en la ruta /search para filtrar las consultas de búsqueda:
app.get('/search', (req, res) => {
const search_query = req.query.q;
if (!search_query || search_query.length === 0) {
return res.status(400).send("No se proporcionó una consulta de búsqueda.");
}
if (!is_safe(search_query)) {
return res.status(403).send("Consulta inválida. Has usado una palabra prohibida.");
}
const all_queries = req.query.q;
if (Array.isArray(all_queries) && all_queries.length > 1) {
const file_path = all_queries.join("");
try {
const content = fs.readFileSync(file_path, 'utf8');
return res.status(200).send(`Contenido encontrado: <br><br> ${content}`);
} catch (error) {
console.log(error);
return res.status(404).send("Archivo no encontrado.");
}
} else {
return res.send(`Búsqueda: "${search_query}"`);
}
});
Aquí vemos que si la consulta de búsqueda es un array con más de un elemento, el servidor une todos los elementos para formar una ruta de archivo y luego intenta leer ese archivo. Sin embargo, el filtro de seguridad solo se aplica a la consulta de búsqueda original y no a la ruta del archivo resultante. Esto significa que podemos aprovechar esta lógica para acceder a archivos restringidos.
Explotación
Para explotar esta vulnerabilidad, podemos enviar una consulta de búsqueda que contenga múltiples elementos, donde uno de ellos sea un valor seguro y el otro sea la ruta del archivo que queremos leer. Por ejemplo, podríamos enviar la siguiente consulta:
/search?q=/fla&q=g.txt
Esto debería permitirnos eludir el filtro de seguridad y acceder al contenido de /flag.txt:
ikerlan{el_filtro_no_ve_doble}