how2heap学习(一)
接下来的时间会通过how2heap学习堆的知识,这个系列可能会更新很多篇,因为每天学习到的东西要保证吸收消化,所以一天不会学习很多,但是又想每天记录一下。所以开个系列。
first_fit
此题的源码经过简化,如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 int main() {
5 char* a = malloc(512); //0x200
6 char* b = malloc(256); //0x100
7 char* c;
8 fprintf(stderr, "1st malloc(512): %p\n", a);
9 fprintf(stderr, "2nd malloc(256): %p\n", b);
10 strcpy(a, "AAAAAAAA");
11 strcpy(b, "BBBBBBBB");
12 fprintf(stderr, "first allocation %p points to %s\n", a, a);
13 fprintf(stderr, "Freeing the first one...\n");
14 free(a);
15 c = malloc(500);
16 fprintf(stderr, "3rd malloc(500): %p\n", c);
17 strcpy(c, "CCCCCCCC");
18 fprintf(stderr, "3rd allocation %p points to %s\n", c, c);
19 fprintf(stderr, "first allocation %p points to %s\n", a, a);
20 }
用gcc进行编译处理,命令:gcc -g first_fit1.c
运行一下看输出结果:
这个程序想让我们明白的是假如我先malloc了一个比较大的堆,然后free掉,当我再申请一个小于刚刚释放的堆的时候,就会申请到刚刚free那个堆的地址。还有就是,我虽然刚刚释放了a指向的堆,但是a指针不会清零,仍然指向那个地址。这里就存在一个uaf(use_after_free)漏洞,原因是free的时候指针没有清零。
接下来再放一些学习资料上面话,比较官方,比较准确。
fastbin_dup
还是先放一下程序源码:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 int main() {
5 fprintf(stderr, "Allocating 3 buffers.\n");
6 char *a = malloc(9);
7 char *b = malloc(9);
8 char *c = malloc(9);
9 strcpy(a, "AAAAAAAA");
10 strcpy(b, "BBBBBBBB");
11 strcpy(c, "CCCCCCCC");
12 fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
13 fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
14 fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
15 fprintf(stderr, "Freeing the first one %p.\n", a);
16 free(a);
17 fprintf(stderr, "Then freeing another one %p.\n", b);
18 free(b);
19 fprintf(stderr, "Freeing the first one %p again.\n", a);
20 free(a);
21 fprintf(stderr, "Allocating 3 buffers.\n");
22 char *d = malloc(9);
23 char *e = malloc(9);
24 char *f = malloc(9);
25 strcpy(d, "DDDDDDDD");
26 fprintf(stderr, "4st malloc(9) %p points to %s the first time\n", d, d);
27 strcpy(e, "EEEEEEEE");
28 fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
29 strcpy(f, "FFFFFFFF");
30 fprintf(stderr, "6rd malloc(9) %p points to %s the second time\n", f, f);
31 }
同样的gcc编译运行后看一下运行结果:
程序做了哪些事呢?
1.malloc申请了三个堆,并赋值。
2.free了第一个堆。
3.free了第二个堆。
4.再次free了第一个堆。
5.malloc又申请了三个堆。
发现:第五步malloc申请堆的时候,第一个堆申请到了free第一次的位置,第二个堆申请到了free第二次的位置,第三个堆又申请到了free了第一次的位置。
说白了就是连着free两次一个堆是不被允许的,但是假如再其中加一个free其他堆,那么就可以对一个堆free两次。这样再我们malloc再申请的时候,就可以申请到两个指针指向同一个堆块了。
为了方便理解,我们试着在pwndbg里面看看:
首先在11行的位置下了断点:
可以看到我们申请的三个堆,接下来我们在看一下free(a)、free(b)、再次free(a)时的情况:
--------------------------------------------------------------------------------------------------------
可以看到fastbins形成了一个环,但是其实应该是栈的样子的,但是由于我们绕过了检测,就可以形成环。
|Chunk A| -> |chunk B| -->| chunk A|
大概如上个图,这样我们就成功绕过了 fastbins 的double free检查。原因如下:
fastbins 可以看成一个 LIFO 的栈,使用单链表实现,通过 fastbin->fd 来遍历 fastbins。由于 free 的过程会对 free list 做检查,我们不能连续两次 free 同一个 chunk,所以这里在两次 free 之间,增加了一次对其他 chunk 的 free 过程,从而绕过检查顺利执行。然后再 malloc 三次,就在同一个地址 malloc 了两次,也就有了两个指向同一块内存区域的指针。
上面的情况是在libc-2.23版本做的实验,但是好像版本不同的时候会有其他情况。这里就直接拿资料上的东西了。
-----------------------资料----------------------------------------------
看一点新鲜的,在 libc-2.26 中,即使两次 free,也并没有触发 double-free 的异常检测,这与 tcache 机制有关,以后会详细讲述。这里先看个能够在该版本下触发double-free 的例子:
#include <stdio.h>
#include <stdlib.h>
int main() {
int i;
void *p = malloc(0x40);
fprintf(stderr, "First allocate a fastbin: p=%p\n", p);
fprintf(stderr, "Then free(p) 7 times\n");
for (i = 0; i < 7; i++)
{
fprintf(stderr, "free %d: %p => %p\n", i+1, &p, p);
free(p);
}
fprintf(stderr, "Then malloc 8 times at the same address\n");
int *a[10];
for (i = 0; i < 8; i++)
{
a[i] = malloc(0x40);
fprintf(stderr, "malloc %d: %p => %p\n", i+1, &a[i], a[i]);}
fprintf(stderr, "Finally trigger double-free\n");
for (i = 0; i < 2; i++)
{
fprintf(stderr, "free %d: %p => %p\n", i+1, &a[i], a[i]);
free(a[i]);
}
}
首先先malloc申请了一个堆,接着连续free了7次。
然后malloc同样大小的堆块,申请了8次。
接下来又free了申请的前两个申请的堆块。
我们看一下运行结果:
可以从输出看到,8次重新申请的堆块都指向一个我们第一次申请的地址。
后记:最后这个列子我还是没看出有啥可以学习到的。。。但是我疑惑的是,free了7次,为什么第8次malloc的时候,还是指向了第一次malloc的地址。
how2heap学习(一)的更多相关文章
- how2heap学习(二)
拖了好久,但是在期间做了几道pwn题目,发现堆原来也没有想象中的难. fastbin_dup_into_stack 这个说白了,就是利用double free可以进行任意地址的写,说是任意地址不准确, ...
- how2heap学习笔记
github源代码地址 这里只分析glibc2.25堆分配的特性,为了方便调试编译时使用 gcc -g -no-pie <input_file_name> -o <output_fi ...
- how2heap libc2.31学习
今天是四月十九,想在五月份之前把how2heap中的高版本(2.31)的例子过一遍.所以这个系列目前还是在更新中.如果比较简单就几句话带过了,遇到难一点的会写的详细一点. fastbin_dup 源代 ...
- House_of_orange 学习小结
House_of_orange学习小结 house_of_orange最早出现在2016年hitcon的一道同名题目,其利用效果,是当程序没有free函数的时候,我们可以通过一些方法,来让chunk被 ...
- fastbin attack学习小结
fastbin attack学习小结 之前留在本地的一篇笔记,复习一下. 下面以glibc2.23为例,说明fastbin管理动态内存的细节.先看一下释放内存的管理: if ((unsigned ...
- 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代
2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...
- Angular2学习笔记(1)
Angular2学习笔记(1) 1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之 ...
- ABP入门系列(1)——学习Abp框架之实操演练
作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...
- 消息队列——RabbitMQ学习笔记
消息队列--RabbitMQ学习笔记 1. 写在前面 昨天简单学习了一个消息队列项目--RabbitMQ,今天趁热打铁,将学到的东西记录下来. 学习的资料主要是官网给出的6个基本的消息发送/接收模型, ...
随机推荐
- OAuth 2.1 的进化之路
背景 2010年, OAuth 授权规范 1.0 (rfc 5849) 版本发布, 2年后, 更简单易用的 OAuth 2.0 规范发布(rfc 6749), 这也是大家最熟悉并且在互联网上使用最广泛 ...
- form-create 3.0 版本发布,好用的Vue3版本动态表单生成组件
form-create 是一个可以通过 JSON 生成具有动态渲染.数据收集.验证和提交功能的表单生成组件.支持2个UI框架,并且支持生成任何 Vue 组件.内置20种常用表单组件和自定义组件,再复杂 ...
- es使用postmain进行数据的增删改查
es的基本安装 安装遇到的问题 java本地环境和es环境冲突 https://www.cnblogs.com/q1359720840/p/14077049.html ,看要使用jdk1 ...
- Pycharm整体缩进和减少缩进
整体缩进:鼠标拉选住代码块,按下tab键. 反向缩进:鼠标拉选住代码块,按下shift+tab键.
- 痞子衡嵌入式:深扒IAR启动函数流程之段初始化实现中可用的压缩选项
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR启动函数流程里段初始化实现中可用的压缩选项. 接着 <IAR启动函数流程之段初始化函数__iar_data_init3实现& ...
- 洛谷 P4240 - 毒瘤之神的考验(数论+复杂度平衡)
洛谷题面传送门 先扯些别的. 2021 年 7 月的某一天,我和 ycx 对话: tzc:你做过哪些名字里带"毒瘤"的题目,我做过一道名副其实的毒瘤题就叫毒瘤,是个虚树+dp yc ...
- python判断字符串是否为空和null
1.使用字符串长度判断 len(s==0)则字符串为空 test1 = '' if len(test1) == 0: print('test1为空串') else: print('test非空串,te ...
- 【k8s】使用Terraform一键部署EKS集群
本文适用范文 使用AWS海外账号 对aws.terraform.k8s有一定的了解 新建一个独立的VPC Terraform简介 terraform是一个云端的资源编排工具,官方对自己的定位:Terr ...
- python-django-查询详解
倒数第二条性质可以实现链式的调用,通过第一次的过滤还可以再过滤倒数第一条就是结果集从数据库中查询出来之后不会再进行数据库的查询的我们使用的object就是模型管理器manager的一个对象 obj = ...
- nginx——网站显示问题
一般来说修改3个位置,一个是nginx.h.另一个是ngx_http_header_filter_module.c.还有一个ngx_http_special_response.c. 提示:一般修改都是 ...