PWN——uaf漏洞学习
PWN——uaf漏洞
1.uaf漏洞原理
在C语言中,我们通过malloc族函数进行堆块的分配,用free()函数进行堆块的释放。在释放堆块的过程中,如果没有将释放的堆块置空,这时候,就有可能出现use after free的情况。这里我写了一个demo
#include<stdio.h>
#include<stdlib.h>
typedef struct demo
{
char *s;
void(*func)(char *);
}DEMO;
void eval(char command[])
{
system(command);
}
void echo(char content[])
{
printf("%s",content);
}
int main()
{
DEMO*p1;
DEMO*p2;
p1=(DEMO*)malloc(sizeof(struct demo));
p1->s="I will tell you what's uaf.";
printf("%s\n",p1->s);
printf("p1 malloc address:%p\n",p1);
p1->func=echo;
p1->func("use after free!\n"); free(p1);
p1->s="~Heihei~";
printf("%s\n",p1->s);
p2=(DEMO*)malloc(sizeof(struct demo));
p2->func=eval;
// p1->func=eval;
printf("p2 malloc address:%p\n",p2);
p2->func("whoami"); p1=NULL;
printf("Now,I can't use address of p1.");
p2->func("whoami");
return 0;
}
运行的结果如下图所示

可以看出,在free()堆块之后,没有将堆块置空,堆块处于悬空状态,导致被free掉的堆块依然可以被使用。同时,如果我们申请相同大小的堆块的话,由于ptmalloc的堆管理机制,重新分配的堆块的位置和我们释放的堆块地址是一样的。但是,在将p1置空之后,再次使用堆块的时候,就会报出段错误。
其实,一般的uaf漏洞利用,和我们上图的demo也是类似的,都是定义一个结构体,结构体中有一个函数指针,然后free,将chunk添加进fastbin,再次分配相同大小的内存块,这时候分配的就是刚才free掉悬空的堆块,然后改写函数指针,劫持数据流,配合不同的函数指针,可以实现任意地址读,任意地址写,以及命令执行。
注:这里第二次分配内存的时候,我们一般分配相同数据类型。比如上面的例子中,第一个释放的堆块p1的是DEMO类型的结构体,第二次分配的时候,我们们分配的p2也是一个DEMO类型的结构体,这种情况下,p2一定用的是之前p1的内存。但是在有些情况下,如果我们分配的数据类型不同,但是前后分配大小相同,也可能造成堆块的再次利用。
2.例题
这道例题,是pwnable.kr上的uaf这道题目,源码如下。
#include <fcntl.h>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
using namespace std; class Human{
private:
virtual void give_shell(){
system("/bin/sh");
}
protected:
int age;
string name;
public:
virtual void introduce(){
cout << "My name is " << name << endl;
cout << "I am " << age << " years old" << endl;
}
}; class Man: public Human{
public:
Man(string name, int age){
this->name = name;
this->age = age;
}
virtual void introduce(){
Human::introduce();
cout << "I am a nice guy!" << endl;
}
}; class Woman: public Human{
public:
Woman(string name, int age){
this->name = name;
this->age = age;
}
virtual void introduce(){
Human::introduce();
cout << "I am a cute girl!" << endl;
}
}; int main(int argc, char* argv[]){
Human* m = new Man("Jack", 25);
Human* w = new Woman("Jill", 21); size_t len;
char* data;
unsigned int op;
while(1){
cout << "1. use\n2. after\n3. free\n";
cin >> op; switch(op){
case 1:
m->introduce();
w->introduce();
break;
case 2:
len = atoi(argv[1]);
data = new char[len];
read(open(argv[2], O_RDONLY), data, len);
cout << "your data is allocated" << endl;
break;
case 3:
delete m;
delete w;
break;
default:
break;
}
} return 0;
}
之前没看过C++,花了点时间把C++的类与面向对象的一些知识学习了一下。
· 先看主函数,主函数中实现了分配堆块,释放堆块,以及从读入数据的功能。然后再看定义的几个类,Human是定义的一个基类,Man和Woman是定义的派生类,Human中public和protected定义的函数和变量可以在后面被子类继承和访问。但是定义的私有的give_shell虚函数,我们是无法在外部调用的,也无法通过子类来访问。只能通过Human类中定义的函数来调用。
我们这里需要一些预备知识:C++的类中有序函数的时候,会生成一个虚表vtable,编译器会生成一个vptr指针指向vtable(不管基类中有多少虚函数,只有一个_vptr指针指向vtable;多态继承时,继承了多个父类,相应就会又多个vtable)。对于共有成员变量来说,虚函数可以被子类同名函数重新调用,子类中有同名函数的时候,子类的vatble中指向基类虚函数的函数指针变为指向子类同名函数。对于私有成员来说,他的函数指针会保留在子类的vtable中(但是子类不是继承私有成员)。所以对于上面的源码来讲,Man类和Woman类的vtable中,introduce函数指针指不同,但是give_shell函数指针是相同的。我们可以再深入思考一下:vtable保留在哪里?通过IDA我们可以看出,vtable是保留在rodata段的。vtable保留着类的虚函数指针,它应该在编译前就完成,相应的它肯定不在代码段,bss段和data段分别保留的是未初始化和初始化后的局部变量,全局变量以及静态变量,所以vtable也不会在bss段或者data段。这样看来,vtable和字符串常量一样,保留在全局数据段是合理的。
这几张图片是从sakura师傅的博客取下来的,这里贴出来,大家可以看一下

对于这道题而言,类比C程序中利用的步骤,我们应改首先创建堆块,然后通过case3释放堆块,但使堆指针悬空,最后通过case2,读入文件内容,覆写类的函数指针,劫持数据流。
打开IDA,main函数的伪代码中可以得知,Man和Woman对象分配的堆的大小为0x18个字节。
我们首先通过调试,找到相应的虚表函数,要找到虚表函数,就要先找到Man的构造函数。

找到Man的构造函数之后进入,会发现调用Human的构造函数(因为Man作为子类要继承父类),所以这时候继续单步,可以在寄存器窗口看见调用give_shell函数的地址


找vtable的话,进入IDA,到rodata段。

Man类vtable表,give_shell的函数指针的地址为0x401570。现在要具体关注一下堆块内部的内存布局,以便在后面有效地覆盖函数指针。


0x40117a是give_shell函数地址,0x4012d2是introduce函数地址。
按照C++实例化类的内存分配的规则,类中有虚函数的时候,分配的对象的内存数据中,前8个字节是_vptr指针,这个指针指向vtable表,以后是成员变量的内存数据(这里应该只是成员变量的内存数据,不包括成员函数,所有函数都是定义在text段的)。
vptr指向的地址,是vtable表的地址,vtable表上存储的是虚函数的地址。
case2的时候填充的数据就应该是把前8个字节修改
case1调用intreduce函数的代码如下

v13和v14应该分别是Man对象和Woman对象的vptr指针,前面看到过,give_shell函数地址在0x401570地址处,我们向文件中写入0x401570-8的地址。
这里要注意的是,再次分配地址的时候,由于最后delete的是Woman对象的地址,第一次写入的是之前Woman的地址,第二次才是写入到Man对象地址的vtable表上。

终于是写完了这篇博客。。。
C++和堆的很多知识我绝对理解的不是很到位,是要不断学习的,但是这道题是看着博客,跌跌撞撞做出来了。写出来是为了加深印象,如果哪里有说的不对的地方,还希望路过的师傅们能过及时指出来,谢过师傅们了。
PWN——uaf漏洞学习的更多相关文章
- PWN二进制漏洞学习指南
目录 PWN二进制漏洞学习指南 前言 前置技能 PWN概念 概述 发音 术语 PWN环境搭建 PWN知识学习途径 常见漏洞 安全机制 PWN技巧 PWN相关资源博客 Pwn菜鸡小分队 PWN二进制漏洞 ...
- UAF漏洞学习
产生原因: UAF漏洞的成因是一块堆内存被释放了之后又被使用.又被使用指的是:指针存在(悬垂指针被引用).这个引用的结果是不可预测的,因为不知道会发生什么.由于大多数的堆内存其实都是C++对象,所以利 ...
- Hitcon 2016 Pwn赛题学习
PS:这是我很久以前写的,大概是去年刚结束Hitcon2016时写的.写完之后就丢在硬盘里没管了,最近翻出来才想起来写过这个,索性发出来 0x0 前言 Hitcon个人感觉是高质量的比赛,相比国内的C ...
- exim CVE-2017-16943 uaf漏洞分析
前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 这是最近爆出来的 exim 的一个 uaf 漏洞,可以进行远程代码 ...
- 【pwn】学pwn日记——栈学习(持续更新)
[pwn]学pwn日记--栈学习(持续更新) 前言 从8.2开始系统性学习pwn,在此之前,学习了部分汇编指令以及32位c语言程序的堆栈图及函数调用. 学习视频链接:XMCVE 2020 CTF Pw ...
- [pwn基础]Pwntools学习
目录 [pwn基础]Pwntools学习 Pwntools介绍 Pwntools安装 Pwntools常用模块和函数 pwnlib.tubes模块学习 tubes.process pwnlib.con ...
- XSS漏洞学习笔记
XSS漏洞学习 简介 xss漏洞,英文名为cross site scripting. xss最大的特点就是能注入恶意的代码到用户浏览器的网页上,从而达到劫持用户会话的目的. 说白了就是想尽办法让你加载 ...
- Typecho-反序列化漏洞学习
目录 Typecho-反序列化漏洞学习 0x00 前言 0x01 分析过程 0x02 调试 0x03 总结 0xFF 参考 Typecho-反序列化漏洞学习 0x00 前言 补丁: https://g ...
- XXE漏洞学习笔记
XXE 参考文章 名称 地址 一篇文章带你深入理解漏洞之 XXE 漏洞 https://xz.aliyun.com/t/3357 Web Hacking 101 https://wizardforce ...
随机推荐
- 乘风破浪,下载安装体验Adobe XD流程,全新的引导和安装体验设计
简介 Adobe XD是一款适用于网站和应用程序等的快速且功能强大的UI/UX设计解决方案.可实现设计.线框.动画制作.原型创建.协作和共享等,功能一应俱全. https://www.adobe.co ...
- flex中Button事件中的e.target
关于flex中的Button事件中的e.target. 今天想在事件中调用模块中的对象通过e.target获取单击的这个Button对象,但是可能是使用var btn:Button = e.targe ...
- AcWing 99. 激光炸弹
地图上有n个目标,用整数x,y表示目标在地图上的位置,每个目标都有一个价值Wi. 注意:不同目标可能在同一位置. 现在有一种新型的激光炸弹,可以摧毁一个包含r个位置的正方形内的所有目标. 激光炸弹的投 ...
- SpringMVC(6)数据验证
在系列SpringMVC(4)数据绑定-1.SpringMVC(5)数据绑定-2中我们展示了如何绑定数据,绑定完数据之后如何确保我们得到的数据的正确性?这就是我们本篇要说的内容 -> 数据验证. ...
- Redisson 分布式锁源码 11:Semaphore 和 CountDownLatch
前言 Redisson 除了提供了分布式锁之外,还额外提供了同步组件,Semaphore 和 CountDownLatch. Semaphore 意思就是在分布式场景下,只有 3 个凭证,也就意味着同 ...
- varnish配置语言(1)
目录 1. vcl语法 1.1 主体语法 1.2 操作符 1.3 Subroutines 1.4 关键字 2. 内置的Subroutines 2.1 client-side vcl_recv vcl_ ...
- Linux中ftp服务器搭建
一.FTP工作原理 (1)FTP使用端口 [root@localhost ~]# cat /etc/services | grep ftp ftp-data 20/tcp #数据链路:端口20 ftp ...
- layim即时通讯实例各功能整合
一.系统演示1.1 聊天窗体主界面演示 1.2 模拟两人在线聊天(点击图片查看演示视频) 1.3 在线演示> 在线演示,点击进入系统到这里,若是您想要的,接下来听我娓娓道来二.开发工具开发软件: ...
- L inux系统安全及应用---暴力破解密码
系统安全及应用一.开关机安全控制① 调整BIOS引导设置② GRUB限制二.终端登录安全控制① 限制root只在安全终端登录② 禁止普通用户登录举例三.系统弱口令检测① Joth the Ripper ...
- MQTT 4 ——MQTT的Spring Mvc 配置接收字节流数据
本篇记录一下MQTT整合Spring Mvc配置直接收发字节流数据 设备方是纯C开发,并且为了交互数据的安全,将传送的数据用了AES CBC进行了加密. 接下来正常方便做法应该是 将加密后的字节流转换 ...