
CVE-2021-21380 को कवर करने वाली एक CodeQL कार्यशाला
इस कार्यशाला में हम CVE-2021-21380 द्वारा प्रलेखित XWiki प्लेटफ़ॉर्म के रेटिंग घटक में SQL इंजेक्शन खोजने के लिए वाक्यात्मक और अर्थगत तर्क का उपयोग करेंगे।
यदि संभव हो तो कृपया कार्यशाला से पहले यह अनुभाग पूरा करें।
Visual Studio Code स्थापित करें।
Visual Studio Code के लिए CodeQL एक्सटेंशन स्थापित करें।
आपको CodeQL CLI स्थापित करने की आवश्यकता नहीं है: एक्सटेंशन आपके लिए यह संभाल लेगा।
इस रिपॉजिटरी को क्लोन करें:
git clone https://github.com/advanced-security/codeql-workshop-cve-2021-21380.git
xwiki-platform-CVE-2021-21380.zip फ़ाइल पर राइट-क्लिक करें और CodeQL: Set Current Database कमांड चुनें।Cmd/Ctrl+Shift+P) से, CodeQL: Install Pack Dependencies कमांड खोजें और चलाएँ।github टाइप करें।cve-2021-21380-exercises, cve-2021-21380-exercises-tests, cve-2021-21380-solutions, और cve-2021-21380-solutions-tests के आगे वाले बॉक्स चेक करें।कार्यशाला को कई अभ्यासों में विभाजित किया गया है जो Java के लिए QL भाषा समर्थन का परिचय देते हैं और ज्ञात SQL इंजेक्शन खोजने के लिए एक अंतिम क्वेरी के साथ समाप्त होते हैं। इन अभ्यासों में आप सीखेंगे:
इस कार्यशाला में हम XWiki Platform के रेटिंग्स API घटक में ज्ञात SQL इंजेक्शन भेद्यताओं की तलाश करेंगे। ऐसी भेद्यताएँ अनुप्रयोगों में तब हो सकती हैं जब किसी बाहरी उपयोगकर्ता द्वारा नियंत्रित जानकारी उस अनुप्रयोग कोड तक पहुँचती है जो असुरक्षित रूप से SQL क्वेरी बनाता है और उसे निष्पादित करता है।
इस कार्यशाला में चर्चित ज्ञात SQL इंजेक्शन की समीक्षा GitHub Advisory Database में GHSA-79rg-7mv3-jrr5 पर की गई है। SQL इंजेक्शन और संभावित प्रकारों को खोजने के लिए, हम निम्नलिखित उप-समस्याओं को हल करेंगे:
पहले कुछ अभ्यासों में हम अमूर्त सिंटैक्स ट्री (AST) का उपयोग करके वाक्यात्मक जानकारी के बारे में तर्क करेंगे, ताकि पहचान सकें:
क्वेरी exercise1.ql को पूरा करके प्रोग्राम में getAverageRating नाम वाली सभी विधियाँ और उसके घोषित प्रकार का पता लगाएँ।
java मॉड्यूल प्रोग्राम में विधियों के बारे में तर्क करने के लिए एक वर्ग Method प्रदान करता है।Method एक विधि के नाम के बारे में तर्क करने के लिए सदस्य विधेय getName और hasName प्रदान करता है।Method विधि को घोषित करने वाले प्रकार के बारे में तर्क करने के लिए सदस्य getDeclaringType प्रदान करता है।समाधान क्वेरी exercise1.ql में पाया जा सकता है।
अभ्यास 1 का समाधान विधियों की एक सूची लौटाता है। उनमें से कुछ RatingsManager नामक एक इंटरफ़ेस में परिभाषित हैं और कुछ वर्गों AbstractRatingsManager और RatingsScriptService में परिभाषित हैं।
क्वेरी और XWiki घटक दस्तावेज़ीकरण द्वारा लौटाई गई जानकारी से हम अनुमान लगा सकते हैं कि:
Role से एनोटेट किया जाता है, और एक कार्यान्वयन होता है जिसे Component से एनोटेट किया जाता है।ScriptService का विस्तार करता है, स्क्रिप्टिंग के माध्यम से विकि पृष्ठों के लिए सुलभ बनाया जाता है।क्वेरी exercise2.ql को पूरा करके Component एनोटेशन से एनोटेट किए गए सभी वर्गों का पता लगाएँ। ध्यान दें कि एनोटेशन के प्रकार का पूर्ण योग्य नाम org.xwiki.component.annotation.Component है।
this का उपयोग करके एक्सेस किया जा सकता है।Class वर्ग संबंधित एनोटेशन प्राप्त करने के लिए एक विधि getAnAnnotation प्रदान करता है।Annotation वर्ग अपने प्रकार के बारे में तर्क करने के लिए सदस्य विधेय getType प्रदान करता है।Type वर्ग किसी प्रकार के नाम के बारे में तर्क करने के लिए सदस्य विधेय getName और hasName प्रदान करता है।RefType वर्ग (जो वर्गों और इंटरफ़ेस का प्रतिनिधित्व करता है) रेफ्टाइप के पूर्ण योग्य नाम के बारे में तर्क करने के लिए सदस्य विधेय getQualifiedName और hasQualifiedName प्रदान करता है।समाधान क्वेरी exercise2.ql में पाया जा सकता है।
क्वेरी excercise3.ql को पूरा करके ScriptService इंटरफ़ेस को लागू करने वाले सभी घटकों का पता लगाएँ।
Class प्रकार सदस्य विधेय getASuperType प्रदान करता है ताकि किसी वर्ग के सुपर प्रकारों (अर्थात वे प्रकार जिन्हें वह extends या implements करता है) के बारे में तर्क किया जा सके।समाधान क्वेरी exercise3.ql में पाया जा सकता है।
इस बिंदु पर हमने वाक्यात्मक रूप से उन विधियों की पहचान कर ली है जिन्हें एक उपयोगकर्ता कॉल कर सकता है और जिनके पैरामीटर हम कार्यशाला में आगे अविश्वसनीय डेटा के स्रोत मानेंगे।
अगले अभ्यास में हम संभावित सिंक की जाँच और पहचान करेंगे। अभ्यास 1 के परिणामों से हम अनुमान लगा सकते हैं कि एक कार्यान्वयन विधि getAverageRatingFromQuery को कॉल करता है। समान क्वेरी का उपयोग करके हम getAverageRatingFromQuery के घोषित प्रकार पा सकते हैं, जो हमें यह स्थापित करने की अनुमति देता है कि वर्ग AbstractRatingsManager में कार्यान्वयन एक SQL स्टेटमेंट बनाता है जो search विधि को पारित किया जाता है।
search विधि एक निर्भरता में कार्यान्वित की गई है और इस प्रकार इसका कार्यान्वयन उपलब्ध नहीं है। अगले अभ्यासों में हम इस search विधि कॉल और इसके घोषित प्रकार की पहचान करने के लिए उपलब्ध प्रकार की जानकारी का उपयोग करेंगे।
क्वेरी exercise4.ql को पूरा करके search विधि के सभी विधि कॉल खोजें और उसके घोषित प्रकार की पहचान करें।
MethodCall प्रकार हमें विधि कॉल के बारे में तर्क करने का साधन प्रदान करता है।MethodAcccess प्रकार विधि कॉल के लक्ष्य के बारे में तर्क करने के लिए सदस्य विधेय getMethod प्रदान करता है।समाधान क्वेरी exercise4.ql में पाया जा सकता है।
क्वेरी exercise5.ql को पूरा करके इंटरफ़ेस XWikiStorageInterface (योग्य नाम com.xpn.xwiki.store.XWikiStoreInterface के साथ) द्वारा घोषित विधियों के सभी विधि कॉल खोजें।
यह बताने के लिए कीवर्ड instanceof का उपयोग किया जा सकता है कि कोई मान किसी प्रकार द्वारा दर्शाए गए मानों के सेट से संबंधित है।
उदाहरण के लिए, इंटरफ़ेस विधियों के सभी कॉल की पहचान करने के लिए:
import java
from MethodCall ma
where ma.getMethod.getDeclaringType() instanceof Interface
select ma
समाधान क्वेरी exercise5.ql में पाया जा सकता है।
इस बिंदु पर हमने QL का उपयोग करके संभावित स्रोतों और सिंक का वाक्यात्मक रूप से वर्णन किया है। यह निर्धारित करने के लिए कि कार्यक्रम में इन बिंदुओं के बीच सूचना प्रवाहित होती है या नहीं, हम टेंट ट्रैकिंग का उपयोग करके कार्यक्रम का अर्थगत विश्लेषण करेंगे।
हमारे द्वारा समर्थित भाषाओं की मानक लाइब्रेरीज़ दो डेटा प्रवाह तंत्र प्रदान करती हैं:
DataFlow मान संरक्षित सूचना प्रवाह का समर्थन करता है।TaintTracking मान संशोधित होने पर भी सूचना प्रवाह का समर्थन करता है।बाद वाला रुचिकर है, क्योंकि SQL इंजेक्शन जैसी इंजेक्शन भेद्यता में अविश्वसनीय डेटा का एक बड़े स्टेटमेंट का हिस्सा बनना सामान्य है जिस पर कार्रवाई की जाती है।
इस कार्यशाला में हम एक मौजूदा SQL इंजेक्शन टेंट ट्रैकिंग कॉन्फ़िगरेशन का पुन: उपयोग करेंगे और SQL इंजेक्शन खोजने के लिए इसे अपने मॉडल किए गए स्रोतों और सिंक के साथ विस्तारित करेंगे। यह समझने के लिए कि हम कॉन्फ़िगरेशन का विस्तार कैसे कर सकते हैं, हम नीचे दिए गए कॉन्फ़िगरेशन की परिभाषा को देखकर शुरू करते हैं।
class QueryInjectionFlowConfig extends TaintTracking::Configuration {
QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or
node.getType() instanceof BoxedType or
node.getType() instanceof NumberType
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
any(AdditionalQueryInjectionTaintStep s).step(node1, node2)
}
}
कॉन्फ़िगरेशन द्वारा उन प्रोग्राम स्थानों की पहचान करने के लिए उपयोग किए जाने वाले isSource और isSink विधेय दोनों ही कीवर्ड instanceof का उपयोग करते हैं जिसे हमने पहले देखा है। RemoteFlowSource और QueryInjectionSink दोनों वर्ग abstract वर्ग हैं। यह एक सामान्य पैटर्न है जिसका सामना आप मानक लाइब्रेरीज़ में करेंगे और यह पैटर्न हमें RemoteFlowSource और QueryInjectionSink वर्गों द्वारा दर्शाए गए मानों के सेट का विस्तार करने की अनुमति देता है।
एक QL class जो एक abstract class का विस्तार करता है, सुपर क्लास द्वारा दर्शाए गए मानों के सेट को परिशोधित नहीं करता, बल्कि उपवर्ग द्वारा दर्शाए गए मानों को सुपरक्लास में जोड़ता है।
अगले अभ्यासों में हम इन उपवर्गों को लागू करेंगे और अपनी अंतिम क्वेरी का निर्माण करेंगे।
अभ्यास 3 में पहचाने गए घटक वर्गों की सार्वजनिक विधियों के पैरामीटर के साथ RemoteFlowSource के मान सेट का विस्तार करने के लिए क्वेरी exercise6.ql को पूरा करें।
यह बताने के लिए कीवर्ड instanceof का उपयोग किया जा सकता है कि कोई मान किसी प्रकार द्वारा दर्शाए गए मानों के सेट से संबंधित है।
उदाहरण के लिए, इंटरफ़ेस विधियों के सभी कॉल की पहचान करने के लिए:
import java
from MethodCall ma
where ma.getMethod.getDeclaringType() instanceof Interface
select ma
समाधान क्वेरी exercise6.ql में पाया जा सकता है।
अभ्यास 5 में पहचाने गए स्टोरेज इंटरफ़ेस की विधियों के कॉल के तर्कों के साथ QueryInjectionSink के मान सेट का विस्तार करने के लिए क्वेरी exercise7.ql को पूरा करें।
exists सूत्र अस्थायी चर के परिचय की अनुमति देता है जिसके बारे में exists के दायरे में तर्क किया जा सकता है।
निम्नलिखित उदाहरण विधियों के सेट को केवल उन विधियों तक कम करने के लिए exists अभिव्यक्ति का उपयोग करता है जिन्हें कॉल किया जाता है।
from Method m
where m.hasName("foo") and exists(MethodCall ma | ma.getMethod() = m)
select m
MethodCall वर्ग विधि एक्सेस के क्वालिफ़ायर के बारे में तर्क करने के लिए सदस्य विधेय getQualifer प्रदान करता है।
समाधान क्वेरी exercise7.ql में पाया जा सकता है।
क्वेरी exercise8.ql को पूरा करके पिछले अभ्यासों के अपने समाधानों को एक अंतिम समाधान में संयोजित करें।
समाधान क्वेरी exercise8.ql में पाया जा सकता है।
XWikiStoreInterface के प्रत्यक्ष उपयोग तक सीमित रखा। सिंक का विस्तार करें ताकि इंटरफ़ेस के कार्यान्वयन के प्रत्यक्ष उपयोग शामिल हों। Class वर्ग सदस्य विधेय extendsOrImplements प्रदान करता है और Method वर्ग सदस्य विधेय overridesOrInstantiates प्रदान करता है जो सहायक हो सकते हैं।