[하루한줄] CVE-2025-6442 : Ruby WEBrick의 HTTP Smuggling로 인한 Request 조작

URL

Target

  • WEBrick ≤ 1.8.1

Explain

background

WEBrick은 간편하게 HTTP 웹 서버를 구현할 수 있는 Ruby 라이브러리입니다. HTTP 및 HTTPS 모두 지원 가능하며 Proxy, Virtual-Host 서버로 활용이 가능하며 몇 가지 인증 방식 또한 적용할 수 있어 Ruby on Rails 및 Pardino 프레임워크를 이용한 개발 시 테스트 서버 구성 시 자주 활용됩니다.

# Source - https://stackoverflow.com/a
# Posted by pmagunia
# Retrieved 2025-11-28, License - CC BY-SA 3.0

require 'webrick'

server = WEBrick::HTTPServer.new(:Port => 80,
                             :SSLEnable => false,
                             :DocumentRoot => '/var/www/myapp',
                             :ServerAlias => 'myapp.example.com')

server.mount_proc '/' do |req, res|
  res.body = 'Hello, world!'
end

trap 'INT' do server.shutdown end

server.start

# 이후 터미널에서 `ruby <filename>.rb` 실행 시 접근 가능
# $ curl http://127.0.0.1
# Hello, world!%

CVE-2025-6442의 타임라인은 다음과 같습니다:

  • 2023.09.13 — Vendor에 취약점 제보 (당시 ZDI-CAN-21876으로 식별)
  • 2024.06.26 — WEBrick github에서 RFC 9110 내용을 위반하는 코드 패턴에 관한 이슈 생성 (이슈 번호 #137)
  • 2024.07.02 — 지적된 사항의 패치 및 1.8.2 버전에서 merge
  • 2025.06.26 — 취약점 정보 공개

root cause

해당 취약점의 경우 대상 서버가 특정 조건을 만족하는 HTTP 프록시 뒤에 배치된 경우 익스플로잇이 가능하며 발생 원인으로는 HTTP 헤더의 종료 문자를 파싱하는 과정에서 일관되지 않은 결과를 나타내는 것으로 설명되었습니다.

연관된 커밋 내역을 확인하면 주요 변경은 lib/webrick/httprequest.rb 파일과 lib/webrick/httputils.rb 파일에서 진행된 점을 알 수 있습니다. 두 파일의 변경 내역은 아래와 같습니다:

lib/webrick/httprequest.rb

      @request_time = Time.now
---   if /^(\S+)\s+(\S++)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line
+++   if /^(\S+) (\S++)(?: HTTP\/(\d+\.\d+))?\r\n/mo =~ @request_line
        @request_method = $1
        @unparsed_uri   = $2
        @http_version   = HTTPVersion.new($3 ? $3 : "0.9")
@@ -471,7 +471,7 @@ def read_request_line(socket)
    def read_header(socket)
      if socket
        while line = read_line(socket)
---       break if /\A(#{CRLF}|#{LF})\z/om =~ line
+++       break if /\A#{CRLF}\z/om =~ line
          if (@request_bytes += line.bytesize) > MAX_HEADER_LENGTH
            raise HTTPStatus::RequestEntityTooLarge, 'headers too large'
          end

lib/webrick/httputils.rb

      field = nil
      raw.each_line{|line|
        case line
---     when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):(.*?)\z/om
---       field, value = $1, $2.strip
+++     when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):([^\r\n\0]*?)\r\n\z/om
+++       field, value = $1, $2
          field.downcase!
          header[field] = HEADER_CLASSES[field].new unless header.has_key?(field)
          header[field] << value
---     when /^\s+(.*?)/om
---       value = line.strip
+++     when /^\s+([^\r\n\0]*?)\r\n/om
          unless field
            raise HTTPStatus::BadRequest, "bad header '#{line}'."
          end
+++       value = line
+++       value.lstrip!
+++       value.slice!(-2..-1)
          header[field][-1] << " " << value
        else
          raise HTTPStatus::BadRequest, "bad header '#{line}'."

변경된 내용을 확인하면 크게 정규식 패턴 수정과 CR 또는 LF 문자가 단독으로 사용될 수 있던 패턴을 CR-LF 형태를 강제하도록 패치가 진행된 것을 알 수 있습니다.

정상적인 구조의 HTTP 패킷의 경우 헤더 영역과 바디 영역의 구분을 위해 CR-LF 문자를 두 번 반복하여 사용하도록 요구하지만, 기존의 코드는 이를 정상적으로 해석하지 못할 가능성이 존재하였습니다.

takeaway

해당 취약점 외에도 자료 조사 과정에서 WEBrick에서 발생하는 HTTP Smuggling 취약점이 다수 존재하였음을 확인할 수 있었습니다. 따라서 가급적 최신 보안 패치가 적용된 버전을 사용하되 불가능한 경우 취약한 설정 등을 제거하는 방향으로 대응이 필요할 것으로 보입니다.

Reference