APT检测之恶意office文件检测原理

          **【Office文件基于CVE漏洞的检测】**

注:以office文件作为载体的攻击方法与沙箱检测恶意文件的基本原理。
缓存区溢出攻击是一种常见的攻击方法,随着攻防的发展,现在对于缓存区溢出已经有一些防御的技术。下面就对office的缓存区溢出写自己的理解。
1 首先,传统的缓存区溢出攻击方法
程序执行的参数、变量值会加载到栈里面去,执行完后会返回一个指令地址赋值给寄存器EIP,如果攻击者利用这里攻击(修改)EIP的值,(如)把这个值修改成了esp(堆栈指针寄存器)的地址,那么cpu下来会根据EIP的指示call堆里面的值(这个值可能就是恶意代码的开始地址),这里就出问题了、达到了攻击者的目的,这就是缓存区溢出攻击。因为攻击者已经突破了程序本身执行的空间,改变如程序执行正常流程。例:程序本身分配的空间是10byte,那么执行完10byte就会返回下一个操作指令的地址给EIP,但是攻击者写入的数据为15byte(多余的部分有payload),那么最后的这5byte里的值会覆盖eip的值,如果eip的值被覆盖成了调用esp的值,那么cpu会跳回来继续执行栈里的代码,就会执行攻击者策划好的payload。
程序在调用一个函数的时候,会首先将函数参数以逆序的方式push到栈中,然后调用call指令跳转到该函数,call的操作是将当前函数返回地址入栈,然后再跳转到调用的函数地址。假如调用了一个函数int add(int a,int b)
那么在栈中的分布就是 [b,a,函数返回地址]
跳转到调用函数后,调用函数在栈上继续分配临时遍历等各种操作后,会执行ret返回原函数。
APT检测之恶意office文件检测原理_第1张图片
这就是栈,栈帧代表一个函数所占用的栈空间。
看上图,假如有段缓冲区在局部变量1的位置,假如有任意操作对缓冲进行写操作,从低地址写向高地址,如果超过缓冲区的位置,就会覆盖返回地址1的位置。
那么在main函数执行ret的时候,便读取到错误的返回地址1到eip中,从而改变程序流程,达到控制eip的目的。
绝大数情况下程序会崩掉,因为返回到一个不可知的位置,指令不能执行,操作系统会接收异常,调用默认异常处理程序,这时候通常会关掉程序,除非你做了异常处理。
一般的攻击操作会将shellcode填到返回地址后面的位置。
但是返回地址填什么却不好确定,因为栈的内存位置是不确定的。
所以这个时候会有一个jmp esp操作,esp 寄存器是指向栈顶的位置。
Jmp esp对应的的机器码是0xff e4。
所以返回地址就覆盖一个对应位置是0xff e4的地址。
比如图形界面的程序都会加载一个库user32.dll,这个库加载的地址还是固定的,所以在内存0x7774fb83(win8)的位置就是jmp esp机器码。
这时候栈的分布就是[0x7774fb83,[一段shellcode],**]
程序在返回的时候会执行jmp esp,也就是跳转到shellcode中,从而攻击成功。

2 其次,也就现在的office堆喷技术ROP。(有了ASLR+DEP的保护技术—-就是默认不执行堆栈中的代码)传统攻击就被防御了。
But,ROP的堆喷方法出来了,现在payload不能再堆栈里执行了。攻击者通过堆喷的技术去调用外部的系统库(dll)去完成自己期望的执行结果。
这里的dll基地址起初是固定的,但是现在多是可变的(动态库),那么攻击者想通过堆喷去调用特定的库函数、执行特定的动作就要大量的尝试,尝试到需要调用的dll函数的基地址,然后调用该dll函数完成payload动作。

后来系统防御措施升级。
防御措施一,DEP(栈区不可执行)
原来的shellcode需要放在栈中,执行也在栈中,后来系统将栈内存标记为不可执行,那么即使你缓冲区溢出也不能执行shellcode。
所以经典的jmp esp的方式在开启dep后失效。
既然栈区不可执行,后来发展成另一种攻击Rop。
Rop攻击由return-into-libc发展而来。
return-into-libc就是将之前的返回地址覆盖成某个系统api的地址,比如WinExec的地址,在地址之前放入参数,那么也是可以执行一个api,绕过了DEP,因为栈中并没有执行代码。
但是return-into-libc功能有限,很难造成一个完整的攻击。
Rop就是利用系统已经存在的指令片段进行组合进行攻击。
指令片段就是就是之前说的类似于jmp esp这样的地址。
先贴一段由mona工具生成的一段rop链
* [ Ruby ] *
def create_rop_chain()
# rop chain generated with mona.py - www.corelan.be
rop_gadgets =
[
0x788d835f, # POP EAX # RETN [msxml5.dll]
0x65001268, # ptr to &VirtualProtect() [IAT VBE6.DLL]
0x65194cde, # MOV EAX,DWORD PTR DS:[EAX] # RETN [VBE6.DLL]
0x788e4a48, # XCHG EAX,ESI # RETN [msxml5.dll]
0x78854775, # POP EBP # RETN [msxml5.dll]
0x6501e2f7, # & jmp esp [VBE6.DLL]
0x65150c9f, # POP EBX # RETN [VBE6.DLL]
0x00000201, # 0x00000201-> ebx
0x6509a89e, # POP EDX # RETN [VBE6.DLL]
0x00000040, # 0x00000040-> edx
0x652190d4, # POP ECX # RETN [VBE6.DLL]
0x789240ea, # &Writable location [msxml5.dll]
0x65053d0b, # POP EDI # RETN [VBE6.DLL]
0x78853403, # RETN (ROP NOP) [msxml5.dll]
0x78913be5, # POP EAX # RETN [msxml5.dll]
0x90909090, # nop
0x650f03bc, # PUSHAD # RETN [VBE6.DLL]
].flatten.pack(“V*”)
return rop_gadgets
end
每一个地址都是指向系统模块的指令片段,这些指令片段都是有一定的规则的。
这些指令片段称之为gadget。
每个gadget都是以retn结尾,且指令个数不超过5个。
Retn结尾保证执行完指令能返回回来,指令个数不超过5个是因为过多指令会影响rop链的拼凑。
这样栈中并没有执行指令,都是借助已有的指令进行执行。
有了rop攻击之后,系统又开启了另一项防御
ASLR(基址重定位)
Rop攻击需要依赖gadget地址,都是指向系统中的各种模块中间的地址。
开启ASLR之后,dll的基址随机,那么之前指向可用的gadget地址变得不可预测。
所以ASLR用来防御一部分rop。
当是在office中,加载的模块并不是所有的模块都支持aslr.
所以rop利用还是可以的,但是利用难度加大。

我们沙箱检测堆喷的技术原理是:
检测样本连接或是尝试连接dll的数量,这个数量的值越大就说明是rop的概率就越大,现在检测阀值是20,如大于等于20就判定为堆喷类型的攻击。
堆喷的原理简要来说就是用大量的滑板指令(不影响shellcode的指令)大量的填充内存空间,从而覆盖返回地址或者虚函数地址,然后很大几率会跳转到滑板指令上,然后在大量滑板指令最后执行shellcode。
但是office堆喷是一种特殊类型的堆喷,称之为ActiveX spary,他的存在并不是为了填充滑板指令,而是作为一种payload(载体)的存在。
主要原理就是office中自定义加入activex控件,承载分段的shellcode,然后放了很多个activex控件,每个activex控件修改成自定义的大小(通常是2M)
一般的操作进行ActiveX spary,然后由rop将shellcode拼凑,再执行shellcode。

简要检测原理:
1.shellcode部分
在进程内存中进行扫描,使用libemu,原理即一段字节码在getpc位置向后可以完整被翻译成汇编且能正确执行100步报shellcode。
Ps:getpc 自定位指令地址(call or fstenv)
误报处理:
Getpc位置后300计算熵值>5.3(目前)才报。
2.Rop
连续发现8个gadget,相邻gadget不超过14,
或者发现关键gadget,已发现gadget超过4,报rop。
误报处理:
已发现的rop链如果满足 [递增序列],[相同最后一个字节],[最后一个字节在相差在0xff以内],gadget来自于一个dll的多个版本,则不报
3.堆喷
进程内存>80M,扫描大于1M的内存块,检测内存块固定位置的特征值,
特征值>=20,报堆喷
4.奔溃和内存过大异常
判断标题+按钮或者标签文字

你可能感兴趣的:(网络安全-APT,apt,漏洞,沙箱检测,恶意文件)