
CVE-2021-35942 के बारे में एक बुनियादी विश्लेषण। Django में SQL इंजेक्शन।
Django एक ओपन-सोर्स वेब एप्लिकेशन फ्रेमवर्क है, जिसे Python में लिखा गया है और MVC (Model - View - Controller) मॉडल के आधार पर बनाया गया है। प्रारंभ में इसे Lawrence प्रकाशन समूह के स्वामित्व वाली समाचार सामग्री वेबसाइटों, CMS (सामग्री प्रबंधन प्रणाली) सॉफ़्टवेयर के प्रबंधन के लिए बनाया गया था।
Django संस्करण 3.1.x -> 3.1.13 और संस्करण 3.2.x -> 3.2.5 में SQL इंजेक्शन भेद्यता मौजूद है।
इस भेद्यता का कारण यह है कि QuerySet.order_by() पर उपयोगकर्ता-नियंत्रित इनपुट डेटा को फ़िल्टर करने का कार्य SQL इंजेक्शन हमलों से बचाव के लिए पर्याप्त नहीं है। इस भेद्यता का फायदा उठाकर हमलावर अनधिकृत कार्य कर सकते हैं, जिससे संवेदनशील डेटा का रिसाव हो सकता है।
| CVE - ID | CVE-2021-35042 |
|---|---|
| गंभीरता | 9.8 - CRITICAL |
| CWE - ID | CWE-89: SQL कमांड में विशेष तत्वों का अनुचित निष्प्रभावीकरण ('SQL इंजेक्शन') |
| भेद्यता प्रकाशन तिथि | 1/7/2021 |
| प्रभावित सॉफ़्टवेयर | 3.1.x < 3.1.13, 3.2.x < 3.2.5 |
| प्रमाणीकरण आवश्यक | आवश्यक नहीं |
Django में, डेटाबेस में तालिका बनाना और फ़ील्ड परिभाषित करना models.py फ़ाइल में एक model क्लास घोषित करके किया जाता है। इस उदाहरण में, हम Wolf नामक एक तालिका और name नामक एक फ़ील्ड घोषित करते हैं।


Django में निर्मित ORM फ्रेमवर्क का उपयोग डेटाबेस के साथ संचालन के लिए किया जाता है, और क्वेरी का परिणाम एक संग्रह होता है, यह संग्रह एक QuerySet है।
order_by(fields)
डिफ़ॉल्ट रूप से, order_by() एक QuerySet लौटाता है जिसे Model के Meta में ordering विकल्प में निर्दिष्ट क्रम के अनुसार क्रमबद्ध किया जाता है। हम order_by() विधि का उपयोग करके प्रत्येक क्वेरी में order_by की स्थिति को ओवरराइड कर सकते हैं।
उदाहरण
wolves = Wolf.objects.order_by('-name', 'id')
उपरोक्त क्वेरी का परिणाम name फ़ील्ड के अनुसार घटते क्रम में, फिर id के अनुसार बढ़ते क्रम में क्रमबद्ध किया जाएगा। name फ़ील्ड नाम के आगे ऋण चिह्न इंगित करता है कि परिणाम घटते क्रम में क्रमबद्ध हैं।
निम्न उदाहरण उपयोगकर्ता से प्राप्त फ़ील्ड के अनुसार लौटाए गए परिणाम को क्रमबद्ध करेगा, यदि कोई मान पारित नहीं किया गया है तो
idफ़ील्ड के अनुसार क्रमबद्ध किया जाएगा।
परिणाम

संस्करण 3.1 और 3.2 में, Django order_by क्वेरी में तालिका नाम के साथ क्वेरी विधि को संयोजित करने की अनुमति देता है। यह भी इस भेद्यता का मुख्य कारण है।
तालिका नाम पारित करने से हमें सामान्य फ़ील्ड नाम पारित करने के समान परिणाम मिलता है
cve202135042_wolf तालिका का नाम है
सबसे पहले एप्लिकेशन सीधे order_by() फ़ंक्शन को कॉल करता है, order_by() फ़ंक्शन को संसाधित करने वाला कोड यहां परिभाषित है:
django/db/models/query.py

order_by() फ़ंक्शन दो कार्य करता है
- order_by() द्वारा वर्तमान में कॉल किए जा रहे सभी तरीकों को हटा देता है और डिफ़ॉल्ट पैरामीटर को हटा देता है जब order_by एक अलग मान प्राप्त करता है।
- पैरामीटर को order_by में पारित करता है।
add_ordering()फ़ंक्शन यह करता है
def add_ordering(self, *ordering):
"""
Add items from the 'ordering' sequence to the query's "order by"
clause. These items are either field names (not column names) --
possibly with a direction prefix ('-' or '?') -- or OrderBy
expressions.
If 'ordering' is empty, clear all ordering from the query.
"""
errors = []
for item in ordering:
if isinstance(item, str):
if '.' in item:
warnings.warn(
'Passing column raw column aliases to order_by() is '
'deprecated. Wrap %r in a RawSQL expression before '
'passing it to order_by().' % item,
category=RemovedInDjango40Warning,
stacklevel=3,
)
continue
if item == '?':
continue
if item.startswith('-'):
item = item[1:]
if item in self.annotations:
continue
if self.extra and item in self.extra:
continue
# names_to_path() validates the lookup. A descriptive
# FieldError will be raise if it's not.
self.names_to_path(item.split(LOOKUP_SEP), self.model._meta)
elif not hasattr(item, 'resolve_expression'):
errors.append(item)
if getattr(item, 'contains_aggregate', False):
raise FieldError(
'Using an aggregate in order_by() without also including '
'it in annotate() is not allowed: %s' % item
)
if errors:
raise FieldError('Invalid order_by arguments: %s' % errors)
if ordering:
self.order_by += ordering
else:
self.default_ordering = False
add_ordering() में पारित पैरामीटर एक सरणी है।
उदाहरण के लिए जब पैरामीटर इस प्रकार पारित किया जाता है:
wolves = Wolf.objects.order_by( 'name' , 'id' )तब, एप्लिकेशन इसे डेटाबेस में निम्नलिखित क्वेरी में परिवर्तित करेगा:
SELECT "cve202135042_wolf"."id", "cve202135042_wolf"."name" FROM "cve202135042_wolf" ORDER BY "cve202135042_wolf"."name" ASC, "cve202135042_wolf"."id" ASC
जब पारित किया जाता है, add_ordering फ़ंक्शन सरणी में प्रत्येक तत्व की जांच करेगा, यदि यह एक string है, तो निम्नलिखित 5 मामलों की जांच की जाएगी:
if '.' in item:यह जांचता है कि क्या यह एक कॉलम नाम वाली क्वेरी है और क्या उस कॉलम में SQL स्टेटमेंट में निर्दिष्ट तालिका नाम है। यदि हाँ, तो एक चेतावनी जारी की जाएगी औरcontinue।if item == '?':यदि तत्व का मान '?' चिह्न है, तो आउटपुट परिणाम यादृच्छिक रूप से क्रमबद्ध किया जाएगा,continue।if item.startswith('-'):यदि item '-' वर्ण से शुरू होता है, तो क्वेरी का परिणाम DESC (घटते क्रम) में क्रमबद्ध किया जाएगा।if item in self.annotations:यह जांचता है कि कोई टिप्पणी है या नहीं, यदि हाँ, तोcontinue।if self.extra and item in self.extra:निर्धारित करता है कि कोई अतिरिक्त जोड़ है या नहीं और यदि हाँ तोcontinue।
5 जांचों के बाद, पैरामीटर को self.names_to_path(item.split(LOOKUP_SEP), self.model._meta) फ़ंक्शन में पारित किया जाता है ताकि यह जांचा जा सके कि यह एक मान्य कॉलम नाम है या नहीं, फिर यदि मान्य है तो उन्हें आगे की प्रक्रिया के लिए Query क्लास के self.ordering में जोड़ा जाएगा।