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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2025-21298 — إثبات المفهوم وتفاصيل CVE-2025-21298 | Kitploit
أدوات/GitHubGitHub/ynwarcs/cve-2025-21298
تحليل الذاكرة الجنائيتحليل الثغرات الأمنيةالاستغلالالهندسة العكسيةتحليل الملفات الثنائية
GitHubynwarcs/cve-2025-21298

CVE-2025-21298

إثبات المفهوم وتفاصيل CVE-2025-21298

عرض المستودع
197492منذ سنة واحدةتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

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

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

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

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

المحتوى

هذا إثبات مفهوم لـ CVE-2025-21298 - ثغرة تنفيذ التعليمات البرمجية عن بُعد في OLE بنظام Windows (CVSS 9.8). هذا إثبات مفهوم لتلف الذاكرة، وليس استغلالاً.

فرق التصحيح الكامل عبر ghidriff: رابط

الثغرة

تقع الثغرة في ole32.dll!UtOlePresStmToContentsStm. الغرض من الدالة هو تحويل البيانات في دفق "OlePres" داخل تخزين OLE إلى بيانات منسقة بشكل مناسب وإدراجها في دفق "CONTENTS" في نفس التخزين. تستقبل مؤشر IStorage إلى كائن تخزين وثلاث وسائط غير مهمة نسبيًا.

أدناه يمكننا رؤية تنفيذ الدالة مع فرق من تصحيح يناير 2025:

root@kitploit:~
__int64 __fastcall UtOlePresStmToContentsStm(IStorage *pstg, wchar_t *puiStatus, __int64 a3, unsigned int *lpszPresStm)
{
  struct IStorageVtbl *lpVtbl; // rax
  int v7; // r14d
+ bool IsEnabled; // al
  IStream *v10; // rcx
  bool v11; // zf
  struct IStorageVtbl *v12; // rax
  int v13; // ebx
  HRESULT v14; // eax
  const wchar_t *v15; // rdx
  IStream *pstmContents; // [rsp+40h] [rbp-19h] BYREF
  IStream *pstmOlePres; // [rsp+48h] [rbp-11h] BYREF
  tagFORMATETC foretc; // [rsp+50h] [rbp-9h] BYREF
  tagHDIBFILEHDR hdfh; // [rsp+70h] [rbp+17h] BYREF

  *lpszPresStm = 0;
  lpVtbl = pstg->lpVtbl;
  pstmContents = 0LL;
  v7 = 1;
  // Create a "CONTENTS" stream in the storage and store it into pstmContents
  if ( (lpVtbl->CreateStream)(pstg, L"CONTENTS", 18LL, 0LL, 0, &pstmContents) )
    return 0LL;
  // Immediately release pstmContents, we're not going to be using it right now
  (pstmContents->lpVtbl->Release)(pstmContents);
+ IsEnabled = wil::details::FeatureImpl<__WilFeatureTraits_Feature_3047977275>::__private_IsEnabled(&`wil::Feature<__WilFeatureTraits_Feature_3047977275>::GetImpl'::`2'::impl);
+ v10 = pstmContents;
+ v11 = !IsEnabled;
  v12 = pstg->lpVtbl;
+ if ( !v11 )
+   v10 = 0LL;
+ pstmContents = v10;
  (v12->DestroyElement)(pstg, L"CONTENTS");
  v13 = (pstg->lpVtbl->OpenStream)(pstg, &OlePres, 0LL, 16LL, 0, &pstmOlePres);// 2nd option to fail -> no OlePres stream
  if ( v13 )
  {
    *lpszPresStm |= 1u;
    if ( (pstg->lpVtbl->OpenStream)(pstg, L"CONTENTS", 0LL, 16LL, 0, &pstmContents) )
    {
      *lpszPresStm |= 2u;
    }
    else
    {
      (pstmContents->lpVtbl->Release)(pstmContents);
+     wil::details::FeatureImpl<__WilFeatureTraits_Feature_3047977275>::__private_IsEnabled(&`wil::Feature<__WilFeatureTraits_Feature_3047977275>::GetImpl'::`2'::impl);
    }
    return v13;
  }
  foretc.ptd = 0LL;
  v13 = UtReadOlePresStmHeader(pstmOlePres, &foretc, 0LL, 0LL);
  if ( v13 >= 0 )
  {
    v13 = (pstmOlePres->lpVtbl->Read)(pstmOlePres, &hdfh, 16LL);
    if ( v13 >= 0 )
    {
      v13 = OpenOrCreateStream(pstg, L"CONTENTS", &pstmContents);
      if ( v13 < 0 )
      {
        *lpszPresStm |= 2u;
        goto $errRtn_197;
      }
      if ( foretc.dwAspect == 4 )
      {
        *lpszPresStm |= 4u;
        v7 = 0;
        v13 = 0;
        goto $errRtn_197;
      }
      if ( foretc.cfFormat == 8 )
      {
        v14 = UtDIBStmToDIBFileStm(pstmOlePres, hdfh.dwSize, pstmContents);
LABEL_19:
        v13 = v14;
        goto $errRtn_197;
      }
      if ( foretc.cfFormat == 3 )
      {
        v14 = UtMFStmToPlaceableMFStm(pstmOlePres, hdfh.dwSize, hdfh.dwWidth, hdfh.dwHeight, pstmContents);
        goto LABEL_19;
      }
      v13 = -2147221398;
    }
  }
$errRtn_197:
  if ( pstmOlePres )
    (pstmOlePres->lpVtbl->Release)(pstmOlePres);
  // Release pstmContents if it still exists, we need to clean up
  if ( pstmContents )
    (pstmContents->lpVtbl->Release)(pstmContents);
  if ( foretc.ptd )
    CoTaskMemFree(foretc.ptd);
  if ( v13 )
  {
    v15 = L"CONTENTS";
    goto LABEL_31;
  }
  if ( v7 )
  {
    v15 = &OlePres;
LABEL_31:
    (pstg->lpVtbl->DestroyElement)(pstg, v15);
  }
  return v13;
}

المشكلة تكمن في المتغير pstmContents. في البداية يُستخدم لتخزين المؤشر إلى كائن دفق "CONTENTS" الذي يتم إنشاؤه في بداية الدالة. يتم إتلاف الدفق فور إنشائه ويتم تحرير المؤشر المخزن في pstmContents (مما يحرره في coml2.dll!ExposedStream::~ExposedStream). ومع ذلك، لا يزال المتغير يحتوي على المؤشر المحرر. في موضع لاحق من الدالة، قد يُعاد استخدام المتغير لتخزين المؤشر إلى دفق "CONTENTS" مرة أخرى - ولهذا السبب، توجد تعليمات برمجية للتنظيف في نهاية الدالة تقوم بتحرير المؤشر في حال كان مخزنًا في المتغير. لا تراعي التعليمات البرمجية حقيقة أن UtReadOlePresStmHeader قد تفشل - إذا حدث ذلك، سيظل pstmContents يشير إلى المؤشر المحرر وسنصل إلى تعليمات التنظيف، والتي ستقوم بتحرير المؤشر مرة أخرى. وبالتالي، سيحدث موقف تحرير مزدوج.

كما يتضح من فرق التصحيح، أصلحت Microsoft المشكلة بتعيين pstmContents إلى صفر بعد تحرير المؤشر الذي يحتويه في البداية.

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

في المستودع ملف rtf يعيد إنتاج الثغرة. اختبرته بفتح الملف في MS Word ولكن يمكنك أيضًا اختباره مع تطبيقات أخرى تحلل بيانات RTF (مثل Outlook). قد يكون الاستغلال عبر تنسيقات أخرى تتضمن كائنات OLE ممكنًا، لكنني لم أجربه.

فيديو:

poc.webm

التفاصيل

سأنشر التفاصيل لاحقًا.

تنزيل الأداة