The Butterfly Effect and the “Shellcode Storm” Chun Feng Microsoft Corporation Tiny change Large-scale alterations • • • • CVE-2010-1297 CVE-2010-2884 CVE-2010-3654 CVE-2011-0609 Clean SWF file 1 byte change Exploit 70 Number of Reported Adobe Flash Player Related Vulnerabilities 60 60 50 42? 40 30 20 20 22 14 10 0 2008 2009 2010 2011 User Developer ActionScript3 AVM (ActionScript Virtual Machine) Compile ByteCode Verifier MIR Code Generator MD Code Generator Native Code (x86, PPC) JIT Compile ActionScript 3: public function add8(a:int): int { return a+8; } MIR (intermediate machine independent language): @5 arg 0 @10 ldop 4(@5) @22 def @10 @37 use @22 [1] @38 imm 8 @42 add @37 @38 Adobe Byte Code (stack machine): pushscope getlocal_1 pushbyte 8 add returnvalue X86 native code: mov eax, 16(ebp) mov edx, 4(eax) mov -84(ebp), edx mov ecx, -84(ebp) add ecx, 8 mov -76(ebp), ecx mov eax, -76(ebp) Time: Early June, 2010 Adobe Flash player version <= 10.0.45.2 Adobe Reader version <= 9.3.2 Sample contains 0-day exploit hosted on a webpage (malformed SWF + JavaScript heap spray) 1 byte changed in function: Public RadioButton.configUI ( ):void 4F D2 02 00 callpropvoid fl.controls:LabelButton.configUI, 0 40 D2 02 00 newfunction TextInput:drawBackground • Pageguard exception – Trouble with Ollydbg; use Windbg, type command “sxi gp” • 15 seconds timeout – Less intrusive debugging - can’t use single step / trace! • Understand JIT compiled code 1. How is the control transferred to shellcode? 2. The root cause of this vulnerability 1. Remove the JavaScript heap spray code to cause a crash rather than have shellcode executed 2. Locate the instruction causing the crash Problems: • • May not be 100% accurate Doesn’t work if the heap spray code is encrypted Assumption: Transferred via call instruction The return address for this call will be pushed onto the stack 463bd28d ff510c 463bd290 83c40c call dword ptr [ecx+0Ch] add esp,0Ch ;[4198000c]=0c050c05 Dump stack at the 1st instruction of shellcode (address 0c050c05) 463bd290 41980000 00000000 0013e364 At the 1st instruction of the shellcode, the return address is at the top of the stack Problems – we are unable stop there: • The address of 1st instruction of the shellcode is not predictable • Single step doesn’t work (15 secs timeout) or al, 5, // … or al, 5 or ; pseudo NOP start ESP = ESP0 ; pseudo NOP end ESP = ESP0 al,00C; 1st instruction of shellcode ESP= ESP0 // ... more code (more bytes pushed onto the stack) Call URLDownloadToFileA; ESP = ESP1 463bd270 mov ecx, dword ptr [ebx+34h] ; [431492b4]=4313e080 463bd276 mov edx,dword ptr [ecx+8]; [4313e088]=42fb208a 463bd27b mov ecx,dword ptr [edx+284h]; [42fb230e]=41980000 463bd28d call dword ptr [ecx+0Ch]; [4198000c]=0c050c05 1. How is the control transferred to shellcode? 2. The root cause of this vulnerability 463bd270 mov ecx, dword ptr [ebx+34h] ; [431492b4]=4313e080 463bd276 mov edx,dword ptr [ecx+8]; [4313e088]=42fb208a 463bd27b mov ecx,dword ptr [edx+284h]; [42fb230e]=41980000 463bd28d call dword ptr [ecx+0Ch]; [4198000c]=0c050c05 • No document for JIT compiler • No PDB symbol file available Revealed by http://jpauclair.net Windows: C:\Documents and Settings\<username>\mm.cfg AS3Verbose = 1 Details of JIT runtime trace: C:\Documents and Settings\<username>\Application Data\Macromedia\Flash Player\Logs\flashlog.txt 26:callpropvoid fl.controls:BaseButton::drawBackground 0 @63 ldop 16(@62) @64 ldop 812(@63) …… @63 ldop 16(@62) 060BD6E4 mov eax, 16(ebx) active: eax(63-64) ebx(62-69) edi(2-142) @64 ldop 812(@63) 060BD6E7 mov ecx, 812(eax) active: ecx(64-70) ebx(62-69) edi(2-142) Each JIT compiled function has three parameters: func(MethodEnv*, int argc, uint32 *ap) For example: RadioButton.configUI ():void • argc = 0 • ap[0] = RadioButton instance (“this” pointer) protected function drawBackground():void { var bg:DisplayObject = background; var styleName:String = (enabled) ? "upSkin" : "disabledSkin"; … } 463bd270 mov ecx, dword ptr [ebx+34h] ; [431492b4]=4313e080 463bd276 mov edx,dword ptr [ecx+8]; [4313e088]=42fb208a 463bd27b mov ecx,dword ptr [edx+284h]; [42fb230e]=41980000 463bd28d call dword ptr [ecx+0Ch]; [4198000c]=0c050c05 The control transfer is in JIT compiled code for TextInput.drawBackground( ) TextInput.drawBackground(MethodEnv*, int argc, uint32 *ap) 463bd1bc 463bd1bd 463bd1bf 463bd1c5 463bd1c8 push mov sub mov mov ebp ebp,esp esp,50h eax,dword ptr [ebp+10h] ; [0013e290]=43169301 eax,dword ptr [eax]; [43169301] = ??? (Unaligned pointer) In TextInput.as TextInput.draw( ) calls TextInput.drawBackground( ) In JIT compiled code TextInput.draw( ): 463bcbdb 83c801 or eax,1 … call TextInput.drawBackground( ) ; make it unaligned! ; Overloaded ! After 1 byte change => newfunction TextInput.drawBackground Internal representations Lowest 3 bit used for type 0x43169301 Type: Object Actual Value: 0x43169300 RadioButton.configUI( ) 1 byte changed TextInput.drawBackground ( ) func obj. created TextInput.draw( ) emits the wrong code / parameter when calling TextInput.drawBackground( ) (which has been “overloaded”) TextInput.drawBackground( ) doesn’t handle it correctly when “enabled” property is referenced Invalid memory accessed, shellcode executed 1. How is the control transferred to shellcode? 2. The root cause of this vulnerability Time: Early Nov 2010 Adobe Flash Player version <= 10.1.85.3 Adobe Reader version <=9.4 Sample containing 0-day exploit distributed as a PDF file with a malformed SWF embedded 16 22(0x16) RadioButtonGroup 0x07 0x02 0x07 07 // [[17]CONSTANT_QName // NsIndex = 2(0x02) // NameIndex = 7(0x07) Button MultiName constant pool: NameIndex changed fl.controls.RadioButtonGroup -> fl.controls.Button RadioButtonGroup.set_groupName -> Button.set_groupName Invalid memory accessed, shellcode executed Time: March 2011 Adobe Flash Player version <= 10.2.152.33 Adobe Reader version <= 10.0.1 Sample containing 0-day exploit distributed as an Excel file with one SWF file embedded Clean 4CC4 10 07 00 00 … jump loc_4CCF 4CCF 80 2C coerce com.greensock.core.SimpleTimeline Malicious 3EA1 10 29 00 00 jump loc_3ECE …. 3ECE 66 D6 02 getproperty <namespace_set>.paused Jump destination is changed! Shellcode payload: • Downloads an encrypted PE file • Decrypts it (xor 0x95 skipping 0x00 and 0x95) Decrypted PE file(Win32/Poison): • Keylogger • Backdoor: Receives shellcode rather than command Pros: • Thin client – just executes whatever receives • Easy to implement new command • Payload code not written on disk Cons: • Coding complexity – coding in shellcode • Platform dependent Shellcode matryoshka Shellcode decrypts PE file from PDF stream Shellcode(in decrypted PE file) decrypts a DLL from resource Shellcode(in decrypted DLL) decrypts and loads a PE file(Win32/Hupigon, aka Win32/Pigeon) • Threats have been targeting Adobe flash player since it is popular and platform-independent • 1 byte change in SWF may cause significant consequences. Attackers have been using dummy fuzzing to find vulnerabilities • The attacks on Adobe Flash Player are likely to continue to be prevalent in the future