HEAD 요청은 몸통이 없다는 규칙을 깜빡한 대가 — OpenResty 요청 스머글링

HEAD 요청은 몸통이 없다는 규칙을 깜빡한 대가 — OpenResty 요청 스머글링

분류: Bugbounty · 웹·서버 · 요청스머글링(Request Smuggling) · CVE-2024-33452 [정보성]

덱. 연구자가 사내 침투 테스트 도중 우연히 발견한 결함이 OpenResty의 lua-nginx-module 전반에 영향을 주는 HTTP 요청 스머글링으로 이어졌습니다. 원인은 아주 단순한 규칙 하나 — “HEAD 요청에는 원래 처리할 몸통(body)이 없다” — 를 코드 한 곳이 깜빡한 것이었습니다.

리드

HTTP 요청 스머글링은 서로 다른 두 서버(프록시와 백엔드처럼)가 같은 요청을 서로 다르게 해석할 때 생깁니다. 이 “해석의 불일치”라는 근본 구조는 늘 같지만, 그 불일치를 만드는 구체적인 원인은 매번 다릅니다. 이번 사례는 HEAD 요청이라는, 평소 거의 신경 쓰지 않는 메서드 하나가 그 원인이었습니다.

핵심 사실 요약

  • 연구자는 OpenResty의 lua-nginx-module v0.10.26 이하 버전에서 HTTP 요청 스머글링 취약점을 발견해 공개했습니다. 이 문제는 2024년 1월 벤더에 신고됐고, 같은 해 3월 패치됐으며, 4월에 CVE-2024-33452로 등록됐습니다.
  • 원인은 HTTP/1.1 규격상 HEAD 요청은 응답 본문이 없어야 하므로 요청 자체에도 몸통을 붙이지 않는 것이 관례인데, lua-nginx-module이 이 관례를 따르는 요청 처리 흐름을 놓쳐, HEAD 요청에 몸통이 딸려오면 그 몸통을 별개의 새 요청으로 잘못 파싱했다는 데 있습니다. 다른 대부분의 프록시는 HEAD 요청의 본문 부분을 그대로 하나의 요청 안에 포함된 것으로 처리하는데, 이 모듈만 다르게 해석하면서 프록시 체인 사이에 해석 불일치가 생겼습니다.
  • 근본원인은 소스코드 파일 src/ngx_http_lua_util.c 내부의 파이프라인 처리 로직에 있다고 원문은 설명합니다. 정상적으로는 요청 본문을 건너뛰고 다음 요청의 시작 위치로 커서를 옮기는 처리가 있어야 하는데, 현재 요청 메서드가 HEAD일 경우 이 처리 이전에 함수가 먼저 반환돼 버려, 본문이 그대로 다음 요청으로 취급된다는 것입니다.
  • 이 결함은 lua-nginx-module 위에 구축된 여러 API 게이트웨이(Kong Gateway, Apache APISIX 등)에도 그대로 영향을 줬다고 밝혀졌습니다. 특히 이런 게이트웨이가 앞단에 별도 프록시(Nginx, Cloudflare 등)를 두고 **연결을 유지(keep-alive)**하는 구성일 때 위험이 커집니다.
  • 원문이 제시한 공격 시나리오는 세 가지입니다. (1) 몸통에 악성 스크립트를 실은 HEAD 요청으로 다음 사용자에게 XSS 응답이 전달되게 하는 것, (2) /admin 같은 경로를 차단하는 전면 프록시(Cloudflare 류)를 HEAD 요청 몸통에 숨긴 요청으로 우회하는 것, (3) 응답 큐를 어긋나게 만들어 다른 사용자에게 갈 응답을 가로채는 것입니다.

대응방안

  1. 근본. lua-nginx-module을 벤더가 배포한 패치 버전 이상으로 업데이트합니다. Kong Gateway·Apache APISIX 등 이 모듈 위에 구축된 게이트웨이를 쓰고 있다면 해당 벤더의 후속 패치 여부도 함께 확인합니다.
  2. 차선. 프록시 체인 구성 시 앞단 프록시와 백엔드 사이의 연결 재사용(keep-alive) 정책을 점검하고, 가능하면 신뢰 경계가 다른 프록시 사이에서는 연결을 요청 단위로 분리하는 것이 완화에 도움이 됩니다.
  3. 탐지 관점. Content-Length가 붙은 HEAD 요청 자체가 이례적인 트래픽이므로, 이런 패턴을 로그·WAF 규칙으로 감시하는 것이 신호가 됩니다.

짧은 논평

이 취약점의 근본 구조는 요청 스머글링 클래스에서 반복적으로 나오는 “두 파서가 같은 바이트열을 다르게 읽는다”는 패턴 그대로입니다. 다만 이번 사례가 알려주는 것은, 그 불일치가 꼭 복잡한 인코딩 트릭에서만 나오는 게 아니라 “이 메서드는 본문이 없다”는 아주 기본적인 HTTP 규약 하나를 처리 흐름 한 군데에서 놓치는 것만으로도 발생할 수 있다는 점입니다. 프록시 체인이 늘어날수록 이런 미세한 처리 차이가 누적된 공격 표면이 되고, 그 체인 중 한 곳만 다르게 동작해도 전체 신뢰 관계가 무너질 수 있습니다.

References / 참고자료

  1. Benasin (FrogSec Research), “OpenResty/lua-nginx-module v0.10.26 HTTP Request Smuggling in HEAD requests” — 이 글이 재구성한 원 분석. 근본원인 코드 위치·공격 시나리오·공개 타임라인을 다룸. https://www.benasin.space/2025/03/18/OpenResty-lua-nginx-module-v0-10-26-HTTP-Request-Smuggling-in-HEAD-requests/

이 글은 위 원 분석을 우리 관점에서 다시 쓰고 짧은 논평을 더한 정보성 초안입니다. 특정 문장·PoC 요청을 그대로 옮기지 않았으며, 작동하는 페이로드는 싣지 않았습니다. ⚠️미확인 표시가 없는 항목도 발행 전 독립 팩트체크에서 재확인됩니다.