利用程序漏洞去执行shellcode
以便劫持进程的控制权。代码植入--淹没返回地址--劫持进程的控制权,让程序跳转去执行shellcode
。
Shellcode
往往需要用汇编语言编写,并转换成二进制机器码,其内容和长度经常会受到很多苛刻限制,开发和调试的难度很高。
int MessageBox(
HWND hWnd, // handle to owner window
LPCTSTR lpText, // text in message box
LPCTSTR lpCaption, // message box title
UINT uType // message box style
);
写出调用这个API的汇编代码--翻译成机器代码--用十六进制编辑工具填入reg.txt文件。
用汇编语言调用MessageboxA
Dependency Walker -- 随便拖拽一个有图形界面的PE文件进去--找到并选中user32.dll
---右栏中会列出所有导出函数及偏移地址 / 下栏列出了PE文件用到的所有的库的基地址
user32.dll
的基地址为0x77D10000
,MessageBoxA
的偏移地址为0x000407EA
。基地址加上偏移地址就得到了MessageBoxA
函数在内存中的入口地址:0x 77D507EA
字符串westwest
压入栈区--消息框的文本和标题都显示为westwest
,重复压入指向这个字符串的指针--第1个和第4个参数这里都将设置为NULL
写出的汇编代码和指令所对应的机器代码如表所示。
机器代码(十六进制) | 汇编指令 | 注释 |
---|---|---|
33 DB | XOR EBX,EBX | 将EBX的值设置为0 |
53 | PUSH EBX | 将EBX的值入栈 |
68 77 65 73 74 | PUSH 74736577 | 将字符串west入栈 |
68 77 65 73 74 | PUSH 74736577 | 将字符串west入栈 |
8B C4 | MOV EAX,ESP | 将栈顶指针存入EAX(栈顶指针的值就是字符串的首地址) |
53 | PUSH EBX | 入栈Messagebox的4个参数-类型 |
50 | PUSH EAX | 入栈Messagebox的4个参数-标题 |
50 | PUSH EAX | 入栈Messagebox的4个参数-消息 |
53 | PUSH EBX | 入栈Messagebox的4个参数-句柄 |
B8 EA 07 D5 77 | MOV EAX, 0x77D507EA | 调用MessageBoxA函数 |
FF D0 | CALL EAX | 调用MessageBoxA函数 |
得到的shellcode
为:33 DB 53 68 77 65 73 74 68 77 65 73 74 8B C4 53 50 50 53 B8 EA 07 D5 77 FF D0
。将shellcode
写入reg.txt
文件,且在返回地址处写buffer
的地址。Buffer
的地址(OllyDbg查看 or 反汇编方式) = 0018FAB8
这样一运行 pwd.exe,verify函数返回地址跳到了buffer--执行 messageBox--弹出窗口
Shellcode
编写自行编写Shellcode / 23333
heap spray
技术不支持或者不能实现精确定位shellcode
。例,浏览器或其使用的activeX
控件中存在漏洞,攻击者可以生成 HTML文件诱发用户访问来触发这个漏洞。HTML页面中的Javascript
可以在用户计算机中申请堆内存,shellcode
通过 Javascript
被注入到堆空间中。由于堆分配地址随机性较大,为了解决shellcode
在堆中的定位以便触发,可以采用heap spray
的方法
Heap Spray
也称为堆喷洒技术,是在shellcode
的前面加上大量的滑板指令slide code
,组成一个非常长的注入代码段。然后向系统申请大量内存,并且反复用这个注入代码段来填充。这样使得内存空间被大量的注入代码所占据。攻击者结合漏洞利用技术,只要使程序跳转到堆中被填充了注入代码的任何一个地址,程序指令就会顺着滑板指令最终执行到shellcode
代码。
滑板指令slide code
是由大量NOP
(no-operation
)空指令0x90
填充组成的指令序列,当遇到这些NOP
指令时,CPU指令指针会一个指令接一个指令的执行下去,中间不做任何具体操作,直到“滑”过最后一个滑板指令后,接着执行这些指令后面的其他指令,往往后面接着的是shellcode
代码。Shellcode
的正常执行,需要从shellcode
的第一条指令开始。前面加上滑板指令之后,程序跳转后只要命中滑板指令中的任何一个,就可以保证它后面接着的shellcode
能成功执行。
随着一些新的攻击技术的出现,滑板指令除了利用NOP
指令填充外,也逐渐开始使用更多的类NOP
指令,譬如0x0C
,0x0D
等
Heap Spray
用于针对浏览器漏洞的攻击较多,尤其是网页木马应用较多。这些漏洞利用程序通常会将EIP
指向堆区的0x0C0C0C0C
地址,然后使用Javascript
脚本申请大量的堆内存,在内存空间中填充了大量包含0x90
和shellcode
的注入代码。漏洞利用程序从低地址向高地址一直申请超过200MB的堆内存空间,由于200MB对应的内存地址为0x0C800000
,高于EIP指向的0x0C0C0C0C
,因而,申请的堆空间超过200MB时将覆盖0x0C0C0C0C
。只要注入代码中填充的0x90
能够覆盖0x0C0C0C0C
的位置,shellcode
就会最终执行。
Heap Spray
技术通过使用类NOP
指令来进行覆盖,对shellcode
地址的跳转准确性要求不高,从而增加了缓冲区溢出攻击的成功率。然而,Heap Spray
会导致被攻击进程的内存占用非常大,计算机无法正常运转,因而容易被察觉。一般配合堆栈溢出攻击,不能用于主动攻击,也不能保证成功。
介绍Windows操作系统中提供的主要几种软件漏洞利用的防范技术。
GS Stack Protection
技术是一项缓冲区溢出的检测防护技术。VC++编译器中提供了一个/GS编译选项,选择该选项,编译器针对函数调用和返回时添加保护和检查功能的代码,在函数被调用时,在缓冲区和函数返回地址增加一个32位的随机数security_cookie
,在函数返回时,调用检查函数检查security_cookie
的值是否有变化。
security_cookie
在进程启动时会随机产生,并且它的原始存储地址因Windows操作系统的ASLR
机制也是随机存放的,攻击者无法对security_cookie
进行篡改。当发生栈缓冲区溢出攻击时,对返回地址或其他指针进行覆盖的同时,会覆盖security_cookie
的值,因此在函数调用结束返回时,对security_cookie
进行检查就会发现它的值变化了,从而发现缓冲区溢出的操作,中断当前进程并报错。
因此,GS技术对基于栈的缓冲区溢出攻击能起到很好的防范作用。
数据执行保护DEP
(data execute prevention
)技术可以 限制内存堆栈区的代码为不可执行状态 -- 防范溢出后代码的执行
Windows操作系统中,默认情况下将 包含执行代码和DLL文件的txt段 即 代码段 的内存区域设置为 可执行代码的内存区域。其他的内存区域不包含执行代码,应该不能具有代码执行权限,但是Windows XP及其之前的操作系统,没有对这些内存区域的代码执行进行限制。因此,对于缓冲区溢出攻击,攻击者能够对 内存的堆栈 或 堆的缓冲区 进行覆盖操作,并执行写入的shellcode
代码。启用DEP机制后,DEP机制将这些敏感区域设置不可执行的non-executable
标志位,因此在溢出后即使跳转到恶意代码的地址,恶意代码也将无法运行,从而有效地阻止了缓冲区溢出攻击的执行。
DEP
分为软件DEP和硬件DEP。硬件DEP需要CPU的支持,需要CPU在页表增加一个保护位NX(no execute
),来控制页面是否可执行。现在CPU一般都支持硬件NX,所以现在的DEP保护机制一般都采用的硬件DEP,对于DEP设置non-executable
标志位的内存区域,CPU会添加NX
保护位来控制内存区域的代码执行。
地址空间分布随机化ASLR
(addressspace layout randomization
),将系统关键地址随机化,使攻击者无法获得需要跳转的精确地址。Shellcode
需要调用一些系统函数才能实现系统功能达到攻击目的,因为这些函数的地址往往是系统DLL(如kernel32. Dll
)、可执行文件本身、栈数据或PEB
(Process Environment Block
,进程环境块)中的固定调用地址,所以为shellcode
的调用提供了方便。
使用ASLR
技术的目的就是打乱系统中存在的固定地址,使攻击者很难从进程的内存空间中找到稳定的跳转地址。ASLR
随机化的关键系统地址包括: PE文件(exe文件和dll文件)映像地址、堆栈基址、堆地址、PEB和TEB(Thread Environment Block,线程环境块)地址等。
当程序启动将执行文件加载到内存时,操作系统通过内核模块提供的ASLR
功能,在原来映像基址的基础上加上一个随机数作为新的映像基址。随机数的取值范围限定为1至254,并保证每个数值随机出现。
SEH
(Structured Exception Handler
)是Windows异常处理机制所采用的重要数据结构链表。程序设计者可以根据自身需要,定义程序发生各种异常时相应的处理函数,保存在SEH
中。通过精心构造,攻击者通过缓冲区溢出覆盖SEH
中异常处理函数句柄,将其替换为指向恶意代码shellcode
的地址,并触发相应异常,从而使程序流程转向执行恶意代码。
SafeSEH
就是一项保护SEH
函数不被非法利用的技术。微软在编译器中加入了/SafeSEH
选项,采用该选项编译的程序将PE文件中所有合法的SEH
异常处理函数的地址解析出来制成一张SEH
函数表,放在PE文件的数据块中,用于异常处理时候进行匹配检查。
在该PE文件被加载时,系统读出该SEH
函数表的地址,使用内存中的一个随机数加密,将加密后的SEH
函数表地址、模块的基址、模块的大小、合法SEH
函数的个数等信息,放入ntdll.dll
的SEHIndex
结构中。在PE文件运行中,如果需要调用异常处理函数,系统会调用加解密函数解密从而获得SEH
函数表地址,然后针对程序的每个异常处理函数检查是否在合法的SEH
函数表中,如果没有则说明该函数非法,将终止异常处理。接着要检查异常处理句柄是否在栈上,如果在栈上也将停止异常处理。这两个检测可以防止在堆上伪造异常链和把shellcode
放置在栈上的情况,最后还要检测异常处理函数句柄的有效性。
从Vista开始,由于系统PE文件在编译时都采用SafeSEH编译选项,因此以前那种通过覆盖异常处理句柄的漏洞利用技术,也就不能正常使用了。
结构化异常处理覆盖保护SEHOP
(Structured Exception Handler Overwrite Protection
)是微软针对SEH
攻击提出的一种安全防护方案。SEH
攻击是指通过栈溢出或者其他漏洞,使用精心构造的数据覆盖SEH
上面的某个函数或者多个函数,从而控制EIP
(控制程序执行流程)。
微软提供这个功能是在Windows Vista SP1
、 Windows 7
以及它们的后续版本。它是以一种SEH
扩展的方式提供的,通过对程序中使用的SEH
结构进行一些安全检测,来判断应用程序是否受到了SEH
攻击。SEHOP
的核心是检测程序栈中的所有SEH
结构链表的完整性,SEHOP
针对下列条件进行检测,包括SEH
结构都必须在栈上,最后一个SEH
结构也必须在栈上;所有的SEH
结构都必须是4字节对齐的;SEH结构中异常处理函数的句柄handle
(即处理函数地址)必须不在栈上;最后一个SEH
结构的handle
必须是ntdll!FinalExceptionHandler
函数,最后一个SEH
结构的next seh
指针必须为特定值0xFFFFFFFF
等。
当进行异常处理时,由系统接管进行异常处理,因此SEHOP
由系统独立来完成,应用程序不用做任何改变,只需要在操作系统中开启SEHOP
防护功能即可。开启SEHOP
,可以在注册表编辑器找到注册表子项:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\kernel
,查看其包含的DisableExceptionChainValidation
的值,将其注册表项的值更改为 0,则表示启用了SEHOP
。如果没有此注册表项,可创建一个DWORD
类型的DisableExceptionChainValidation
,并将其设为0。