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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2023-21768 — إثبات مفهوم لاستغلال CVE-2023-21768، وهي ثغرة كتابة عشوائية في نواة نظام التشغيل Windows عبر برنامج تشغيل الوظائف المساعدة (AFD.sys)، مما يتيح تصعيد الامتيازات محليًا عبر حلقة الإدخال/الإخراج (I/O ring). | Kitploit
أدوات/GitHubGitHub/h1bana/cve-2023-21768
تصعيد الامتيازاتتحليل الثغرات الأمنيةالاستغلالاستغلال الملفات الثنائية
GitHubh1bana/cve-2023-21768

CVE-2023-21768

إثبات مفهوم لاستغلال CVE-2023-21768، وهي ثغرة كتابة عشوائية في نواة نظام التشغيل Windows عبر برنامج تشغيل الوظائف المساعدة (AFD.sys)، مما يتيح تصعيد الامتيازات محليًا عبر حلقة الإدخال/الإخراج (I/O ring).

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

الأكثر شعبية

عرض الكل →

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

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

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

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

CVE-2023-21768

برنامج تشغيل الوظائف الإضافية لويندوز لـ WinSock

وفقًا للوصف التفصيلي لـ CVE-2023-21768 الذي نشرته Microsoft Security Response Center (MSRC)، توجد الثغرة في Ancillary Function Driver (AFD)، واسم ملفه في النظام هو afd.sys. وحدة AFD هي نقطة دخول النواة (kernel entry point) لـ WinSock API. في هذا التحليل سأستخدمها لاستغلال تصعيد الامتيازات على ويندوز 11.

تحليل الفروقات في التصحيح وسبب الجذر

قم بتحميل نسختين من afd.sys من Winbindex، أحدث نسخة قبل التصحيح، ونسخة بعد التصحيح. ثم استخدم Bindiff لمقارنة هاتين النسختين. bindiff

بمقارنة النسختين بشكل عام، نرى أن هناك دالة واحدة فقط مختلفة وهي AfdNotifyRemoveIoCompletion. دعونا نلقي نظرة أكثر تفصيلًا على الاختلافات في هذه الدالة بين النسختين. bindiff

لا توجد اختلافات كثيرة بين النسختين. في الإصدار بعد التصحيح (post-patch)، تمت إضافة تعليمات assembly لتعيين المعاملات واستدعاء دالة ProbeForWrite. وفقًا لـ الوثيقة الخاصة بشركة Microsoft، تُستخدم هذه الدالة للتحقق مما إذا كان العنوان ينتمي حقًا إلى وضع المستخدم (user-mode)، ولديه صلاحية الكتابة، ومحاذي بشكل صحيح أم لا. تحليل أكثر تفصيلًا لهذا الكود:

  • ما قبل التصحيح afd.sys version 10.0.22621.608 code1

  • ما بعد التصحيح afd.sys version 10.0.22621.1105 code2

كلاهما يتحقق من قيمة r15_1، إذا كانت تساوي 0 فسيتم كتابة قيمة var_304 إلى المؤشر المحدد في أحد حقول struct_1. إذا كانت مختلفة عن 0، فسيتم استدعاء ProbeForWrite للتأكد من أن المؤشر يشير إلى عنوان صالح. في إصدار pre-patch يتم بعد ذلك كتابة القيمة عند var_304 إلى المؤشر، وهذا الفحص مفقود. من هذا التصحيح، يمكننا تخمين أنه يمكننا استدعاء هذا الكود بقيمة arg3_1->field_18 التي نتحكم فيها. إذا تمكنا من تعيين قيمة عنوان kernel في field_18، فيمكننا كتابة var_304 إلى عنوان في ذاكرة kernel.

=> bug type: arbitrary kernel Write-Where

الآن نحتاج إلى إيجاد طريقة لتفعيل (trigger) الثغرة. يتم استدعاء الدالة AfdNotifyRemoveIoCompletion مباشرة داخل الدالة AfdNotifySock. crossRef

وبالمثل، عند البحث عن cross reference للدالة AfdNotifySock نجد أنها لا تُستدعى مباشرة من أي دالة أخرى، ولكن عنوان الدالة يُحفظ في عنوان داخل .rdata cross2

هذا العنوان يقع مباشرة قبل AfdIrpCallDispatch. cross3

لتفعيل الثغرة، سأستدعي DeviceIoControl مع IOCTL_AFD_NOTIFY_SOCK وسيتم استدعاء AfdNotifySock.

BOOL DeviceIoControl(
  [in]                HANDLE       hDevice,
  [in]                DWORD        dwIoControlCode,
  [in, optional]      LPVOID       lpInBuffer,
  [in]                DWORD        nInBufferSize,
  [out, optional]     LPVOID       lpOutBuffer,
  [in]                DWORD        nOutBufferSize,
  [out, optional]     LPDWORD      lpBytesReturned,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);

التحليل العكسي والتصحيح

لكل برنامج تشغيل (driver)، يتم إنشاء كائن DRIVER_OBJECT في النواة، وهو معرّف على النحو التالي:

typedef struct _DRIVER_OBJECT {
  CSHORT             Type;
  CSHORT             Size;
  PDEVICE_OBJECT     DeviceObject;
  ULONG              Flags;
  PVOID              DriverStart;
  ULONG              DriverSize;
  PVOID              DriverSection;
  PDRIVER_EXTENSION  DriverExtension;
  UNICODE_STRING     DriverName;
  PUNICODE_STRING    HardwareDatabase;
  PFAST_IO_DISPATCH  FastIoDispatch;
  PDRIVER_INITIALIZE DriverInit;
  PDRIVER_STARTIO    DriverStartIo;
  PDRIVER_UNLOAD     DriverUnload;
  PDRIVER_DISPATCH   MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT, *PDRIVER_OBJECT;

المكوّن الأخير MajorFunction هو مصفوفة تحتوي على دوال dispatch الخاصة ببرنامج التشغيل لمعالجة الاتصالات بين النواة ووضع المستخدم. دالة dispatch المقابلة لاستدعاء DeviceIoControl تُحفظ في MajorFunction[IRP_MJ_DEVICE_CONTROL].

#define IRP_MJ_DEVICE_CONTROL           0x0e

من خلال دالة DriverEntry الخاصة بـ afd.sys، يمكننا أن نرى أن برنامج التشغيل أنشأ device object "\Device\Afd": code3

يتم تعيين MajorFunction[IRP_MJ_DEVICE_CONTROL] = AfdDispatchDeviceControl، لذلك عند استدعاء DeviceIoControl للتواصل مع النواة، سيتم استدعاء هذه الدالة. code4

يوجد في AFD جدولان للتوزيع (dispatch table) وهما AfdIrpCallDispatch و AfdImmediateCallDispatch. dispatchtable1 dispatchtable2

يمكننا بسهولة ملاحظة أن AfdDispatchDeviceIoControl يحسب subscript من خلال IoControlCode ويأخذ القيمة المقابلة للـ subscript من AfdIoctlTable للتحقق منها باستخدام IoControlCode. 1

من المسافة بين عنوان بداية AfdImmediateCallDispatch والعنوان الذي يُخزّن AfdNotifySock، نحسب أن الـ index هو 73، ورمز التحكم (control code) هو 0x12127 ioctl

int main() {
    WSADATA WSAData;
    SOCKET s;
    SOCKADDR_IN sa;
    int ierr;

    WSAStartup(0x2, &WSAData);
    s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    memset(&sa, 0, sizeof(sa));
    sa.sin_port = htons(135);
    sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    sa.sin_family = AF_INET;
    ierr = connect(s, (const struct sockaddr*)&sa, sizeof(sa));

    char outBuf[100];
    DWORD bytesRet;
    DWORD inbuf1[100];

    memset(inbuf1, 0, sizeof(inbuf1));

    DeviceIoControl((HANDLE)s, 0x12127, (LPVOID)inbuf1, 0x30, outBuf, 0, &bytesRet, NULL);
    return 0;
}

لقد نجح الأمر!

bp1

كما ذكرنا منذ البداية، تحدث الثغرة عندما نتمكن من تمرير مؤشر غير مُتحقق منه (unvalidated pointer) عبر struct. يتم تمرير هذا الـ struct مباشرة من وضع المستخدم عبر lpInBuffer الخاص بـ DeviceIoControl. ثم يُمرَّر إلى AfdNotifySock كمعامل رابع ويُمرَّر إلى AfdNotifyRemoveIoCompletion كمعامل ثالث.

para1 para2 para3

نظرًا لأننا لا نعرف ما يتضمنه الـ struct، تركت IDA ينشئ الـ struct تلقائيًا. الآن نحتاج إلى إيجاد طريقة لتمرير البيانات إلى هذا الـ struct وتجاوز الفحوصات اللازمة للوصول إلى الكود المعيب. نبدأ من الدالة AfdNotifySock:

تنزيل الأداة