
An implementation of the Fusee Gelee exploit (CVE-2018-6242) for the Nintendo Switch, along with a custom payload.
Nintendo Switch के लिए Fusee Gelee एक्सप्लॉइट (CVE-2018-6242) का एक कार्यान्वयन, जो मार्च 2018 में Kate Temkin / ReSwitched द्वारा खोजी गई कमजोरी पर आधारित है।
USB रिकवरी मोड (RCM) में एक Tegra X1 डिवाइस पर एक मनमाना पेलोड (जैसे hekate) लॉन्च करता है, बूट ROM के सिग्नेचर सत्यापन को पूरी तरह से बायपास करते हुए।
RCM (रिकवरी मोड) एक USB-आधारित रिकवरी प्रोटोकॉल है जो Tegra X1 के बूट ROM में बनाया गया है। NVIDIA ने इसे डिज़ाइन किया ताकि वे डिवाइस पर छोटे प्रोग्राम ("एप्लेट") लोड कर सकें निदान या मरम्मत के लिए — उदाहरण के लिए जब Switch अपने स्टोरेज पर वैध बूटलोडर नहीं ढूंढ पाता।
Nintendo Switch पर, RCM में बूट करते समय दाएं joycon रेल पर पिन 1 और 10 को ब्रिज करके प्रवेश किया जाता है। सामान्य संचालन में, केवल NVIDIA ही RCM का उपयोग कर सकता है — सभी कमांड्स को NVIDIA की RSA प्राइवेट कुंजी से हस्ताक्षरित होना चाहिए, और बूट ROM कुछ भी निष्पादित करने से पहले हस्ताक्षर सत्यापित करता है।
एक्सप्लॉइट दो स्वतंत्र प्रोटोकॉल परतों में काम करता है जो IRAM (ऑन-चिप RAM) साझा करती हैं:
USB परत (मानक, EP0): प्रत्येक USB डिवाइस में एक नियंत्रण एंडपॉइंट (EP0) होता है जो GET_STATUS, GET_DESCRIPTOR, SET_ADDRESS जैसे मानक अनुरोधों को संभालता है। बूट ROM USB 2.0 विनिर्देश के अनुसार इन्हें लागू करता है। EP0 अंतर्निहित है — यह डिवाइस के एंडपॉइंट डिस्क्रिप्टर में दिखाई नहीं देता।
RCM परत (NVIDIA स्वामित्व, EP1): NVIDIA RCM कमांड और पेलोड स्थानांतरित करने के लिए एक बल्क एंडपॉइंट (EP1) परिभाषित करता है। EP1 डिवाइस डिस्क्रिप्टर में दो दिशाओं के रूप में दिखाई देता है:
0x01 = OUT (होस्ट डिवाइस को डेटा भेजता है)0x81 = IN (डिवाइस होस्ट को डेटा भेजता है)EP1 पर भेजा गया डेटा इस प्रकार संरचित है:
[680-बाइट RCM कमांड हेडर] [पेलोड बाइट्स]
680-बाइट हेडर rcm_msg_t स्ट्रक्ट है — एक NVIDIA-स्वामित्व संरचना जिसमें RSA मॉड्यूलस/सिग्नेचर, ECID, ऑपकोड और अन्य फ़ील्ड शामिल हैं। यह आकार Tegra X1 बूट ROM को रिवर्स इंजीनियर करके निर्धारित किया गया था (देखें
q3k का IDA डेटाबेस)।
NVIDIA का ओपन-सोर्स tegrarcm केवल 644 बाइट्स (Tegra124) तक दस्तावेज़ित करता है; T210 वैरिएंट 36 बाइट्स बड़ा है।
बूट ROM के EP0 नियंत्रण अनुरोध हैंडलर में ENDPOINT प्राप्तकर्ताओं के लिए इसके GET_STATUS कार्यान्वयन में एक बग है। Temkin के श्वेतपत्र से:
// बग: size_to_tx = sizeof(status) होना चाहिए, अर्थात 2 बाइट्स
size_to_tx = length_read; // wLength के माध्यम से हमलावर-नियंत्रित, 65535 तक
data_to_tx = &status; // स्टैक पर एक uint16_t
memcpy(dma_buffer, data_to_tx, size_to_tx);
memcpy &status (एक स्टैक वेरिएबल जो 0x40010000 के ठीक नीचे है) से पढ़ता है और DMA बफर ( 0x40009000 पर) में लिखता है। एक बड़े आकार के साथ:
&status से आगे, पूरे स्टैक के माध्यम से, और 0x40010000+ पर हमलावर-नियंत्रित पेलोड क्षेत्र में पढ़ता है (EP1 बल्क राइट्स के माध्यम से वहां रखा गया)।स्रोत डेटा में एक "स्टैक स्प्रे" (दोहराया गया 0x40010000) शामिल है, जो स्टैक के रिटर्न एड्रेस पर लिखा जाता है। जब हैंडलर वापस लौटता है, निष्पादन 0x40010000 पर कूदता है — जहां हमने इंटरमेज़ो नामक एक छोटा रीलोकेटर स्टब रखा है।
यह सब RCM प्राप्त लूप के दौरान (handle_control_requests के अंदर) होता है, बूट ROM द्वारा हस्ताक्षरों को मान्य करने से पहले। RCM प्रोटोकॉल डिलीवरी तंत्र है; USB नियंत्रण हैंडलर ट्रिगर है।
0x40005000 +------------------+
| DMA बफर LOW | USB नियंत्रक यहां विषम पैकेट लिखता है
0x40009000 +------------------+
| DMA बफर HIGH | USB नियंत्रक यहां सम पैकेट लिखता है
+------------------+
| निष्पादन स्टैक | DMA बफर की ओर नीचे बढ़ता है
0x40010000 +------------------+ <-- स्टैक यहां समाप्त / पेलोड यहां शुरू
| intermezzo | छोटा रीलोकेटर स्टब (124 बाइट्स)
0x40010E40 +------------------+
| उपयोगकर्ता पेलोड भाग1 | पहला ~16KB उपयोगकर्ता पेलोड
0x40014E40 +------------------+
| स्टैक स्प्रे | 0x40010000 दोहराया (8640 बाइट्स)
0x40017000 +------------------+
| उपयोगकर्ता पेलोड भाग2 | शेष उपयोगकर्ता पेलोड
+------------------+
उपयोगकर्ता पेलोड स्टैक स्प्रे के आसपास विभाजित होता है क्योंकि स्प्रे को इस प्रकार स्थित होना चाहिए कि ओवरफ्लो इसे स्टैक के रिटर्न एड्रेस पर कॉपी करे। Intermezzo दो हिस्सों को 0x40010000 पर एक सन्निहित ब्लॉक में पुनः जोड़ता है और उस पर कूदता है।
0x0955:0x7321) द्वारा डिवाइस ढूंढें0x40010000+ पर कॉपी करता है, हमारे intermezzo, उपयोगकर्ता पेलोड और स्टैक स्प्रे को रखता है0x40009000) को लक्षित करता हैwLength=0x7000 के साथ एक GET_STATUS नियंत्रण अनुरोध भेजें — यह कमजोर memcpy को ट्रिगर करता है, स्टैक स्प्रे रिटर्न एड्रेस को अधिलेखित करता है, और हैंडलर intermezzo में वापस लौटता हैpip install pyusb
python launcher.py
USB के माध्यम से कनेक्टेड RCM मोड में एक Switch की आवश्यकता है। macOS पर, आपको
brew install libusb की आवश्यकता हो सकती है।
अपने पेलोड बाइनरी को binaries/payload.bin पर रखें। शामिल intermezzo.bin
पेलोड रीलोकेशन को संभालता है और इसे बदलने की आवश्यकता नहीं होनी चाहिए।
launcher.py — एक्सप्लॉइट स्क्रिप्टbinaries/intermezzo.bin — रीलोकेटर स्टब (124 बाइट्स), विभाजित पेलोड को पुनः जोड़ता हैbinaries/payload.bin — निष्पादित करने के लिए उपयोगकर्ता पेलोड (जैसे hekate)