Recently there were several new posts (FSecure Post and Peter Ferrie) about updates to the Necurs malicious kit which in essence is based on the malicious driver with sole purpose to protect other malware from security products. The updated version is now shipped as an embedded self-contained launch-and-forget shellcode which will drop the appropriate driver according to the underlingg OS and on successful deployment will start immediate protection. The authors of the kit will supply the client several APIs that could be used to operate the driver.
I knew that for driver loading on OSs above Vista, it was using privilege escalation vulnerability. It was interesting to understand how that exploit was used in Necurs’ case and as I was unable to find a fine explanation, I studied it by myself . Here I present my findings for the matter.
As already mentioned,
Necurs operates as a 3rd party driver – meaning, the user will need
Admin rights to actually use it. Being a 3rd-party product, it needs to operate on verity of Windows OSs:
- Windows XP – by default the logged-in user is already
Admin, so no problem here.
- Vista and above – the user will probably have UAC enabled which will prevent driver loading.
The by-pass is based on changing the security token of the malicious process by the “powerful” one which is borrowed from the
system process in kernel space. This task is achieved in the following way:
- kernel APIs resolution – as the exploit shellcode will actually be executed in the kernel space, it will need the appropriate API addresses to do so. Those APIs are resolved by extracting the APIs’ RVAs from the
ntoskrnl.exefile and finding the actual
ntoskrnl.exebase address (using
- registry preparation – craft registry data in the way, that will trigger the CVE-2010-4398 exploit as explained in the original article by calling
- exploit shellcode execution – get security token (
PsReferencePrimaryToken) from the initial system process (
PsInitialSystemProcess) and replace the current process’s (
IoGetCurrentProcess) token with the new one (Fig. 1). Once token replaced, the shellcode will return to the original execution flow.
Figure 1: Grant Administrator privileges to current process
Multi-OS support was achieved by using predefined offsets to the
Token member in the
EPROCESS structure (Fig 2).
Figure 2: Multi-OS support
Return from exploit shellcode
Once the exploitation was done, the exploit shellcode will try to return to the original execution flow, as if nothing has happened (in other words,
internal_func_b finished its execution properly – see below). For the explanation, I’ll use arbitrary symbolic addresses to describe the following call stack and 32 bit shellcode version:
To understand the trick, let’s look how
ESP changes from the call
EnableEUDC till the stack overflow at
RtlQueryRegistryValues. The overflow will overwrite the return address of
internal_func_b (for explanation please read here).
ESP undergoes the following changes and this “picture” of
ESP is what exploit shellcode will see (Fig 3):
|ESP address||ESP pointed data||Remarks|
|0x0||1|| parameter for
|0x4||0xae1efe|| return after
|0x14||0xbf81b8d0|| return after call to
|0x3C||local vars|| local params in
|0x48||reg value||this is what exploit shellcode sees|
Figure 3: Return from exploit shellcode
token_fix global variable will fix the
ESP in a such way, so it will point to the
internal_func_a stack frame. Finally, the return address of
internal_func_a is used to return to the original flow of execution (Fig 4).
Figure 4: Searching for return address
Once found, the flow will land in
internal_func_a (Fig 5).
Figure 5: Execution after exploitation
Now, the running process has
Administrator account rights, so the only simple thing left is just to re-launch itself, drop and load the driver. Just to note, that on 64 bit systems, there are similar flow of events occur.