
Aviso de Segurança: Desreferência de ponteiro NULL não autenticada derruba o servidor (TinyWeb)
ID de CVE atribuído: CVE-2026-67184
Quando o TinyWeb falha ao analisar uma linha de requisição, ele retorna um erro, mas deixa o ponteiro de URL da requisição definido como NULL. O chamador ignora o erro e passa a requisição para o construtor de resposta, que desreferencia esse ponteiro NULL e derruba o worker. Algumas requisições malformadas derrubam todo o servidor, e ele não se recupera.
TnyWeb/0.0.8e48f15d (2018-11-20), onde este parser e o caminho de resposta foram introduzidos, até a381da2 (2023-11-22, o mais recente em 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:NUm atacante remoto não autenticado que possa alcançar a porta TCP de escuta do servidor (9090 na configuração fornecida). Nenhuma credencial ou interação do usuário é necessária.
HttpParser::execute() aloca o objeto URL somente depois que a linha de requisição é analisada com sucesso. Uma versão HTTP malformada faz a verificação de versão falhar e saltar para o rótulo de erro, que retorna -1 antes que a alocação seja executada:
// 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;
O HttpRequest é criado com std::make_shared<HttpRequest>(), que o inicializa por valor; portanto, url permanece NULL quando a alocação é ignorada.
WebProtocol::dataReceived() registra o valor de retorno, mas mesmo assim chama 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() recebe valid_requ == false, mas nunca o verifica e desreferencia o ponteiro de 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
O processo worker é derrubado nesse acesso. Ele não é reiniciado em um estado operacional; portanto, uma vez que os workers caem, o servidor para de responder.
Inicie o servidor com a configuração fornecida (escutando na porta 9090).
Confirme que ele responde a uma requisição normal:
curl http://TARGET:9090/
XTTP/1.1 falha na verificação de versão depois que a linha de requisição já assumiu o modo de requisição:printf 'GET / XTTP/1.1\r\n\r\n' | nc TARGET 9090
Um depurador anexado a um worker mostra a queda na desreferência de 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
Um atacante não autenticado pode derrubar os workers do servidor com algumas requisições curtas e manter o serviço offline reenviando-as. Isso é uma negação de serviço.
Em dataReceived(), quando valid_requ for false, construa uma resposta de erro e retorne em vez de chamar buildResponse(). Em buildResponse(), verifique se req->url é NULL antes de usá-lo. Alocar o objeto URL antes que o parse possa falhar também fecharia a lacuna.