Updated March 25: added a proof-of-concept video
As part of our research, we analyze the intricate relationship between Anti-Virus and Operating Systems (OS). During this process, we came across a vulnerability in AVG Internet Security 2015 build 5736 + Virus database 8919 released January 13th 2015.
The vulnerability? The affected AVG product had allocated a memory page with RWX permissions at a constant predictable address. This allocation had occurred for each created user-mode process.
This flaw significantly diminished the efforts that the threat actor needed in order to exploit a third party application. Effectively, this vulnerability enabled a threat actor to exploit any old vulnerability (for instance, as of 2010) in a 3rd party application in order to compromise the underlying Windows system using a multi-stage process.
We had responsibly disclosed this issue to AVG and we’re left to compliment AVG for their handling of the issue. The way that AVG approached their fix should act as a positive case-study to other vendors when it comes to their patch fixes. AVG was extremely quick to respond to this flaw and had released a corresponding patch on Thursday, March 12th– just two days after our disclosure. To err is human and we can always expect code flaws. However, AVG’s demonstrated response should set the bar for other vendors when it comes to patching their systems.
This entry details the revealed (now-patched) vulnerability and provides a corresponding Proof of Concept.
The vulnerability resided in the way AVG performed its kernel injection to load a DLL into the process space of a third-party application.
Each time a user-mode process is created, AVG’s device driver – avgidsdriverx.sys – receives a notification (through the PsSetCreateProcessNotifyRoutine callback), allocates memory in the target process, copies a code stub that will load the DLL to the newly allocated memory, and executes it.
Let’s further detail kernel-mode process injection:
Step 1: Memory allocation in the target process
In order to inject the required code stub, AVG’s Internet Security product allocated a memory page with RWX permissions.
Figure 1: The allocation of a RWX memory page at address 00010000 (Win 7 32-bit)
As can be seen in Figure 1, AVG Internet Security 2015 allocated, on every created user mode process (in this case, AcroRD32.exe), a RWX memory page at address 00010000 address (Win7 32 bit).
Figure 2: ZwAllocateVirtualMemory from avgidsdrvierx.sys
What does this call do? To quote Windows:
“Virtual memory allocations that are made by an application can have their base address assigned in one of three ways: bottom-up, top-down, or based. The bottom-up method searches for a free region starting from the bottom of the address space (e.g. VirtualAlloc default), the top-down method searches starting from the top of the address space (e.g. VirtualAlloc with MEM_TOP_DOWN), and the based method attempts to allocate memory at a supplied base address (e.g. VirtualAlloc with an explicit base). In practice, the majority of the memory that is allocated by an application will use the bottom-up allocation method, and it is rare to see applications use the based method for allocating memory.
Prior to Windows 8, bottom-up and top-down allocations were not randomized by ASLR. This meant that allocations made through functions like VirtualAlloc and MapViewOfFile had no entropy and could therefore be placed at a predictable location in memory (barring non-deterministic application behavior). While certain memory regions had their own base randomization, such as heaps, stacks, TEBs, and PEBs, all other bottom-up and top-down allocations were not randomized.”
Step 2: Code stub copying
The small code stub is actually the code that loads AVG’s dll – avghookx.dll – into the target’s process virtual space.
Typically, Windows’ Kernel32.LoadLibrary API is used for this. AVG, however, directly called the ntdll.LdrloadDll API.
Figure 3: The stub loads the DLL through the LdrloadDll API
Step 3: Injected payload – code execution
In order to execute the newly allocated code stub, avgidsdriverx.sys used the Asynchronous Procedure Call (APC) technique.
To explain APC, I’ll quote an explanation I was fond of (reference below):
“APCs are a Windows functionality that can divert a thread from its regular execution path and direct it to execute some other code. The APC allows user programs and system components to execute code in the context of a particular thread and, therefore, within the address space of a particular process.
APCs come in three modes:
- Special kernel mode APC: execute kernel mode code at APC IRQL.
- Regular kernel mode APC: execute kernel mode code at PASSIVE IRQL.
- User mode APC: call user mode code.”
For detailed information on this technique, please refer to:
- http://rsdn.ru/article/baseserv/InjectDll.xml (Russian)
AVG uses the user-mode APC.
Since the memory allocation was on a constant address and with RWX permissions, a threat actor developing an exploit was able to leverage this AVG vulnerability in order to remove any guesswork about the address space layout of the process.
Consequently, a threat actor that had exploited a vulnerable third-party application and had gained control of that application’s instruction pointer would have been able to copy the malicious code to AVG’s allocated RWX page and directly execute the malicious code.
It is important to note that in order to leverage this vulnerability there was no need to bypass the underlying Windows’ Address Space Layout (ASLR) and Data Execution Prevention (DEP) protections. Effectively, the AVG vulnerability acted as the conduit to defeating these defenses.
For those that would like a short recall of these defenses, and a reminder of how severe it is to bypass these protections, here is a short overview of these two protections:
Data Execution Prevention (DEP) –
The purpose of DEP is to prevent attackers from being able to execute data as if it were code. In practice, this means that an attacker cannot directly execute code from the stack, heap, and other non-code memory regions. Due to DEP, exploitation techniques like heap spraying (of shellcode) or a classic stack overflow (returning into the stack) are not immediately possible.
ASLR (Address Space Layout Randomization) –
ASLR prevents an attacker from making assumptions about the address space layout of a process when developing an exploit. Common assumptions that threat actors make include, for instance, loading modules at a predictable address or existing readable/writable memory at a specific address across all PCs. By randomizing the address space layout, an attacker cannot directly and reliably leverage code in loaded modules.
Triggering the Vulnerability using a 4-Year Old Vulnerability
As a Proof of Concept example, we used the Adobe PDF Reader v.9.3, vulnerable to CVE-2010-0188.
Figure 4: Traditional EIP overwrite
It’s important to see that were an attacker using a regular exploitation scenario, the attacker would require to build a ROP chain after overwriting EIP. The ROP chain would require first allocating a new memory, with PAGE_EXECUTE_READWRITE protection, followed by a copy gadget that will copy the attacker’s shellcode to the newly allocated space.
However, when AVG was installed, all the attacker required was to copy the shellcode to AVG’s previously allocated memory and execute it from there (we used corelan’s mona.py to find these gadgets).
Figure 5: The ROP chain
- AVG Internet Security 2015 (build5736) + Virus database 8919 released January 13th
As mentioned earlier, we have responsibly disclosed this vulnerability to AVG. They have fixed and distributed the patch to their users within two days of disclosure on build 5856 of the affected product.
AVG’s response and rapid fix is amazing – we should all take our hats off and learn from them.
- Windows Vista
- Windows 7 32 bit
- Windows 7 64 bit
- Windows 8 and onwards. We’d like to note that although the AVG vulnerability existed in these systems as well, Microsoft had introduced its Bottom-up and Top-down Randomization mitigation starting with Windows 8. This mitigation essentially nullified leveraging this vulnerability.
To explain the Bottom-up and Top-down Randomization technique, it’s time to once again quote Microsoft:
“Starting with Windows 8, the base address of all bottom-up and top-down allocations is explicitly randomized. This is accomplished by randomizing the address that bottom-up and top-down allocations start from for a given process. In this way, fragmentation within the address space is minimized while also realizing the benefits of randomizing the base address of all memory allocations that are not explicitly based.”
Proof Of Concept
Collaborating with researchers and working with them should be a top priority for vendors, essential to minimize the window of exploit opportunity.
Additionally, this vulnerability demonstrates the problems in the security eco-system. On the one hand, Microsoft invests loads of resources in defenses, mitigations and enhancements to strengthen its system against compromise. One the other hand, there’ll always be some oversight in applications. Unfortunately, vulnerable third party applications can lead to the bypassing of these defenses.
As the security industry, we simply cannot rely on the defense of an underlying system. Rather, we need to consider our systems as one eco-system where each affects the other.