an examination of string allocations: ie-9 edition chris valasek, director of security intelligence...
TRANSCRIPT
An Examination of String Allocations: IE-9 Edition
Chris Valasek, Director of Security IntelligenceIOActive@nudehaberdasher
An Examination of String Allocations: IE-9 Edition
An Examination of String Allocations: IE-9 & 10 Edition
An Examination of String Allocations: IE-9 to11 Edition
Chris Valasek, Director of Security IntelligenceIOActive@nudehaberdasher
Introduction
Chris Valasek• Director of Security Intel @ IOA• <3 Windows memory stuff• Car Hacking! • Pittsburgh PA USA• Chairman of Summercon• Fun Fact: I like cheese
Overview
• Brief history of Javascript string allocations in IE6-7
• JavaScript string changes in IE-9
• IE-9 Core JavaScript Methods
• IE-9 DOM Strings
• Premier: heapLib2
• Note: Non-comprehensive list
• Note: Algorithms seem to be the same for IE-10 and IE-11
Why?
• Nico’s APT talk at Blackhat USA 2010 mentioned the following:“IE 8 introduced a weak heap spray protection”
• There didn’t appear to be any public information explaining the statement
• Sotirov published “Heap Feng Shui” but no such information was available for IE-9 (Skipping IE-8 at this point…)
• Memory management makes me smile…then scream…then cry…then smile again.
Impact
• Browser exploitation requires knowledge of sizes / objects for subsequent allocation/de-allocation of those objects• For example: Use-after-free bugs, to be exploited without ‘pray-after-free’,
will require intricate knowledge of object sizes and subsequent allocations/frees
• Heap spraying still tends to be common during browser exploitation but has had limited updates since IE-8• See Corelan Team & Nico’s references in later slides
• Exploitation can take less time with added knowledge of JS and DOM objects
Requisite Reading
• Nico Waisman – “Aleatory Persistent Threat”http://www.immunitysec.com/downloads/APT_kiwicon.pdf
• Alex Sotirov – “Heap Feng Shui in JavaScript”http://www.phreedom.org/research/heap-feng-shui/
• Dowd, Smith, Dewey – “Attacking Interoperability” http://www.hustlelabs.com/stuff/bh2009_dowd_smith_dewey.pdf
History
History: I
• Heap spraying made wildly popular by Skylined in MS04-040• Wow, its been a long time
• Sotirov documented the allocation / de-allocation process• Concatenating strings could cause allocations (jscript!JsStrConcat)
• Creating substrings could cause allocations (jscript!JsStrSubstrCore)
• Freeing of chunks could be achieved by setting a string to NULL and performing garbage collection
• It was quite easy to make allocations in IE6-7
History: II
Each iteration of the loop would create a new copy of the string, storing it in the array
History: III
• The aforementioned method no longer worked in IE-8
• Corelan Team suggested some variations• https://www.corelan.be/index.php/2011/12/31/exploit-writing-tutorial-part
-11-heap-spraying-demystified/
• Nico also suggested a work around (that inspired this research)
History: IV
Substring? Array Assignment? Not really sure since I didn’t look at IE-8
IE-9 Strings
JavaScript Strings: IE-9
• Not just a simple bstr object anymore
• Concatenation and substring calls don’t mindlessly allocate memory
• Jscript9.dll has replaced jscript.dll• Jscript.dll is NOT loaded in IE-9
• Versions• Jscript9.dll 9.0.8112.16450 (might be a few versions off)
• Mshtml.dll 9.0.8112.16464
Core Methods
Core: ArenaLiteralString
• Js::ArenaLiteralString::New
• Base for static strings created in JS• Var a = “CHRIS”;
• Var b = new String(“Chris”);
• Var c = unescape(“%u9090”);
• Transformed as needed• Example: unescape() == Js::StringBuilderString::New()
• The strings are allocated from an arena, so you won’t see allocations for individual strings in default heap• Var a = “AAAABBBB” != malloc((a.length * 2) + 6) [Like it did in IE-6]
Core: ConcatString
• Js::ConcatString::New
• Stores pointers to the concat-er and concat-ee
• No longer will allocate per concatenation • We’ll see later how and were allocations occur
• The strings passed can be any JavascriptString• StringBuilderString, ArenaLiteralString, even another ConcatString
• Smells like:
Core: ConcatString cont.
The ConcatString objects come from pre-allocated, page aligned HeapBuckets.
Core: ConcatString cont. II
Pointers are stored instead of allocating/copying data.
Core: SubString
• Js::SubString::New
• Will expand the JavaScript string if need be• Allocations will come from PageAllocator, so completely controlled
allocations will not occur
• Holds references and will expand/flatten only 1x
• Smells like:
Core: SubString cont.
Core: Example
Core: Example Part I
• Events• Js::ArenaLiteralString::New with “%u9090%u9090%u9090%u9090”
• The string has yet to be unescaped at this point
• Also, the memory holding the string isn’t allocated from the default heap, instead it uses a page-based allocator for string objects
• Js::GlobalObject::EntryUnEscape• Convert the values to 0x9090 0x9090 0x9090
• Call the functions below….
• Js::JavascriptConversion::ToString
• Js::StringBuilderString::New
• As you see, this does NOT have a precise allocation from the default heap
Core: Example Part II
• Iterations1. ConcatString [LHS=>str_builder, RHS=>str_builder, length=>0x10]
• LHS => StringBuilderString | RHS = StringBuilderString
2. ConcatString [LHS=>str_builder, RHS=>str_builder, length=>0x20]• LHS => ConcatString | RHS = ConcatString
3. ConcatString [LHS=>str_builder, RHS=>str_builder, length=>0x40]• LHS => ConcatString | RHS = ConcatString
4. ConcatString [LHS=>str_builder, RHS=>str_builder, length=>0x80]• LHS => ConcatString | RHS = ConcatString
5. ConcatString [LHS=>str_builder, RHS=>str_builder, length=>0x100]• LHS => ConcatString | RHS = ConcatString
• After the 1st iteration ‘str_builder’ is now a ConcatString
• No allocation occur during this process• Also ConcatString->str == NULL
Core: Example Part III
• Events• Js::Substring::New passing the ConcatString created in our loop
• If str_builder->str == NULL { str_builder->GetSz } • This is the case, so Js::ConcatString::GetSz() will be called
• Js::ConcatString::GetSz() will call Js::ConcatString::Flatten
• Js::ConcatString::Flatten call Recycler::AllocLeaf
• Recycler::AllocLeaf check size
• If str_builder.length < 0x400 HeapBucket::SnailAlloc(Recycler, this, Round16(str_builder.length), 0);*This will allocate from the Recyler PagePool
• If str_builder.length >= 0x400Recycler::TryLargeAlloc(str_builder.length, this, Recycler, 0);*This can possibly trigger a call to VirtualAlloc, but won’t be exact*VirtualMemory Allocation granularity
• Again, not precise direct allocations from default heap…
Core: Example Part IV
• Events• Js::Substring::New passing the ConcatString created in our loop
• If str_builder->str == NULL { str_builder->GetSz } • This is the case, so Js::ConcatString::GetSz() will be NOT called
• Since our ConcatString has been flattened / copied in the previous call to “substring” it doesn’t need to happen again
• String allocation from the pool only happens once to avoid the need of multiple copies of the same string
Core: Conclusion
• Static strings are allocated from a page-aligned memory• i.e. var a = “CHRIS” does NOT directly hit the default heap
• JavaScript objects are allocated from HeapBuckets• i.e. ConcatString, SubString, etc
• HeapBucket is pooled memory which will only alloc from default heap in pages
• Much more efficient an allocations for substrings/concatenations
• While not officially ‘heap spray protection’, it does prevent previous methods from achieving their goal
• Are there still ways to get allocations from the default process heap with JS strings? • Hint: Yup
DOM Memory Management
DOM: Elements
• Most familiar piece of the Document Object Model
• Each tag is allocated from the default process heap
• Each tag also consists of a certain amount of bytes
• For example:• Anchor Tag “<A>” == 0x64 byte allocation
• Bold Tag “<B>” == 0x30 byte allocation
• Simple way to create elements statically or dynamically for precise allocations from the default heap
DOM: Elements cont.
• I’ve created a script that will attempt to pull the allocation call for each HTML tag in MSHTML.DLL
• Nico’s chart in his APT talk. Instead of re-creating I wrote a script
• It’s called “get_elements.py”
DOM: Attributes
• Element attributes are allocated directly (well, sort of) from the default heap
• They last the lifetime of the page (or until you remove them)• i.e. fully controlled
• Creates null terminated string• <string><2-byte NULL>
• They have a certain Variant type• See Dowd, Smith, Dewey paper
• Certain global attributes exist for all elements, such as ‘title’
• See mshtml_1.html
DOM: Custom Attributes
• HTML5 supports custom attributes
• For example: <h1 wonk-attr=“specialvalue”>Hello</h1>• Yes I know this breaks W3 standards. Should start with “data-”
• Above custom attribute with the name “wonk-attr”
• The value “specialvalue” will be allocated based on its string length from the default process heap!
• They last the lifetime of the page (or until you remove them)• i.e. fully controlled
• Creates your typical bstr object• <DWORD size><string><2-byte NULL>
• See mshtml_2.html
DOM: Attribute Shellcode
• Since we know that attributes can be used to directly allocate user-controlled amounts of data from the default process heap…
• Let’s have UTF-8 and UTF-16 be our friends
• ‘html_spray.py’• Python code to generate massive payload statically in HTML
• Gzip from the server, drastically shrinking the size, and send to client
• *Note: I haven’t not thoroughly tested this, only saw allocations working
• See ‘html_spray.html’
DOM: Static Attributes
• All the attributes we talked about in the last few slides would static. i.e. known before the DOM has been laid out
• Follow the call chain:• MSHTML!BASICPROPPARAMS::SetString
• =>MSHTML!CAttrArray::SetString
• => CAttrValue::InitVariant
• => MSHTML!_HeapAllocString
• _HeapAllocString will allocate the amount of bytes in the string from the default process heap and copy the data
• But I don’t wanna create all the elements before hand….
DOM: Credit
• Corelan Team had the right idea
• Certain attributes exist for all elements, such as ‘title’
• https://www.corelan.be/index.php/2013/02/19/deps-precise-heap-spray-on-firefox-and-ie10/
• There’s a reason this works really well• ‘title’ is a slightly different variant type as opposed to custom attribute
• Attributes are just another Variant type in IE• See Dowd, Smith, Dewey paper
Custom Attributes
Custom Attibutes: Creation
• I’m a learn by example type of guy….
Custom Attributes: Creation cont.
• Call to ‘setAttribute()’ will marshal the JavascriptString to a bstr used by the DOM• DispatchHelper::MarshalJsVarsToVariants
• This lazy allocation ensures that the PageAllocator is used for JS strings while the default process heap is only required when necessary, such as augmenting the DOM
• Dynamically Created Custom Attribute: Call chain• MSHTML!CAttrArray::SetAt
• => MSHTML!CAttrValue::InitVariant (Type 0x08)
• => MSHTML!EdUtil::FormsAllocStringW
• => OLEAUT32!SysAllocString
• => OLEAUT32!SysAllocStringLen
• => OLEAUT32!APP_DATA::AllocCachedMem
• That last one looks familiar!
Dynamic Attribute Assign: Sidebar
• Not all attributes are created equal• Global Attribute (title, class, lang, etc)
• MSHTML!CAttrArray::SetString
• => MSHTML!CAttrArray::Set
• => MSHTML!CAttrValue::InitVariant (Type 0x31)
• => MSHTML!_HeapAllocString
• You can see, for instance, that the ‘title’ attribute would bypass the cache allocator, directly accessing the default process heap
• Good work Corelan Team, just wanted to point out intricacies ;)• Hint: There are probably more. Look for XREFS to _HeapAllocString
Custom Attributes: Destruction
• Can we free memory at will too?
• Sure we can!
• In the previous example we saw that ‘setAttribute(name, value)’ was used to allocate memory
• All we have to do is ‘setAttribute(name, null)’ and the value will be freed! • MSHTML!CAttrArray::SetAt
• => MSHTML!CAttrValue::Free
• => kernel32!HeapFree
• => ntdll!RtlFreeHeap
• Now we have a plan for heap massaging!
heapLib2
heapLib2: Overview
• I saw that dynamic custom attributes were allocated from OLEAUT32!APP_DATA::AllocCachedMem
• After investigation, I realized the allocator hasn’t changed since IE-6
• So long as I can refactor the plunger technique written by Sotirov years ago, we can have precision allocations
• See: http://www.phreedom.org/research/heap-feng-shui/
• Steps• Populate cache before freeing
• Clear cache before allocating
• Also, since we can create large strings in JS and marshal them to the default process heap, we can heap spray like it’s 2004
• Note: There is overhead with creating attributes malloc(0x60) being one of many….
heapLib2: Example
heapLib2: Demo
Conclusions
Conclusions
• Precise allocations are nearly impossible to achieve directly from Javascript in IE-9
• This seems like ‘heap spray protection’ but I think was more of an architecture change• Someone from MSFT let me know if I’m wrong
• To make allocations directly from the default process heap one can leverage the DOM
• I found that custom attributes were a nifty way of doing this
• heapLib2 permits allocations of arbitrary sizes and provides functionality to do easy heap sprays
• There is a bunch more research to be had• The Recyler is really neat / confusing
Continuation!
• I’ll be releasing a white paper at some point
• Much more information about DOM / JS objects
• Detailed notes: Recycler, HeapBuckets, PoolAllocator, etc
• Follow me on Twitter (@nudehaberdasher) and check the IOActive blog as I’ll be putting slides, examples, and heapLib2 for public download
• Alex Sotirov should get most of the credit as he figured all this stuff out years ago, I just augmented it to work w/ IE-9 – IE-11
• Thanks!