
Living of the Land - WinExec - Symantec Endpoint Protection Manager (SEPM)
Reference: - https://twitter.com/nas_bench/status/1483402513193881600 Having an instance of Symantec Endpoint Protection Manager (SEPM) installed would give user access to the…
WinExec - Symantec Endpoint Protection Manager (SEPM)
Reference:
Summary
Having an instance of Symantec Endpoint Protection Manager (SEPM) installed would give user access to the binary "WinExec.EXE". It can be used to launch arbitrary commands.
It offers to mode of execution.
- If the
-cthe flag is provided. The next argument will be called directly by theCreateProcessWAPI. - Otherwise the provided argument is passed to
cmd.exe /c <Command>.
Example
WinExec.exe <Command>
WinExec.exe -c <Binary>
Additional Details
Taking a look behind the scene we can see the following decompiled main function.
int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
{
HMODULE LibraryA; // eax
HMODULE v5; // esi
BOOL (__stdcall *HeapSetInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T); // eax
wchar_t Destination[1024]; // [esp+8h] [ebp-804h] BYREF
LibraryA = LoadLibraryA("kernel32.dll");
v5 = LibraryA;
if ( LibraryA )
{
HeapSetInformation = (BOOL (__stdcall *)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T))GetProcAddress(
LibraryA,
"HeapSetInformation");
if ( HeapSetInformation )
HeapSetInformation(0, HeapEnableTerminationOnCorruption, 0, 0);
FreeLibrary(v5);
}
if ( dword_11D9B24 < 2 )
return -1;
if ( !wcscmp(*(const unsigned __int16 **)(dword_11D9B2C + 4), L"-c") )
{
if ( dword_11D9B24 < 3 )
return -1;
return sub_11D5290(*(LPWSTR *)(dword_11D9B2C + 8));
}
else
{
wcscpy_s(Destination, 0x3FFu, L"cmd.exe /c ");
wcscat_s(Destination, 0x3E8u, *(const wchar_t **)(dword_11D9B2C + 4));
return sub_11D5290(Destination);
}
}From a LOLBIN perspective we're going to focus on the following section
if ( dword_11D9B24 < 2 )
return -1;
if ( !wcscmp(*(const unsigned __int16 **)(dword_11D9B2C + 4), L"-c") )
{
if ( dword_11D9B24 < 3 )
return -1;
return sub_11D5290(*(LPWSTR *)(dword_11D9B2C + 8));
}
else
{
wcscpy_s(Destination, 0x3FFu, L"cmd.exe /c ");
wcscat_s(Destination, 0x3E8u, *(const wchar_t **)(dword_11D9B2C + 4));
return sub_11D5290(Destination);
}In this case the dword_11D9B24 variable represent the number of argument being passed. The first ensures that there's at least 1 argument being passed. Then another check is made to see if a -c passed. If that's the case then the program makes sure that there is another argument after -c. If there is then the latter is passed directly to sub_11D5290 (which we'll look at later) else the programs terminates.
If there is not -c flag being passed, then all the arguments passed to "WinExec.EXE" are concatenated to the string cmd.exe /c and passed to sub_11D5290.
This translates to the following:
- If
dword_11D9B24is less than 2, the program exits. - Checks if the first command line argument is
-c:- If true, checks if
dword_11D9B24is at least 3. If not, returns -1 (exit). - Calls
sub_11D5290with the subsequent argument.
- If true, checks if
- If the argument is not
-c, constructs a command to execute viacmd.exe /cand callssub_11D5290with this command.
Now let's look at the sub_11D5290 function.
int __cdecl sub_11D5290(LPWSTR lpCommandLine)
{
struct _STARTUPINFOW StartupInfo; // [esp+0h] [ebp-54h] BYREF
struct _PROCESS_INFORMATION ProcessInformation; // [esp+44h] [ebp-10h] BYREF
GetStartupInfoW(&StartupInfo);
memset(&ProcessInformation, 0, sizeof(ProcessInformation));
if ( !CreateProcessW(0, lpCommandLine, 0, 0, 0, 0x8000000u, 0, 0, &StartupInfo, &ProcessInformation) )
return -1;
WaitForSingleObject(ProcessInformation.hProcess, 0xFFFFFFFF);
return 0;
}The most interesting thing for our case is that the lpCommandLine argument is passed directly to CreateProcessW. This means that anything we pass from the CLI either via the -c flag or other will be executed via WinExec by proxy.