
Aviso de seguridad: desreferencia de puntero NULL no autenticada provoca un bloqueo del servidor (TinyWeb)
ID de CVE asignado: CVE-2026-67184
Cuando TinyWeb no puede analizar una línea de solicitud, devuelve un error pero deja el puntero URL de la solicitud establecido en NULL. El llamador ignora el error y pasa la solicitud al constructor de respuestas, que desreferencia ese puntero NULL y bloquea el worker. Unas pocas solicitudes malformadas derriban todo el servidor, y este no se recupera.
TnyWeb/0.0.8e48f15d (2018-11-20), donde se introdujeron este analizador y la ruta de respuesta, hasta a381da2 (2023-11-22, el más reciente en master).CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NUn atacante remoto no autenticado que pueda alcanzar el puerto TCP de escucha del servidor (9090 en la configuración distribuida). No se requieren credenciales ni interacción del usuario.
HttpParser::execute() asigna el objeto URL solo después de que la línea de solicitud se haya analizado correctamente. Una versión HTTP malformada hace que la comprobación de versión falle y salte a la etiqueta de error, que devuelve -1 antes de que se ejecute la asignación:
// src/tiny_http/http_parser.cc:1401 (the "H" of "HTTP" is expected here)
checkOrGoError((ch == 'H')); // false -> goto error
// src/tiny_http/http_parser.cc:1692 (skipped by the goto above)
request->url = new Url;
// src/tiny_http/http_parser.cc:1750-1753
error:
LOG(Debug) << "http request content is invalid\n";
return -1;
El HttpRequest se crea con std::make_shared<HttpRequest>(), que lo inicializa por valor, por lo que url permanece NULL cuando se omite la asignación.
WebProtocol::dataReceived() registra el valor de retorno pero llama a buildResponse() de todos modos:
// src/tiny_http/http_protocol.cc:57-61
valid = m_nParser.execute(data.c_str(), begin, data.size(), m_pRequest.get());
valid_requ = (valid == -1) ? false : true;
// src/tiny_http/http_protocol.cc:75
m_nResponser.buildResponse(m_pRequest.get(), valid_requ, m_pResponse.get());
buildResponse() recibe valid_requ == false pero nunca lo comprueba, y desreferencia el puntero URL NULL:
// src/tiny_http/http_responser.cc:66
Url* url = req->url; // NULL
// src/tiny_http/http_responser.cc:83
if (url->field_set & (1 << HTTP_UF_PATH)) { // SIGSEGV
El proceso worker se bloquea en este acceso. No se reinicia a un estado de servicio, por lo que una vez que los workers desaparecen, el servidor deja de responder.
Inicia el servidor con la configuración distribuida (escuchando en el puerto 9090).
Confirma que responde a una solicitud normal:
curl http://TARGET:9090/
XTTP/1.1 falla la comprobación de versión después de que la línea de solicitud ya haya pasado al modo de solicitud:printf 'GET / XTTP/1.1\r\n\r\n' | nc TARGET 9090
Un depurador adjunto a un worker muestra el bloqueo en la desreferencia NULL:
#0 HttpBuilder::buildResponse (valid_requ=false) at src/tiny_http/http_responser.cc:83
#1 WebProtocol::dataReceived (data="GET / XTTP/1.1\r\n...") at src/tiny_http/http_protocol.cc:75
Un atacante no autenticado puede bloquear los workers del servidor con unas pocas solicitudes cortas y mantener el servicio fuera de línea reenviándolas. Esto es una denegación de servicio.
En dataReceived(), cuando valid_requ sea falso, construir una respuesta de error y retornar en lugar de llamar a buildResponse(). En buildResponse(), comprobar si req->url es NULL antes de usarlo. Asignar el objeto URL antes de que el análisis pueda fallar también cerraría la brecha.