In the previous blog post, I discussed a modest technique to “fix” the default process heap in order to prevent various Windows API functions from crashing, by replacing the corresponding field in PEB (Process Environment Block) with a freshly created heap. This of course assumes that the attacker has already achieved arbitrary code execution, or is at least able to use ROP and knows the base addresses of some vital system DLLs. It is likely the last exploitation technique one would use before gaining full control over the vulnerable application or system, and was indeed used by Gynvael and me while wrapping up the exploitation of the easier challenge during this year’s DEF CON CTF qualifiers which took place in May.
However, before we could even reach that stage, I had to overcome a few other significant obstacles, the hardest of which was converting the available primitives into a hijacked control flow. Following hours of trying to reproduce the same heap layout on the organizers’ and my own platform (exploiting the bugs was in fact the easiest part), I finally managed to achieve close to arbitrary memory read and write capabilities. By that point, I knew the location of the heap, the challenge image base and NTDLL.DLL image base, where I could freely read from and write to. On the other hand, the task itself did not make it easy to get controlled EIP even with such powerful primitives, as it didn’t store plain-text function pointers, virtual objects or any data directly controlling the execution flow on either the heap or in static memory. This meant that a generic technique had to be used instead.