
Avviso di sicurezza: la dereferenziazione di un puntatore NULL non autenticata provoca il crash del server (TinyWeb)
ID CVE assegnato: CVE-2026-67184
Quando TinyWeb non riesce a analizzare una riga di richiesta, restituisce un errore ma lascia il puntatore all'URL della richiesta impostato su NULL. Il chiamante ignora l'errore e passa la richiesta al costruttore della risposta, che dereferenzia quel puntatore NULL e causa il crash del worker. Poche richieste malformate mettono a terra l'intero server, che non si riprende.
TnyWeb/0.0.8e48f15d (2018-11-20), in cui sono stati introdotti questo parser e il percorso di risposta, fino a a381da2 (2023-11-22, ultimo su 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 attaccante remoto non autenticato che può raggiungere la porta TCP di ascolto del server (9090 nella configurazione fornita). Non sono richieste credenziali o interazione con l'utente.
HttpParser::execute() alloca l'oggetto URL solo dopo che la riga di richiesta è stata analizzata con successo. Una versione HTTP malformata fa fallire il controllo della versione e salta all'etichetta di errore, che restituisce -1 prima che l'allocazione venga eseguita:
// src/tiny_http/http_parser.cc:1401 (qui ci si aspetta la "H" di "HTTP")
checkOrGoError((ch == 'H')); // false -> goto error
// src/tiny_http/http_parser.cc:1692 (saltato dal goto precedente)
request->url = new Url;
// src/tiny_http/http_parser.cc:1750-1753
error:
LOG(Debug) << "http request content is invalid\n";
return -1;
HttpRequest viene creato con std::make_shared<HttpRequest>(), che lo inizializza per valore, quindi url rimane NULL quando l'allocazione viene saltata.
WebProtocol::dataReceived() registra il valore di ritorno ma chiama comunque buildResponse():
// 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() riceve valid_requ == false ma non lo controlla mai e dereferenzia il puntatore 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
Il processo worker va in crash su questo accesso. Non viene riavviato in uno stato operativo, quindi una volta che i worker sono terminati il server smette di rispondere.
Avviare il server con la configurazione fornita (in ascolto sulla porta 9090).
Verificare che risponda a una richiesta normale:
curl http://TARGET:9090/
XTTP/1.1 fallisce il controllo della versione dopo che la riga di richiesta si è già impegnata nella modalità di richiesta:printf 'GET / XTTP/1.1\r\n\r\n' | nc TARGET 9090
Un debugger collegato a un worker mostra il crash alla dereferenziazione del 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 attaccante non autenticato può mandare in crash i worker del server con poche brevi richieste e mantenere il servizio offline rinviandole. Si tratta di una denial of service.
In dataReceived(), quando valid_requ è false, costruire una risposta di errore e restituire il controllo invece di chiamare buildResponse(). In buildResponse(), controllare che req->url non sia NULL prima di usarlo. Anche allocare l'oggetto URL prima che l'analisi possa fallire chiuderebbe il varco.