Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2025-21298 — Une vulnérabilité critique Windows OLE Zero-Click. Ceci est une preuve de concept pour CVE-2025-21298 - Vulnérabilité d'exécution de code à distance Windows OLE (CVSS 9.8). Ceci est un PoC de corruption de mémoire. | Kitploit
Outils/GitHubGitHub/thebl4ckph4nt0m/cve-2025-21298
Criminalistique MémoireAnalyse des VulnérabilitésExploitationExploitation de Binaires
GitHubthebl4ckph4nt0m/cve-2025-21298

CVE-2025-21298

Une vulnérabilité critique Windows OLE Zero-Click. Ceci est une preuve de concept pour CVE-2025-21298 - Vulnérabilité d'exécution de code à distance Windows OLE (CVSS 9.8). Ceci est un PoC de corruption de mémoire.

Voir le dépôt

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
13il y a 1 anPas encore vérifié

CVE-2025-21298

contenu

Ceci est une preuve de concept pour CVE-2025-21298 - Vulnérabilité d'exécution de code à distance OLE Windows (CVSS 9.8). Il s'agit d'un PoC de corruption mémoire, pas d'un exploit.

vulnérabilité

La vulnérabilité se situe dans ole32.dll!UtOlePresStmToContentsStm. Le but de la fonction est de convertir les données d'un flux "OlePres" dans un stockage OLE en données correctement formatées et de les insérer dans le flux "CONTENTS" du même stockage. Elle reçoit un pointeur IStorage vers un objet de stockage et trois arguments plutôt secondaires.

Ci-dessous, nous pouvons voir l'implémentation de la fonction avec une différence par rapport au correctif de janvier 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;
}

Le problème se trouve dans la variable pstmContents. Initialement, elle est utilisée pour stocker le pointeur vers l'objet de flux "CONTENTS" créé au début de la fonction. Le flux est immédiatement détruit après sa création et le pointeur stocké dans pstmContents est libéré (ce qui le libère dans coml2.dll!ExposedStream::~ExposedStream). Cependant, la variable contient toujours le pointeur libéré. Plus loin dans la fonction, la variable peut être réutilisée pour stocker à nouveau le pointeur vers le flux "CONTENTS" — à cause de cela, il y a du code de nettoyage à la fin de la fonction qui libère le pointeur au cas où il serait stocké dans la variable. Le code ne prend pas en compte le fait que UtReadOlePresStmHeader peut échouer — si cela se produit, pstmContents pointera toujours vers le pointeur libéré et nous tomberons dans le code de nettoyage, qui libérera à nouveau le pointeur. Il en résulte donc une situation de double libération.

Comme on peut le voir dans le diff du correctif, Microsoft a résolu le problème en mettant pstmContents à zéro après la libération initiale du pointeur qu'il contient.

Reproduction

Dans le dépôt se trouve un fichier rtf qui reproduit la vulnérabilité. J'ai testé en ouvrant le fichier dans MS Word mais vous pouvez aussi le tester avec d'autres applications qui analysent les données RTF (par exemple Outlook). L'exploitation via d'autres formats qui intègrent des objets OLE peut être possible, je n'ai pas essayé.

Vidéo :

poc

Télécharger l’outil