
보안 권고: 인증되지 않은 NULL 포인터 역참조로 서버 충돌 발생 (TinyWeb)
할당된 CVE ID: CVE-2026-67184
TinyWeb이 요청 라인을 파싱하지 못하면 오류를 반환하지만 요청의 URL 포인터를 NULL로 남겨둡니다. 호출자는 오류를 무시하고 요청을 응답 빌더에 전달하며, 응답 빌더는 해당 NULL 포인터를 역참조하여 워커를 크래시시킵니다. 잘못된 형식의 요청 몇 개만으로도 전체 서버가 다운되며, 복구되지 않습니다.
TnyWeb/0.0.8e48f15d(2018-11-20)부터 master의 최신 커밋인 a381da2(2023-11-22)까지입니다.CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N서버의 수신 대기 TCP 포트(배포 구성에서는 9090)에 도달할 수 있는 인증되지 않은 원격 공격자. 자격 증명이나 사용자 상호작용은 필요하지 않습니다.
HttpParser::execute()는 요청 라인이 성공적으로 파싱된 후에만 URL 객체를 할당합니다. 잘못된 형식의 HTTP 버전은 버전 검사를 실패하게 하고 error 라벨로 점프하여, 할당이 실행되기 전에 -1을 반환합니다:
// 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;
HttpRequest는 std::make_shared<HttpRequest>()로 생성되며, 이는 값을 초기화하므로 할당이 건너뛰어지면 url은 NULL로 유지됩니다.
WebProtocol::dataReceived()는 반환 값을 기록하지만 조건 없이 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()는 valid_requ == false를 받지만 이를 전혀 확인하지 않고 NULL URL 포인터를 역참조합니다:
// 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
워커 프로세스는 이 접근에서 크래시합니다. 워커는 서빙 상태로 재시작되지 않으므로, 워커가 모두 사라지면 서버는 응답을 중단합니다.
배포된 구성으로 서버를 시작합니다(포트 9090에서 수신 대기).
정상 요청에 응답하는지 확인합니다:
curl http://TARGET:9090/
XTTP/1.1은 요청 라인이 이미 요청 모드로 전환된 후 버전 검사에서 실패합니다:printf 'GET / XTTP/1.1\r\n\r\n' | nc TARGET 9090
워커에 연결된 디버거는 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
인증되지 않은 공격자는 몇 개의 짧은 요청으로 서버 워커를 크래시시키고, 요청을 계속 재전송하여 서비스를 오프라인 상태로 유지할 수 있습니다. 이는 서비스 거부(DoS)입니다.
dataReceived()에서 valid_requ가 false인 경우 buildResponse()를 호출하는 대신 오류 응답을 생성하고 반환합니다. buildResponse()에서는 req->url을 사용하기 전에 NULL인지 확인합니다. 파싱이 실패할 수 있기 전에 URL 객체를 할당하는 것도 이 허점을 막을 수 있습니다.