堆溢出-unlink
#有几张图出自hollk师傅的文章,原文链接:https://blog.csdn.net/qq_41202237/article/details/108481889#
堆溢出-unlink
对unlink的利用大概就是对chunk进行内存布局,然后借助unlink中对指针的操作来修改chunk中的指针
unlink的宏定义:
#define unlink(AV, P, BK, FD) { FD = P->fd; BK = P->bk; if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) malloc_printerr (check_action, "corrupted double-linked list", P, AV); else { FD->bk = BK; BK->fd = FD; if (!in_smallbin_range (P->size) && __builtin_expect (P->fd_nextsize != NULL, 0)) { if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0)) malloc_printerr (check_action, "corrupted double-linked list (not small)", P, AV); if (FD->fd_nextsize == NULL) { if (P->fd_nextsize == P) FD->fd_nextsize = FD->bk_nextsize = FD; else { FD->fd_nextsize = P->fd_nextsize; FD->bk_nextsize = P->bk_nextsize; P->fd_nextsize->bk_nextsize = FD; P->bk_nextsize->fd_nextsize = FD; } } else { P->fd_nextsize->bk_nextsize = P->bk_nextsize; P->bk_nextsize->fd_nextsize = P->fd_nextsize; } } }
}
在以前认识的函数中free()函数在执行时有一个int_free 的过程中调用了unlink,如下:
#define unlink(AV, P, BK, FD)
static void _int_free (mstate av, mchunkptr p, int have_lock)
free(){_int_free(){unlink();}
}
堆释放
设置这样一个堆的创建与释放过程,依次释放first second third_chunk,中间创建的heap1 2 3是为了隔开需要释放的几个chunk,防止他们在free时合并
#include<stdio.h>
void main(){long *heap1 = malloc(0x80);
long *first_chunk = malloc(0x80);
long *heap2 = malloc(0x80);
long *second_chunk = malloc(0x80);
long *heap3 = malloc(0x80);
long *third_chunk = malloc(0x80);
long *heap4 = malloc(0x80);free(first_chunk);
free(second_chunk);
free(third_chunk);return 0;
}
使用命令gcc -g text.c - o test编译生成一个elf文件来进行gdb的动态调试
先在程序的第15行下一个断点 :b 15
然后r运行程序之后输入bin 看一下这几个内存空间被释放到了哪里去:
这里可以看见释放的三个chunk是以链表形式储存在unsorted bin 当中.
unlink的检查过程及操作理解
前面可以看见释放的三个chunk是以链表的方式储存在unsorted bin当中:
这里可以看见三个chunk的 fd 和 bk的相互指向关系,unlink的大概操作就是将second_chunk 从这个链表中取出来,那么如果second_chunk 被取出,剩下的三个chunk就会变成一下这样:
chunk状态检查
仍然是前面的这个test的例子,再次使用gdb来调试一下,看一下second_chunk中的情况;
检查1:检查被释放的chunk相邻高地址的chunk的pre_size是否与size位值相同:
这就是检查被释放chunk的相邻chunk的pre_size是否与这个chunk的size相同,防止chunk的size值被篡改,以及检查这个被释放chunk是否处于空闲状态
检查2:检查被释放chunk的相邻高地址chunk的P位值是否为0:
前面提到过的P位:这是AMP三个字段中最为重要的一个字段,记录前一个chunk是不是malloc的chunk,如果是1,那么就是已经写入用户数据的chunk,如果是0,则是free chunk,在释放内存空间时,如果上一个chunk为free chunk,那么就会将两个chunk合并为一个chunk,size字节就会变大
这里还是检查确认被释放的chunk是否为空闲状态
检查3:检查被释放chunk的前后指针fd 和 bk:
可以看左图红色框中的内容,这里是second_chunk的fd和bk。首先看fd,它指向的位置就是前一个被释放的块first_chunk,这里需要检查的是first_chunk的bk是否指向second_chunk的地址。再看second_chunk的bk,它指向的是后一个被释放的块third_chunk,这里需要检查的是third_chunk的fd是否指向second_chunk的地址
以上三个检查就是对于某个chunk是否处于free状态的三次检查确认,以及三大标准:pre_size,P位,前后指针
例题:[2014 HITCON stkof]
网址:https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/unlink/2014_hitcon_stkof
保护检查:
除了没开PIE,其他的都开了
这个程序运行起来并没有以前那样的操作提示页面,只有一个一直等待输入的操作
进入ID看一下静态分析
主函数:
__int64 __fastcall main(int a1, char **a2, char **a3)
{int v3; // eaxint v5; // [rsp+Ch] [rbp-74h]char nptr[104]; // [rsp+10h] [rbp-70h] BYREFunsigned __int64 v7; // [rsp+78h] [rbp-8h]v7 = __readfsqword(0x28u);alarm(0x78u);while ( fgets(nptr, 10, stdin) ){v3 = atoi(nptr);if ( v3 == 2 ){v5 = sub_4009E8();goto LABEL_14;}if ( v3 > 2 ){if ( v3 == 3 ){v5 = sub_400B07();goto LABEL_14;}if ( v3 == 4 ){v5 = sub_400BA9();goto LABEL_14;}}else if ( v3 == 1 ){v5 = sub_400936();goto LABEL_14;}v5 = -1;
LABEL_14:if ( v5 )puts("FAIL");elseputs("OK");fflush(stdout);}return 0LL;
}
可以看出这个程序的主体其实就是先让我们输入一个数字存入v3之中,根据v3的值进入不同的函数功能之中(v3可以是1 2 3 4)
下面看一下每个函数是要干什么
sub_4009E8()
__int64 sub_4009E8()
{__int64 result; // raxint i; // eaxunsigned int v2; // [rsp+8h] [rbp-88h]__int64 n; // [rsp+10h] [rbp-80h]char *ptr; // [rsp+18h] [rbp-78h]char s[104]; // [rsp+20h] [rbp-70h] BYREFunsigned __int64 v6; // [rsp+88h] [rbp-8h]v6 = __readfsqword(0x28u);fgets(s, 16, stdin);v2 = atol(s);if ( v2 > 0x100000 )return 0xFFFFFFFFLL;if ( !(&::s)[v2] )return 0xFFFFFFFFLL;fgets(s, 16, stdin);n = atoll(s);ptr = (&::s)[v2];for ( i = fread(ptr, 1uLL, n, stdin); i > 0; i = fread(ptr, 1uLL, n, stdin) ){ptr += i;n -= i;}if ( n )result = 0xFFFFFFFFLL;elseresult = 0LL;return result;
}
这个函数的功能大概是:先从外部接受输入缓冲区的数据,再将输入的数据转换为数值输入给变量v2,然后对v2的值大小进行判定,如果大于了0x100000则结束程序,之后判断*(&:
堆溢出-unlink相关推荐
- Linux (x86) Exploit 开发系列教程之九 使用 unlink 的堆溢出
使用 unlink 的堆溢出 译者:飞龙 原文:Heap overflow using unlink 预备条件: 理解 glibc malloc 这篇文章中,让我们了解如何使用 unlink 技巧成功 ...
- 【pwn学习】堆溢出(三)- Unlink和UAF
前置学习 [pwn学习]堆溢出(一) [pwn学习]堆溢出(二)- First Fit 文章目录 什么是Unlink? Unlink如何利用? 加入错误检查 什么是Use-After-free? 例题 ...
- 堆溢出攻击(XP SP2 - 2003)
微软在堆中也增加了一些安全校验操作,使得原本是不容易的堆溢出变得困难重重: * PEB Random:在 Windows XP SP2 之后,微软不再使用固定的 PEB 基址 0x7FFDF000,而 ...
- Linux (x86) Exploit 开发系列教程之十 使用 Malloc Maleficarum 的堆溢出
使用 Malloc Maleficarum 的堆溢出 译者:飞龙 原文:Heap overflow using Malloc Maleficarum 预备条件: 理解 glibc malloc 从 2 ...
- 总结windows下堆溢出的三种利用方式
创建时间:2004-04-08 文章属性:转载 文章提交:watercloud (watercloud_at_xfocus.org) 原文由Leven发在网络编程版: https://www.xfoc ...
- Netgear R6400v2 堆溢出漏洞分析与利用
2020 年 6 月,ZDI发布了一个关于Netgear R6700型号设备上堆溢出漏洞的安全公告,随后又发布了一篇关于该漏洞的博客,其中对该漏洞进行了详细分析,并给出了完整的漏洞利用代码.该漏洞存在 ...
- [pwn]堆:unlink绕过,0CTF2015 freenote详解
[pwn]堆:2free=unlink绕过,0CTF2015 freenote 题目地址,提取码:f0xd 拿到题目,国际惯例,首先查看安全策略; 没有开启PIE和full partial.然后查看程 ...
- 【pwn学习】堆溢出(一)
文章目录 什么是堆溢出 基本示例 堆分配函数 堆填充长度 堆攻击总结 学习这部分之前,如果对堆的基础还不甚了解可以参考一下下面的学习笔记 Linux堆管理基础知识(一) Linux堆管理基础知识(二) ...
- 5.4 堆溢出利用(上)——DWORD SHOOT
目录 一.预备知识 二.实验环境 三.实验代码 四.实验步骤 一.预备知识 堆管理系统的三类操作:堆块分配.堆块释放和堆快合并归根结底都是对链表的修改.堆溢出利用的精髓就是用精心构造的数据溢出下一个堆 ...
- android 9patch 漏洞,Android 9patch 图片解析堆溢出漏洞分析(CVE-2015-1532)
[前言] 日前谷歌公开了一个今年1月份更新的漏洞.这个漏洞修复了一个存在于Android 5.1版本以下图片渲染的问题,可以查看相关链接. 9patch是Android上特有的一种图片格式,就是在普通 ...
最新文章
- pku 1077 Eight
- 分割BiSeNet笔记
- linux环境下安装mysql 8.0
- 【译】 Diving Into The Ethereum VM Part 6 - How Solidity Events Are Implemented
- create document history via code
- Java迭代器contains的问题
- vagrant系列教程(四):vagrant搭建redis与redis的监控程序redis-stat(转)
- 《我的成长》6月下2009年第7期(总第7期)
- tensorflow 相关的 warning
- crontab导致磁盘空间满问题的解决
- Linux 修改 Tomcat 编码
- OpenGL图形渲染管线(Pipeline)学习
- Linux 学习笔记 (一)
- 基于VUMAT复合材料夹层结构冲击仿真
- Modbus协议中文pdf免费下载地址
- npm jdf压缩并上传静态文件到服务器
- python实现触摸精灵功能_触摸精灵lua脚本实现微信群加好友功能
- EM算法及python实现
- Mac IntelliJIDEA非正常关闭解决(reopen失败)
- 笔记本电脑散热风扇声音比较大解决方法