صائد الثغرات: كيف تبحث عن الاستغلالات الجاهزة (Exploits) في قواعد البيانات؟


صائد الثغرات: كيف تبحث عن الاستغلالات الجاهزة (Exploits) في قواعد البيانات؟

ماذا سنتعلم اليوم؟ سنستكشف كيفية البحث المبرمج عن الاستغلالات الجاهزة (Exploits) في قواعد بيانات الثغرات، مع التركيز على استخدام Python لاستخلاص المعلومات القيمة.

سنتعلم كيفية التفاعل مع قواعد بيانات الاستغلالات الشهيرة للعثور على نقاط ضعف محددة واستغلالاتها.

الخطوة 1: فهم قواعد بيانات الاستغلالات وأهميتها

قبل الغوص في الكود، من الضروري فهم ماهية قواعد بيانات الاستغلالات. هذه القواعد هي مستودعات ضخمة تحتوي على معلومات حول الثغرات الأمنية المعروفة، بالإضافة إلى الأكواد البرمجية (Exploits) التي يمكن استخدامها لاستغلال هذه الثغرات.

ملاحظة تقنية: من أشهر قواعد البيانات هذه: Exploit-DB، Packet Storm، و CVE Details. كل منها يقدم واجهة بحث، ولكن البحث المبرمج يوفر سرعة ومرونة أكبر بكثير للباحث الأمني.

سنركز في هذا الدرس على البحث في Exploit-DB كمثال، حيث لا توفر واجهة برمجة تطبيقات (API) عامة، مما يجعلها مرشحاً ممتازاً لتطبيق تقنيات استخلاص الويب (Web Scraping) باستخدام Python.

الخطوة 2: إعداد بيئة البحث وجلب المحتوى

سنبدأ بإعداد بيئة Python الخاصة بنا. نحتاج إلى مكتبة requests لجلب صفحات الويب، ومكتبة BeautifulSoup لتحليل محتوى HTML. إذا لم تكن مثبتة لديك، يمكنك تثبيتها كالتالي:

pip install requests beautifulsoup4

الآن، لنكتب جزءاً من الكود الذي يقوم بجلب صفحة البحث من Exploit-DB. سنقوم بإنشاء دالة تستقبل الكلمة المفتاحية للبحث.

import requests
from bs4 import BeautifulSoup

def search_exploitdb(keyword):
    """
    تقوم بجلب محتوى صفحة البحث من Exploit-DB بناءً على الكلمة المفتاحية.
    تستخدم طلب HTTP GET لمحاكاة البحث اليدوي.
    """
    # بناء عنوان URL للبحث في Exploit-DB. نستبدل المسافات بعلامة '+' لعنوان URL صحيح.
    search_url = f"https://www.exploit-db.com/search?q={keyword.replace(' ', '+')}"
    
    try:
        # إرسال طلب HTTP للحصول على محتوى الصفحة مع مهلة 10 ثوانٍ.
        response = requests.get(search_url, timeout=10)
        # إطلاق استثناء لأخطاء HTTP (4xx أو 5xx) لسهولة التعامل مع الأخطاء.
        response.raise_for_status()
        print(f"تم جلب صفحة البحث بنجاح لـ: '{keyword}'")
        return response.text
    except requests.exceptions.RequestException as e:
        print(f"فشل جلب صفحة البحث لـ '{keyword}'. الخطأ: {e}")
        return None

# مثال على الاستخدام:
# html_content = search_exploitdb("MySQL SQL Injection")
# if html_content:
#     print("تم الحصول على محتوى HTML بنجاح.")

ملاحظة تقنية: استخلاص الويب (Web Scraping) يتطلب الحذر واحترام شروط استخدام الموقع المستهدف. التغييرات في هيكل الموقع قد تتطلب تعديل الـ selectors المستخدمة في الكود.

الخطوة 3: تحليل النتائج واستخلاص المعلومات

بعد جلب محتوى HTML، نحتاج إلى تحليل هذا المحتوى لاستخراج المعلومات ذات الصلة مثل اسم الاستغلال، تاريخ النشر، ورابط الاستغلال. سنستخدم BeautifulSoup لهذا الغرض، مع الأخذ في الاعتبار أن نتائج Exploit-DB تظهر عادةً في جدول.

# ... (الكود السابق)

def parse_exploit_results(html_content):
    """
    تقوم بتحليل محتوى HTML المستخلص من Exploit-DB واستخراج تفاصيل الاستغلالات.
    تعتمد على بنية HTML الخاصة بـ Exploit-DB، وقد تتطلب تحديثات إذا تغير هيكل الموقع.
    """
    if not html_content:
        return []

    soup = BeautifulSoup(html_content, 'html.parser')
    results = []
    
    # البحث عن جدول النتائج الذي يحتوي على الاستغلالات. عادة ما يكون له class معين.
    # في Exploit-DB، النتائج عادةً ما تكون في جدول ضمن <table class="table table-striped">
    table_body = soup.find('table', class_='table table-striped')
    if not table_body:
        print("لم يتم العثور على جدول النتائج (table.table-striped). ربما تغير هيكل الموقع.")
        return []

    # البحث عن صفوف البيانات (<tr>) داخل جسم الجدول (<tbody>).
    rows = table_body.find('tbody').find_all('tr') 

    for row in rows:
        cols = row.find_all('td') # استخراج الخلايا (<td>) من كل صف.
        # نتوقع على الأقل 6 أعمدة: ID, Date, Description, Type, Platform, Author.
        if len(cols) >= 6:
            try:
                exploit_id = cols[0].get_text(strip=True)
                exploit_date = cols[1].get_text(strip=True)
                
                # الوصف عادة ما يكون داخل وسم <a> داخل الخلية الثالثة.
                description_tag = cols[2].find('a')
                exploit_description = description_tag.get_text(strip=True) if description_tag else "N/A"
                # بناء الرابط الكامل للاستغلال.
                exploit_link = "https://www.exploit-db.com" + description_tag['href'] if description_tag and 'href' in description_tag.attrs else "N/A"
                
                exploit_type = cols[3].get_text(strip=True)
                exploit_platform = cols[4].get_text(strip=True)
                exploit_author = cols[5].get_text(strip=True)

                results.append({
                    "ID": exploit_id,
                    "Date": exploit_date,
                    "Description": exploit_description,
                    "Type": exploit_type,
                    "Platform": exploit_platform,
                    "Author": exploit_author,
                    "Link": exploit_link
                })
            except Exception as e:
                print(f"خطأ أثناء تحليل صف: {row}. الخطأ: {e}")
                continue
    return results

# مثال على الاستخدام:
# search_term = "PostgreSQL Remote Code Execution"
# html_content = search_exploitdb(search_term)
# if html_content:
#     parsed_exploits = parse_exploit_results(html_content)
#     for exploit in parsed_exploits[:3]: # عرض أول 3 نتائج
#         print(f"ID: {exploit['ID']}, Description: {exploit['Description']}")

الخطوة 4: عرض النتائج بطريقة منظمة

الآن بعد أن أصبح لدينا قائمة بالاستغلالات، يمكننا عرضها بطريقة واضحة ومنظمة في سطر الأوامر. سنقوم بإنشاء دالة لطباعة أهم التفاصيل لكل استغلال تم العثور عليه، مع إمكانية تحديد عدد النتائج المعروضة.

# ... (الكود السابق)

def display_exploits(exploits, limit=10):
    """
    تقوم بطباعة تفاصيل الاستغلالات التي تم العثور عليها بطريقة منظمة.
    يمكن تحديد عدد النتائج القصوى للعرض باستخدام المعامل 'limit'.
    """
    if not exploits:
        print("لم يتم العثور على أي استغلالات مطابقة للبحث.")
        return

    print(f"\n--- تم العثور على {len(exploits)} استغلالات. عرض أول {min(len(exploits), limit)} ---")
    print("=" * 80)
    for i, exploit in enumerate(exploits):
        if i >= limit:
            break
        print(f"ID: {exploit['ID']}")
        print(f"الوصف: {exploit['Description']}")
        print(f"النوع: {exploit['Type']} | المنصة: {exploit['Platform']}")
        print(f"التاريخ: {exploit['Date']} | المؤلف: {exploit['Author']}")
        print(f"الرابط: {exploit['Link']}")
        print("=" * 80)

# مثال على الاستخدام النهائي:
# search_term = "MySQL Remote Code Execution"
# html_content = search_exploitdb(search_term)
# if html_content:
#     parsed_exploits = parse_exploit_results(html_content)
#     display_exploits(parsed_exploits, limit=5) # عرض أول 5 استغلالات

الكود النهائي الكامل

هذا هو السكربت الكامل الذي يجمع الخطوات المذكورة أعلاه. يمكنك نسخه ولصقه وتشغيله مباشرة في بيئة Python.

import requests
from bs4 import BeautifulSoup

def search_exploitdb(keyword):
    """
    تقوم بجلب محتوى صفحة البحث من Exploit-DB بناءً على الكلمة المفتاحية.
    تستخدم طلب HTTP GET لمحاكاة البحث اليدوي.
    """
    # بناء عنوان URL للبحث في Exploit-DB. نستبدل المسافات بعلامة '+' لعنوان URL صحيح.
    search_url = f"https://www.exploit-db.com/search?q={keyword.replace(' ', '+')}"
    
    try:
        # إرسال طلب HTTP للحصول على محتوى الصفحة مع مهلة 10 ثوانٍ.
        response = requests.get(search_url, timeout=10)
        # إطلاق استثناء لأخطاء HTTP (4xx أو 5xx) لسهولة التعامل مع الأخطاء.
        response.raise_for_status()
        print(f"تم جلب صفحة البحث بنجاح لـ: '{keyword}'")
        return response.text
    except requests.exceptions.RequestException as e:
        print(f"فشل جلب صفحة البحث لـ '{keyword}'. الخطأ: {e}")
        return None

def parse_exploit_results(html_content):
    """
    تقوم بتحليل محتوى HTML المستخلص من Exploit-DB واستخراج تفاصيل الاستغلالات.
    تعتمد على بنية HTML الخاصة بـ Exploit-DB، وقد تتطلب تحديثات إذا تغير هيكل الموقع.
    """
    if not html_content:
        return []

    soup = BeautifulSoup(html_content, 'html.parser')
    results = []
    
    # البحث عن جدول النتائج الذي يحتوي على الاستغلالات. عادة ما يكون له class معين.
    # في Exploit-DB، النتائج عادةً ما تكون في جدول ضمن <table class="table table-striped">
    table_body = soup.find('table', class_='table table-striped')
    if not table_body:
        print("لم يتم العثور على جدول النتائج (table.table-striped). ربما تغير هيكل الموقع.")
        return []

    # البحث عن صفوف البيانات (<tr>) داخل جسم الجدول (<tbody>).
    rows = table_body.find('tbody').find_all('tr') 

    for row in rows:
        cols = row.find_all('td') # استخراج الخلايا (<td>) من كل صف.
        # نتوقع على الأقل 6 أعمدة: ID, Date, Description, Type, Platform, Author.
        if len(cols) >= 6:
            try:
                exploit_id = cols[0].get_text(strip=True)
                exploit_date = cols[1].get_text(strip=True)
                
                # الوصف عادة ما يكون داخل وسم <a> داخل الخلية الثالثة.
                description_tag = cols[2].find('a')
                exploit_description = description_tag.get_text(strip=True) if description_tag else "N/A"
                # بناء الرابط الكامل للاستغلال.
                exploit_link = "https://www.exploit-db.com" + description_tag['href'] if description_tag and 'href' in description_tag.attrs else "N/A"
                
                exploit_type = cols[3].get_text(strip=True)
                exploit_platform = cols[4].get_text(strip=True)
                exploit_author = cols[5].get_text(strip=True)

                results.append({
                    "ID": exploit_id,
                    "Date": exploit_date,
                    "Description": exploit_description,
                    "Type": exploit_type,
                    "Platform": exploit_platform,
                    "Author": exploit_author,
                    "Link": exploit_link
                })
            except Exception as e:
                print(f"خطأ أثناء تحليل صف: {row}. الخطأ: {e}")
                continue
    return results

def display_exploits(exploits, limit=10):
    """
    تقوم بطباعة تفاصيل الاستغلالات التي تم العثور عليها بطريقة منظمة.
    يمكن تحديد عدد النتائج القصوى للعرض باستخدام المعامل 'limit'.
    """
    if not exploits:
        print("لم يتم العثور على أي استغلالات مطابقة للبحث.")
        return

    print(f"\n--- تم العثور على {len(exploits)} استغلالات. عرض أول {min(len(exploits), limit)} ---")
    print("=" * 80)
    for i, exploit in enumerate(exploits):
        if i >= limit:
            break
        print(f"ID: {exploit['ID']}")
        print(f"الوصف: {exploit['Description']}")
        print(f"النوع: {exploit['Type']} | المنصة: {exploit['Platform']}")
        print(f"التاريخ: {exploit['Date']} | المؤلف: {exploit['Author']}")
        print(f"الرابط: {exploit['Link']}")
        print("=" * 80)

if __name__ == "__main__":
    # الكلمة المفتاحية للبحث، يطلبها من المستخدم.
    search_term = input("أدخل الكلمة المفتاحية للبحث عن الاستغلالات (مثال: MySQL SQL Injection): ")
    
    html_content = search_exploitdb(search_term)
    
    if html_content:
        parsed_exploits = parse_exploit_results(html_content)
        display_exploits(parsed_exploits, limit=10) # عرض أول 10 استغلالات بشكل افتراضي

النتيجة المتوقعة

عند تشغيل السكربت، سيطلب منك إدخال كلمة مفتاحية للبحث. بعد إدخال الكلمة (مثال: "MySQL SQL Injection" أو "PostgreSQL RCE")، سيقوم السكربت بـ:

  1. جلب صفحة نتائج البحث من Exploit-DB.
  2. تحليل محتوى HTML للصفحة باستخدام BeautifulSoup.
  3. استخراج تفاصيل الاستغلالات مثل الـ ID، الوصف، النوع، المنصة، التاريخ، المؤلف، والرابط.
  4. طباعة قائمة منظمة بأول 10 استغلالات تم العثور عليها (أو حسب الحد المحدد).

ستظهر النتائج في سطر الأوامر (Terminal) بالشكل التالي:

أدخل الكلمة المفتاحية للبحث عن الاستغلالات (مثال: MySQL SQL Injection): MySQL RCE
تم جلب صفحة البحث بنجاح لـ: 'MySQL RCE'
--- تم العثور على X استغلالات. عرض أول 10 ---
================================================================================
ID: 40854
الوصف: MySQL / MariaDB - Remote Root Code Execution
النوع: remote | المنصة: multiple
التاريخ: 2016-12-19 | المؤلف: Dawid Golunski
الرابط: https://www.exploit-db.com/exploits/40854
================================================================================
ID: 40853
الوصف: MySQL / MariaDB - Privilege Escalation
النوع: local | المنصة: linux
التاريخ: 2016-12-19 | المؤلف: Dawid Golunski
الرابط: https://www.exploit-db.com/exploits/40853
================================================================================
... والمزيد من النتائج، تعرض تفاصيل الاستغلالات التي تطابق كلمة البحث ...

بهذه الطريقة، تكون قد بنيت أداة بسيطة لكنها قوية للبحث المبرمج عن الاستغلالات الجاهزة في قواعد البيانات العامة، مما يوفر الوقت والجهد في عمليات البحث اليدوية ويسهل دمج هذه الوظيفة في أدوات أمنية أكبر.