
보안 권고: 인증되지 않은 메모리 누수로 인한 메모리 고갈 (TinyWeb)
할당된 CVE ID: CVE-2026-67183
TinyWeb는 각 요청을 파싱하는 동안 여러 객체를 할당하고 해제하지 않습니다. 요청 및 헤더 구조체에는 소멸자가 없으며, 응답이 전송된 후 이들을 삭제하는 코드도 없습니다. 워커 메모리는 모든 요청마다 증가하고 절대 줄어들지 않으므로, 지속적인 일반 요청 흐름은 워커를 메모리 고갈 상태로 만듭니다.
TnyWeb/0.0.8e48f15d (2018-11-20)부터 a381da2 (2023-11-22, 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:N서버의 수신 TCP 포트(제공된 구성에서는 9090)에 도달할 수 있고 적당한 지속 속도로 요청을 보낼 수 있는 인증되지 않은 원격 공격자. 자격 증명이나 사용자 상호 작용이 필요하지 않습니다. 요청은 정상적으로 구성될 수 있으며 특별한 페이로드가 필요하지 않습니다.
각 요청에 대해 HttpParser::execute()는 Url, HttpHeaders, 그리고 각 헤더 줄마다 하나의 HttpHeader를 할당합니다:
// src/tiny_http/http_parser.cc:1692
request->url = new Url;
// src/tiny_http/http_parser.cc:1709
request->headers = new HttpHeaders;
// src/tiny_http/http_parser.cc:1033-1040
HttpHeader* header = new HttpHeader;
return_val = parseHeader(stream, offset, len, header);
...
result->generals.push_back(header); // stored in a raw-pointer list
HttpRequest와 HttpHeaders는 소멸자가 없는 단순 구조체이므로, HttpRequest를 파괴해도 이들 중 어느 것도 해제되지 않습니다:
// src/tiny_http/http_parser.h:442
typedef struct HttpRequest {
...
Url* url;
HttpHeaders* headers;
HttpBody* body;
} HttpRequest;
// src/tiny_http/http_parser.h:279-304
typedef struct HttpHeaders {
...
std::list<HttpHeader*> generals; // raw pointers, never deleted
...
} HttpHeaders;
WebProtocol은 요청을 std::shared_ptr<HttpRequest> (src/tiny_http/http_protocol.h:49)에 보관합니다. 다음 요청이 이를 대체하면 기본 ~HttpRequest가 실행되어 url, headers, body, 그리고 generals의 모든 HttpHeader가 누수됩니다. 코드에서 유일한 delete request는 getDataFromProxy() (src/tiny_http/http_protocol.cc:194)에 있으며, 이 함수는 요청 경로에서 호출되지 않습니다. 메모리 풀의 요청별 응답 버퍼도 증가에 더해집니다.
제공된 구성으로 서버를 시작합니다(포트 9090에서 수신). 워커의 프로세스 ID를 기록합니다.
워커의 상주 메모리를 기록합니다:
grep VmRSS /proc/<worker_pid>/status
for i in $(seq 1 2000); do
curl -s -o /dev/null http://TARGET:9090/
done
VmRSS를 다시 읽습니다. 증가했으며 이후로 떨어지지 않습니다. 대표적인 실행 결과:VmRSS before: 3704 kB
after 500 requests: 4788 kB
after 1000 requests: 22068 kB
after 1500 requests: 41652 kB
after 2000 requests: 59956 kB
증가는 단조적이며 요청당 대략 20~28kB로, 고원(plateau) 현상이 없습니다. 배치를 반복하면 워커가 메모리 고갈로 종료될 때까지 계속 상승합니다.
인증되지 않은 공격자는 지속적인 요청 스트림으로 워커의 메모리를 고갈시키고 메모리 부족 상태를 강제하여 서비스 거부를 유발할 수 있습니다. 일반 트래픽도 시간이 지나며 누수되므로, 공격자 없이도 이 상태가 발생할 수 있습니다.
HttpRequest와 HttpHeaders에 url, headers, body, 그리고 generals의 모든 HttpHeader를 해제하는 소멸자를 추가하거나, 스마트 포인터로 보관하여 자동으로 해제되도록 하십시오. 또한 응답이 전송된 후 요청별 메모리 풀 버퍼도 해제하십시오.