漏洞类型及检测

I.通用漏洞类型
 
1.栈溢出
 
栈溢出是缓冲区溢出的一种,往往由于对缓冲区的长度没有判断,导致缓冲区的大小超过了预定的大小,导致在栈内的保存的返回地址被覆盖,这时候返回地址将指向未知的位置.造成访问异常的错误.
 
而当我们精心构造一段shellcode保存在某个位置,并且通过滑板指令以及其他特定的方法跳转至shellcode的位置上执行shellcode,此时就可以通过shellcode获取到系统的管理员权限.执行任意代码,
 
windows XP之前的系统可以直接利用,在windows7以后的系统需要构造ROP链突破保护权限,突破方法见附录1.
 
 
2.堆溢出
 
堆溢出与栈溢出一样,也是缓冲区溢出的一种,堆栈溢出的产生往往是由于过多的函数调用,导致调用堆栈无法容纳这些调用的返回地址,一般在递归中产生。堆栈溢出很可能由无限递归产生,但也可能仅仅是过多的堆栈层级
 
在 windows XP SP2上可以利用调整链表指针的方式,向固定的地址写入可控的数据,比如讲shellcode的地址写到返回地址,或者覆盖PEB函数指针.SEH结构等方法,但是随着后续系统的更新,在windows 7系统中多了许多保护机制,因此需要构造ROP在绕过相关的保护机制后再利用漏洞获取管理员权限,执行任意代码.
 
 
3.整数溢出
 
整数分为有符号和无符号两种类型,有符号数以最高位作为其符号位,即正整数最高位为1,负整数最高位为0,而无符号数没有这种情况,它的取值范围是非负数,在平时编程的时候常用的整型变量有 8位(单字节字符、布尔类型)、16位(短整型)、32位(长整型)等 ,每种整数类型在内存中有不同的固定取值范围,比如unsigned short的存储范围是0-65535,但是当存储的值超过65535的时候,数据就会截断,例如输入65536,系统就会识别为0.
 
如果利用整数溢出后的值做为内存拷贝的参数,那么就会造成缓冲区溢出(堆/栈),利用方法就是缓冲区溢出的利用方法.
 
 
4.格式化字符串
 
格式化字符串漏洞的产生主要源于对用户输入内容未进行过滤,这些输入数据都是作为参数传递给某些执行格式化操作的函数,如printf.fprintf.bprintf.sprintf等等.恶意用户可以使用”%s”和”%x”等格式符,从堆栈或其他位置输出数据,也可以使用格式符”%n”向任意位置写入任意数据,配合printf()函数和其他功能类似的函数就可以向任意地址写入被格式化的字节数,可能导致任意代码执行,或者读取敏感信息,比如用户名以及密码等等.
 
因为可以执行任意代码,所以可以通过shellcode获取系统管理员的权限,也有可能通过一些技术,直接在内存中将系统密码直接读出.
 
 
5.双重释放
 
双重释放漏洞主要是由对同一块内存进行二次重复释放导致的,利用漏洞可以执行任意代码.
 
在释放过程中,临近的已释放堆块的合并动作,这回改变原有的堆头信息以及前后向指针,之后在对其中的地址进行引用,就会导致访问异常,最后程序崩溃,正式因为程序引用到了已释放的内存,所以说双重释放漏洞就是Use After Free漏洞的子集.如果程序不存在堆块合并动作,那么双重释放后可能不会马上崩溃,但会在程序中遗留隐患,导致在后续执行过程中的某一刻爆发.
 
对于堆内存的利用,最常用也最简单的方法就是使用堆喷射技术(Heap Spraying),也就是申请大量内存块,将shellcode放在内存块的最后,前面放上利用地址以及滑板指令,用大量内存来碰撞,直到最后执行到shellcode.
 
Shellcode可以执行任意代码,也就可以利用此来进行提权操作.
 
 
6.释放重引用
 
UAF漏洞的成因一般都是因为在编程过程中对引用计数的处理不当导致对象被释放后重用的。利用UAF漏洞实现远程代码执行,首先需要Bypass ASLR,获得模块基址及 shellcode的地址(也可以通过堆喷射在指定内存空间布置shellcode),然后硬编码、动态构造ROP来Bypass DEP,最终实现任意代码的执行。
 
 
7.数组访问越界
 
数组访问越界类似于溢出漏洞,但是又不完全是溢出漏洞
 
A)数组访问越界包含读写类型,而溢出属于数据写入
 
通常数组越界访问是由于数组下标数值超出了数组元素个数导致的,数组的读写操作有时是同时并存的,程序越界索引栈上分配的数组,同时又向其写入数据.最终造成溢出.
 
B)部分溢出漏洞的本质就是数组越界
 
导致溢出的原因有多种,有些正是由于针对数组下表标范围未做有效限制,导致允许越界访问数组并对其写入数据,造成溢出
 
 
8.内核级漏洞
 
在Ring3的溢出漏洞,格式化字符串漏洞,释放重引用漏洞,双重释放漏洞,数组越界漏洞都可以在内核中复现,但是利用方法差异比较大.
 
内核漏洞不易挖掘,也不易分析利用.但是如果可以利用成功,那么直接可以使用Ring0权限.
 
 
9.类型混淆
 
类型混淆漏洞主要是讲数据类型A当做数据类型B解析引用,可能导致非法访问数据,进而执行任意代码,但这里的数据类型并非是单纯的编程概念上的数据类型,比如Uint被转换成String,Flash漏洞:CVE-2014-0590,也包括类对象或者数据结构的转换,比如以下两个类,A类被混淆成B类,就可能导致私有域被外部访问到.
 
 
10.沙盒逃逸
 
A)Broker接口漏洞:IE借助Broker进程完成一些需要高权限的操作,若其服务端口本身就存在漏洞,就可以直接被攻击者用于执行任意代码.
 
B)策略检查绕过:Broker进程在检查Elevation Policies时若被绕过也可能导致沙盒逃逸,比如CVE-2013-4015用Tab带起空格从而绕过对程序名的检查.
 
C)策略设置不当:对于沙箱可操作的程序,如果其Elevation Policies设置不当,允许静默以Medium权限执行,就可能创建高权限的进程再借助该程序的一些接口完成任意代码执行.
 
D)IPC通信问题:当IPC通信过程中使用的共享内存包含过多的IE的未注册信息,可能导致沙盒的进程篡改其中主进程中的敏感信息,比如EPM沙盒的开关标准,被篡改后就可以直接关闭沙盒
 
E)沙盒权限限制不严:在沙盒中的进程如果权限限制的不够严谨,使得本不改访问的安全对象被访问,就可能导致沙盒逃逸.
 
F)内核提取:利用系统内核漏洞获取比沙盒本更更高的权限,就可以直接关闭沙盒本身,从而实现沙盒逃逸.
 
 
11.RPC漏洞
 
RPC是一种远程过程调用协议,RPC提供进程间的交互通信机制,允许在某台计算机上运行的程序无缝的在远程系统上执行.
 
因为TCP/IP处理交换等问题,导致恶意代码可以利用漏洞以本地系统权限在系统上执行任意指令.

 

 
V.检测方法
 
1.shellcode模糊检测
A)利用特定的编码方式检测
1)/x**:类C语言的shellcode编码形式
2)/u****:类javascript的shellcode编码形式
 
3)%u****:类JavaScript的shellcode编码形式
4)%**:多种脚本使用的shellcode编码形式
 
 
B)利用GetPC的特征来匹配shellcode
1)E80000000058方式GetPC
2)E8FFFFFFFFC258方式GetPC
3)D9EED97424F45B方式GetPC
 
 
C)利用动态函数获取编码来匹配shellcode
1)利用shellcode必须动态获取函数地址,以摆脱对宿主的环境要求的特点,针对动态获取函数地址的编码来进行检测
 
 
D)利用滑板指令来匹配shellcode
1)可以利用大量出现的滑板指令来匹配shellcode,例如0C0C0C0C,90909090,FFFFFFFF等经典滑板指令
 
 
2.恶意行为模糊检测
A)针对不应该出现的敏感库进行检测,如文档中如果出现ws2_32.dll就属于不正常的情况,可以针对性检测
B)针对不应该出现的敏感函数进行检测,如文档中如果出现申请内存,download等敏感操作,可以针对性进程检测
C)针对敏感对象以及字段进行检测,如果出现updata,autoopen一类敏感对象或字段,可以针对性进行检测
D)针对未知网址的检测,如果文档中出现非官方网址的未知网址,那么可以针对其进行针对性检测
 
 
3.漏洞特征检测
A)利用逆向分析出的漏洞触发特征,进行漏洞精确检测
 
附录1(windows保护机制):
GS:
在所有函数调用发生时,向栈桢里面压入一个随机的DWORD,这个数被称为canary,canary位于EBP之前,系统还在数据段的内存区域中存储一个canary的副本,当栈中发生溢出的时候,canary将被首先淹没,之后才是EBP和返回地址
在函数返回之前,系统做一个额外的安全验证,确认栈桢中的canary与数据段中的副本是否一致,如果两者不一致,说明栈桢中的canary已经被破坏,也就是栈中发生了溢出。
 
 
突破GS:
1.利用不受保护的内存突破,例如某函数中不包括4字节以上的缓冲区,即使开启GS,也并没有保护
2.利用虚函数突破,将虚表指针指向我们说需要的位置
3.利用异常处理突破,GS机制并没对SEHJ进行保护,我们可以通过超长字符串覆盖掉异常处理函数指针,然后触发一个异常,这时候就会转入异常处理,但是异常处理函数指针被覆盖了,那么就可以劫持SEH来控制程序流程了
4.利用GS自身验证突破,同时替换栈中和数据段中的canary
 
SafeSEH:
编译器:
在编译的时候产生一张安全SEH表,并且将这张表放在程序的映像里,当程序调用异常处理函数的时候,首先检查调用的异常处理函数是否在安全SEH表里。
操作系统:
1.检查异常处理链是否处于当前栈中,如果不在,程序终止异常处理的调用
2.检查异常处理函数指针是否指向当前程序的栈中,如果指向,终止异常处理函数的调用
3.调用RtllsValidhandler()来进行有效验证
     1)检查程序上是否设置了IMAGE_DLLCHARACTERISTICS_NO_SEH标记。如果设置了这个标识,这个程序内的异常将会被胡烈,所以这个标志被设置时,函数直接返回效验失败
     2)检测程序是否包含安全SEH表,如果程序中包含安全SEH表,则将当前的异常处理函数地址和该表进行匹配,匹配成功则返回校验成功。匹配失败则返回校验失败。
     3)判断程序是否设置ILonly标识,如果设置了这个标识,说明该程序 只包含.NET编译人中间语言,哈数直接返回校验失败
     4)判断异常处理函数是否位于不可执行页上,当异常处理函数地址位于不可执行页上,校验函数会检测DEP是否开启,如果系统未开启DEP则返回校验成功,否则程序抛出访问异常。
突破SafeSEH:
1.攻击返回地址,如果启用了safeSEH而没有启用GS,或者刚好这个函数没有GS保护,那么就可以直接攻击函数返回地址
 
2.利用虚函数表来劫持程序流程,这个过程中不涉及任何异常处理。SafeSEH也就没有机会生效了
3.利用未启用SafeSEH的模块绕过SafeSEH
 
DEP:
DEP的基本原理就是将数据所在的内存页标识为不可执行,当程序溢出后执行shellcode的时候,就会尝试在数据面上执行指令,此时CPU就会抛出异常,而不是去执行恶意的指令
根据机制的不同可以分为软件DEP和硬件DEP
软件DEP就是SafeSEH
硬件DEP才是真正意义上的DEP,需要CPU的支持,通过设置内存也的NX属性标记,来表明不能从该内存执行代码。当NX标记为0的时候表示这个页面可以执行指令,当NX标记为1的时候表示不能执行指令
 
突破DEP:
1.利用ret2libc
     1)通过跳转到ZwSetInfromationProcess函数将DEP关闭再转 Shellcode执行。
     2)通过跳转到Virtualprotect函数来将shellcode所在的内存也设置为可执行状态,然后转入shellcode执行
     3)通过跳转到VirualAlloc函数开辟一段具有执行权限的内存空间,然后将shellcode复制到这段内存中执行
2.利用可执行内存
     如果进程空间里存在一段可读可写可执行的内存,那么如果我们可以将shellcode复制到这段内存中,并且劫持程序执行流程,那么我们的shellcode就有执行的机会
3.利用java applet
     它可以被加载到IE客户端中,而且加载到IE进程的内存空间后,这些空间与空间都具有可执行属性
 
ASLR:
1.基址随机化
 
2.堆栈随机化
3.PRB和TEB的随机化
突破ASLR:
1.利用没有开启ASLR的模块进行绕过,比如Flash插件
2.利用部分覆盖进行定位,基址随机化只随机了前2个字节,这样就可以利用这个地址的后两个字来在一定程度上控制这个程序。
3.利用堆喷射进行内存定位。
    1.Heap spary:堆喷射就是申请大量内存,占领内存中的0x0c0c0c0c,并且在这些内存中放置0x90(nop)和shellcode,最后控制程序转入0x0c0c0c0c执行,只要不是0x0c0c0c0c整好处于shellcode当中,那么shellcode就可以成功执行。
     思路:申请200个1MB的内存块来堆喷,每个内存块中包含0x90和shellcode,堆喷结束后我们就会占领0x0c0c0c0c附近的内存,只要控制程序转到0x0c0c0c0c执行,通过0x90就滑板,最终执行shellcode
     在程序中找到溢出点,覆盖其返回地址,将返回地址覆盖为0x0c0c0c0c,这样函数返回执行的时候就会跳到我们申请的内存中
 
SEHOP:
SEHOP的核心任务是检查SEH链的完整性,在程序转入异常处理前SEHOP会检查SEH链上的最后一个异常处理函数是不是系统的异常处理函数,如果是,那么说明异常处理链没有被破坏,如果不是,那么说明SEH链已经被破坏,可能发生了覆盖攻击,程序不会执行当前的异常处理程序。
突破SEHOP:
1.伪造SEH链结构
2.利用未开启SEHOP的模块进行突破。
 
1月8/9日晚8:00-9:30直播(B站/腾讯课堂/微信视频号)多平台同时直播
8日HOOK专题直播预告(点击下方红色按钮预约)
9日lnject专题直播(同一时间直播)
 

关于作者

作者:rkvir(榴莲老师)

简介:曾任某安全企业技术总监;看雪讲师;曾任职国内多家大型安全公司;参与*2国家级安全项目

擅长:C/C++/Python/x86/x64汇编/系统原理&

研究方向:二进制漏洞/FUZZ/Windows内核安全/内网攻防