欢迎来到 嗅灵易学

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

[原创windows漏洞及其防御方法简单总结

[原创windows漏洞及其防御方法简单总结

1.栈溢出

     通过栈溢出修改局部变量

     修改函数返回地址

    缓冲区溢出执行代码植入

2.shellcode:用来统称缓冲区溢出攻击的植入代码

    2.1 exploit:针对特定漏洞开发的代码,关心如何淹没返回地址,获取进程的控制权

    2.2 使用jmp esp覆盖对应的返回地址,使用jmp esp 相当于将eip的值设置成esp的值,由于esp寄存器在函数返回之后不会被溢出数据所干扰,且始终指向放回地址之后的位置(由于esp在返回时仍然指向栈区,jmp esp之后,处理器会返回到栈区函数返回地址之后的地方)。以我们可以通过跳板的方法动态定位shellcode。可以不止shellcode在淹没函数返回地址之后,继续淹没一片栈空间,将缓冲区前边一段地方的数据用任意数据填充,把shellcode恰好摆在返回地址之后,这样jmp esp指令执行之后会恰好跳进shellcode(缓冲区溢出没有修改过esp的值).

    2.2 缓冲区的组织一般使用x09090来填充缓冲区,即使不能跳转到正确的位置,跳转到nop指令也能正常执行到shellcode处,淹没返回地址的数据,跳转指令的地址,shellcode的地址,还可以是一个近似的地址。把shellcode布置在缓冲区之后就不用担心被压栈数据破坏。可以通过抬高栈顶保护shellcode.

    2.3可以使用其它跳转指令,比如mov eax,esp ;jmp eax等指令也可以进入,也可以不使用跳转指令,增大shellcode面积,提高命中率。

    2.4 shellcode编码:有时候shellcode会受到限制,首先字符串会对null字节进行限制其次函数还要求所有的shellcode 必须为可见的ascll字符或者unicode字符,基于特征的ids(入侵检测)也会对shellcode进行检查,先精心设计逻辑,然后对shellcode进行编码,使其内容达到限制要求。

3.漏洞测试平台msf(metasploit frame work)简介

    触发漏洞,选取shellcode,重要参数设定,选用编码,解码算法。msf时一种框架,它对漏洞利用几个相对独立的过程进行了很好的封装,把一次入侵过程简化为多若干模块的选择与组装,对各个环节进行了封装,模块化,标准化。

4.堆溢出利用

    4.1 堆与栈的区别:

    栈空间由系统维护,栈变量在使用的时候不需要额外的申请系统。堆是在运行的时候动态分配的。用堆指针来操作申请得到相应的堆空间,使用完成后要释放相应的堆,否则会造成内存泄露。

    4.2 堆溢出的利用

    double shoot技术:利用精心构造的数据取溢出下一个堆块的块首,改写块首中前向指针和后向指针,然后再分配,释放,合并等操作发生时获得一次向内存任意地址写入任意数的机会。把向任意地址写入任意数据的机会称为dword shoot,不但可以控制相应的目标,还可以劫持进程,运行shellcode.

常用的目标:内存变量,代码逻辑,函数返回地址,攻击异常处理机制,函数指针,peb线程同步函数入口地址

5.SEH

    由于seh在栈内,可以溢出缓冲区的数据有可能淹没seh,把seh构造为shellcode的起始地址,溢出后的栈帧或者堆块可能发生异常。当触发异常的时候就会把shellcode当作异常处理函数执行,异常处理和堆分配机制类似,会检测进程是否处于调试状态,如果直接使用调试器加载程序,异常处理会进入调试状态下的处理流程。主要关键步骤就是确定栈中的seh回调句柄的偏移,然后布置缓冲区,精确淹没这个地址,将该句柄改为shellcode的起始地址。

也可以利用堆溢出攻击将seh异常处句柄改为shellcode地址。也可以攻击peb中的函数指针。exitprocess()是利用通过存放在peb中的一对指针来调用

这两个函数的,如果能够把peb中的这对指针改成shellcode入口地址,那么程序最终结束的时候,exitprocess()将启动。


6.攻击c++虚函数

     虚函数的虚表

    1.成员函数用virtual声明的时候称为虚函数,一个类中可以有多个虚函数,虚函数的入口地址保存在虚标中,使用虚函数的时候先通过虚标指针找到虚表,从虚表中取出最终的函数入口地址进行调用。虚表指针保存在对象内存空间终,紧接虚标指针的是其它成员变量,虚表指针只有通过对象的指针引用才能表现出它的动态调用的特性,如果对象变量发生了溢出,有机会修改对象终的虚表指针或者修改虚标中的虚函数指针,那么在程序调用虚函数的时候就会跑去执行shellcode。由于虚标在成员函数之前,溢出只能向后修改数据,所以这种方式在“栈溢出”场景种有一定的局限性。对象内容空间位于队中。如果存在多个对象连续覆盖还是有机会的,对于堆溢出的double shoot的利用场景攻击虚函数会相对更加容易一些,修改虚标指针或者直接修改虚函数指针都是一个不错的选择。


7.堆喷雾 heap spray:堆栈协同攻击

    溢出的最终目标就是要能够获得eip,在使用heap spray的的hi后,一般会将eip指向堆区0x0c0c0c0c位置,然后用javascript申请大量的堆内存,并且用包含着0x90和shellcode的内存片覆盖这些内存。通常,javascript会从内存低地址向高地址分配内存,申请超过200M的内存后,0x0c0c0c0c机会被含有shellcode的内存片覆盖,只要内存片种的0x90能够命中0x0c0c0c0c的位置,shellcode就能够得到执行。200MB=200*1024*1024=0x0c800000>0x0c0c0c0c0),我们构造相应的内存片来覆盖内存,用200个这样的内存片来覆盖堆内存,只要其中任意一片nop区域能够覆盖0x0c0c0c0c,攻击就可以成功。


8.格式化字符串漏洞

    如果printf种的格式控制符可以被外界输入影响,就是所谓的格式化字符串漏洞了格式控制符号%n这个控制符号可以把当前输出的数据长度写回一个变量中。

格式化字符串漏洞的防范:当输入输出的格式化控制符能够被外界所影响的时候,攻击者可以综合利用前面的内存读写方式修改函数的返回地址,劫持进程从而使得shellcode得到执行。可以引起这种漏洞的函数有,printf,wprintf,fprintf,swprintf,sprintf,swprintf,vpringf,vwprintf,vfprintf,vfwprintf,vsprintf,vswprintf.


9.GS(great stack)

    针对返回值覆盖函数返回地址等选项,微软应用了相应的编译选项,visual studio默认开启了这个选项,gs编译选项为每个函数调用的时候增加了额外的数据和操作,用来检测栈中的溢出。在函数调用发生的时候,向栈中压入一个随机数,这个随机数叫做"canary",这个security cookie位于返回地址之前。系统还将在.data的内存区域存放一个serurity cookie的副本。当栈中发生溢出的时候,security  cookie将首先被淹没,之后才是ebp和返回地址。函数返回之前,将进行一个额外的安全验证工作,称为security cheek.会比较栈帧中存放的security cookie和.data中的副本值,如果不吻合则发生了溢出。如果不吻合说明栈帧被破坏,发生了对应的溢出操作。但是会带来相应性能的下降。不是所有的地方都会使用gs保护,只有存在缓冲区的地方才包含gs.

    使用#param strict_gs_check新安全问题通过strict_gs_check(on)可以堆任意类型的函数添或种子,作为当前系统的cookie,以此作加secutity cookie,通过设置标识,可以对不符合gs保护条件的函数田间gs保护,还使用了变量重排技术,分局局部变量的类型对变啊零在栈帧中的位置进行调整,将字符串变量移动到栈帧的高地址,可以防止该变量破坏局部变量,将指针参数和字符串参数复制到内存中的地址,防止函数参数被破坏。

    产生的细节,使用.data中第一个dword作为cookie的种子,程序运行的时候系统用ebp异为不同函数之间的区别。增强了cookie的随机性。在函数返回之前用ebp还原出cookie的种子。

    如何突破GS:

    1)利用未保护的内存突破gs,由于内存的原因,并不是所有的函数都会被保护,可以利用一些未被保护的函数绕过gs.

    2)覆盖函数虚函数突破gs程序只有在返回的时候才会检查security cookie,在这之前没有任何检查措施,我们可以在检查security cookie以前对程序进行溢出。c++的虚函数,通过虚函数来绕过gs.的条件1.存在溢出漏洞,2.有虚表指针,3.利用发生溢出的变量溢出时候有可能会影响虚表指针,如果可以控制虚表指针,将其指向我们的内存空间,就可以用虚表指针控制程序流程。

    虚函数的执行过程。虚函数的执行过程为,根据虚表指针找到虚表,然后从虚表指针中取出要调用的虚函数的地址,根据这个地址转入虚函数执行。变量位置不固定,因该考虑如何让虚表指针指针刚好指向我们的shellcode范围内。

    3)攻击异常处理破坏GS.(现在的seh加入了相应的保护机制,防止篡改)

    gs并没有提供对seh的保护,我们可以通过攻击异常处理达到绕过gs的目的,通过超长的字符串覆盖掉异常处理指针,然后想办法触发一个异常,程序就会转入异常处理,由于异常已经被我们控制,我们就可以通过劫持seh来控制后续的流程,主要的思想就是在程序检查security cookie之前将程序流程劫持。

    4)同时替换栈中和.data中的cookie来绕过gs


10.safeseh

    safeseh对异常处理函数保护。seh可以轻松绕过gs保护,safeseh校验机制,在调用异常函数之前,对要嗲用的异常处理函数进行一系列的校验,当返现异常处理函数不可靠时将终止异常处理函数的调用。safeseh需要操作系统与编译器的双重支持。编译器在编译的时候,会将所有的异常处理函数全部提取出阿里啊,编入一张安全的seh表,并将这张表放入程序映像里面,当程序调用异常处理函数的时候会将函数地址与安全seh表进行匹配,检查调用的异常处理函数是否位于安全的seh中,异常处理函数的调用是通过rtldispatchexception()处理函数实现的。safeseh也是从这里开始的,有以下保护措施:

    1)检查异常处理链是否位于当前的程序栈中,如果不在当前栈中,程序将终止异常处理函数的调用。

    2)检查异常处理函数指针是否指向当前程序栈中,如果是在当前程序栈中,程序将终止异常处理函数的调用

    3)当前两项检查都通过以后,程序会调用一个全新的函数,rtvalidhander()来对异常函数的有效性进行验证。函数所作的工作,首先判断异常处理函数的地址是不是加载模块的内存空间,

    a)判断是否设置了IMAGE_DLLCHARACTERISTICS_NO_SEH标识,如果设置了这个标识,这个函数的异常处理将被忽略,当这个标志被设置的时候,函数直接返回校验失败。

    b)检测程序是否包含seh表,如果程序包含表,将当前处理函数地址与该表进行匹配,匹配成功返回校验成功,匹配失败返回校验失败。

    c)判断程序是否设置了ILony标识,如果设置了这个标识,说明该程序只包含.net编译的中间语言,函数直接返回校验失败。

    d)判断异常处理函数地址是否位于不可执行的页上,位于不可以执行的页上的时候函数检查dep是否开启,如果dep开启则校验成功,否则抛出异常。如果没有在加载模块的进程空间的时候,校验函数将直接进行dep相关的校验。函数进行的校验如下,判断系统是否允许跳转到加载模块内存空间外执行,如果允许则返回校验成功,否则返回校验失败。

       哪些情况允许函数执行,1,异常处理函数位于加载模块内存范围之外,dep未开启,2.异常处理函数位于加载模块之内,相应模块未用seh表,同时相应模块不是纯il.3.异常处理函数位于加载模块范围之内,相应模块启用safeseh,异常处理函数地址包含在安全seh表中。只需要在记载模块范围外找到一个跳板跳转到shellcode执行就可以了,可以利用未启用safeseh模块中的指令作为跳板,跳入shellcode执行,可以清空安全seh表,造成未使用safeseh的假象,我们可以将我们的指令注册到安全seh表中,但是seh表是加密存放的,所以突破性不是很大,不攻击seh,可以考虑直接覆盖返回地址或者虚函数表等信息,利用如果seh中的异常函数指针指向堆去,即使安全校验发现seh已经不可信了,仍然会盗用其已被修改过的异常处理函数,因此只要将shellcode 布置到堆区就可以加直接跳转运行。

    绕过seh的办法:

    1)攻击返回地址绕过safeseh:当启用了safeseh但是没有启用gs,或者启用了gs但是刚好被攻击的函数没有gs保护

    2)利用虚函数绕过safeseh,通过攻击虚函数表来劫持进程流程,这个过程不涉及任何异常处理。

    3)从堆中绕过safeseh(利用对堆的特殊处理)将shellcode放入堆中而不是放入栈中,

    4)利用未启用safeseh的模块绕过safeseh如果seh异常处理函数在加载模块之内,但是未启用safeseh,并且该模块不是仅仅包含中间语言IL,这个异常处理函数就可以被执行,如果我们在加载模块中能够找到一个未启用safeseh的模块,就可以利用里面的指令来绕过safeseh.

    5)利用加载模块之外的地址绕过safeseh

    当程序加载到内存之后,除了它所占的整个内存空间中,除了我们平时常见的PE文件模块外(exe,dll),还有其它一些映射文件,我们通过od查看它的映射状态,类型为map的映射文件,safeseh是无视他们的,当异常处理函数的指针指向这些地址的时候,是不对其进行校验的,所以我们可以在这些文件中找到跳转指令的话就可以绕过safeseh,而这样的指令也确实存在。将异常处理的指针覆盖为加载模块以外的地址来绕过safeseh,然后通过除零异常将程序转到异常处理,进而劫持程序流程。


11.DEP

    Dep(data execution prevention)用来弥补代码和数据混淆这一缺陷.dep的原理就是将数据所在的区域标志为不可执行,当程序溢出成功转入sehllcode 的时候,程序再次尝试在数据页面上执行的时候,此时cpu就会抛出异常,而不是去执行恶意指令。Dep的主要任务就是阻止数据页执行代码。分为软件dep,和硬件dep:

    1)软件dep就是safeseh:它的目的是阻止seh的攻击,这种机制与硬件无关,wondows用软件模拟实现dep,对操作系统提供了一定的保护,所以明白了为啥safeseh会检查处理异常的函数是否位于非可执行的页面上了。

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

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

0 0 0 举报
复制成功