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 — Preuve de concept et détails pour CVE-2025-21298 | Kitploit
Outils/GitHubGitHub/ynwarcs/cve-2025-21298
Criminalistique MémoireAnalyse des VulnérabilitésExploitationRétro-ingénierieAnalyse de Binaires
GitHubynwarcs/cve-2025-21298

CVE-2025-21298

Preuve de concept et détails pour CVE-2025-21298

Voir le dépôt
19749il y a 1 anVérifié par Kitploit

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

contenu

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

Diff complet du correctif via ghidriff : LIEN

vulnérabilité

La vulnérabilité se situe dans ole32.dll!UtOlePresStmToContentsStm. Cette fonction a pour but 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 sans importance.

Ci-dessous, nous pouvons voir l'implémentation de la fonction avec un diff du 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 situe 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 » – c'est pourquoi il existe un code de nettoyage à la fin de la fonction qui libère le pointeur s'il est stocké dans la variable. Le code ne tient pas compte du fait que UtReadOlePresStmHeader peut échouer – si cela se produit, pstmContents pointera toujours vers le pointeur libéré et nous tomberons sur le code de nettoyage, qui libérera à nouveau le pointeur. Cela conduit à une situation de double libération (double-free).

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

Reproduction

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

Vidéo :

poc.webm

Détails

Je publierai les détails plus tard.

Télécharger l’outil