首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >二进制学习系列-堆溢出

二进制学习系列-堆溢出

作者头像
安恒网络空间安全讲武堂
发布于 2018-09-21 07:03:35
发布于 2018-09-21 07:03:35
9680
举报

Pwnable-UAF

这道题主要考察的是虚函数的内存地址空间以及UAF的使用

所需知识:

1.虚函数的内存地址空间:

在C++中,如果类中有虚函数,那么它就会有一个虚函数表的指针__vfptr,在类对象最开始的内存数据中。之后是类中的成员变量的内存数据。 对于子类,最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。 之后是子类自己的成员变量数据。

单继承,无虚函数重载:

单继承,有虚函数重载:

总结

  • 如果一个类中有虚函数,那么就会建立一张虚函数表vtable,子类继承父类vtable,若,父类的vtable中私有(private)虚函数,则子类vtable中同样有该私有(private)虚函数的地址。注意这并不是直接继承了私有(private)虚函数
  • 当子类重载父类虚函数时,修改vtable同名函数地址,改为指向子类的函数地址,若子类中有新的虚函数,在vtable尾部添加。
  • vptr每个对象都会有一个,而vptable是每个类有一个,vptr指向vtable,一个类中就算有多个虚函数,也只有一个vptr;做多重继承的时候,继承了多个父类,就会有多个vptr

详情知识请移步:https://bbs.pediy.com/thread-224651.htm

2.Use-After-Free

Dangling pointer:

指向被释放的内存的指针。

成因:释放掉后没有将指针重置为NULL.简单来说就是因为分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存.

UAF:

对上面所说的指针进行利用,引用到自己想引用的函数上等等。

3.SLUB:

SLUB:系统内存分配机制。

对对象类型没有限制,两个对象只要大小差不多就可以重用同一块内存,而不在乎类型是否相同样的话,同一个笼子既可以放鸡,又可以放鸭。也就是说我们释放掉sock对象A以后马上再创建对象B,只要A和B大小相同(不在乎B的类型),那么B就极有可能重用A的内存。SLAB差不多,只不过要求类型也要相同。

既然B可以为任意对象类型,那我们当然希望选择一个用起来顺手的对象类型。至少要符合以下2个条件:

1.用户可以控制该对象的大小

2.用户空间可以对该对象写入数据

Pwnable-UAF详解:

源代码:

快速浏览一遍过后我们可以观察到主要的Human和Man、Woman三个类,Human是父类,其余是继承了的子类,并且两个子类都重写了父类中的introduce函数,我们还注意到了父类中的getshell私有函数,所以我们之后肯定会用到它。由前者的知识点我们可以明白,三个类中都有虚函数,所以每个类都有一个vtable表来存储虚函数,并且两个子类都继承了父类的vtable表,并且也有父类私有虚函数的getshell虚函数。

所以我们可以想到利用子类的构造函数,来跟随找出vtable,再利用getshell虚函数地址来继续。

main函数中after那一段的作用是分配一段地址空间,我们可以利用已经被free的内存重新allocate一个可控的地址空间。

所以我们的思路是:

1.找到getshell虚表的地址

2.找到vtable的地址

3.重写覆盖vptr指针指向地址

4.free后再allocate得到可控地址

1.getshell虚表地址

由于我是本地自己重新把平台上的cpp文件编译了一遍,所以地址和平台上环境地址会不一样。(后来我才明白是因为自己编译cpp文件的时候所使用的参数不同的原因,比如gcc -g uaf.cpp -o uaf和不加-g是有区别的) 以上可以看见getshell虚函数在vtable中的地址为0x4012ea,也可以在gdb中调试,来查看getshell地址。

2.vtable地址

找到man的构造函数

在0x401084处下断点,用gdb调试

p /x $ebx的作用是打印出实例化man对象的地址,而后查看man对象的内存地址空间,因为虚表指针在首部,所以我们找到了虚表的地址是0x401668

3.重写覆盖

我们首先得需要找到虚表指针引用introduce函数时候的偏移量:

我们可以大致推测出v12和v13是同一个vptr指针,偏移+8后刚好是getshell地址+8后的introduce函数地址,所以我们可以开始利用,把vtable表的地址-8,即把vptr指针指向的地址-8时,就可以在程序运行use段时引用introduce函数的时候实则引用的是getshell函数。

4.allocate

可以看到原来man对象分配到的空间是0x30,即48字节,所以当我们再次分配的时候也要分配48字节,保证自己拿到的是原先被free掉的地址空间。

利用:

由于先free掉的是m,所以当我们分配第一次的时候得到的是w所指向的空间,所以我们需要分配两次得到m所指向的空间再来利用。 因为这题是从文件中读出内容覆盖,所以我们可以使用python -c来写入转变成不可见字符(由于我试过直接在文档里面写十六进制的地址没法被读取,所以才明白要转变成不可见的字符)。

程序在case2中读取数据的填充到data空间的时候,开始的八字节就是vtable。之后是类的数据。(因为geshell表+8字节后就是introduce表,所以推测读取的地址为8字节一个段)

0x401668-0x8=0x401660 python -c ' print "\x60\x16\x40\x00\x00\x00\x00\x00" ' > /tmp/exp ./uaf 48 /tmp/exp

getshell
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 恒星EDU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
UAF Writeup - pwnable.kr
0x00 UAF — pwnable.kr是一个韩国的CTF练习的网站,有很多经典的CTF题目供爱好者练习。 UAF(Use After Free)释放后重用,其实是一种指针未置空造成的漏洞。在操作系统中,为了加快程序运行速度,如果释放一块n字节大小的内存空间,当申请一块同样大小的内存空间时,会将刚刚释放的内存空间重新分配。如果指向这块内存空间的指针没有置空,会造成一系列的问题。 0x01 Fastbin — fastbin顾名思义,fast就是要快。所以fastbin旨在加快操作系统的内存分配速度,f
xfkxfk
2018/03/29
1K0
UAF Writeup - pwnable.kr
C++虚函数表原理浅析
C++中的虚函数实现了多态的机制,也就是用父类型指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数,这种技术可以让父类的指针有“多种形态”,这也是一种泛型技术,也就是使用不变的代码来实现可变的算法
ACM算法日常
2021/04/22
1.9K0
C++虚函数表原理浅析
C++面试题
一般指的是某块内存的地址,通过这个地址,我们可以寻址到这块内存;而引用是一个变量的别名。指针可以为空,引用不能为空。
thierryzhou
2022/12/01
2K0
虚函数——从一个bug谈起
在面向对象编程中,尤其是在C++中,虚函数是实现多态性的核心机制之一。虚函数通过允许在运行时决定调用哪个版本的函数,使得不同类型的对象能够对相同的函数调用做出不同的响应。
程序员的园
2024/12/05
2130
虚函数——从一个bug谈起
c++头脑风暴-多态、虚继承、多重继承内存布局
gdb怎么用这里就不展开了,默认你会使用gdb,使用gdb设置打印格式,然后看对象people的内存布局及大小,如下:
cpp加油站
2021/06/29
8240
图说C++对象模型:对象内存布局详解
0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局、虚表指针、虚基类指针等有深入了解的朋友可以慢慢看。 本文的结论都在VS2013上得到验证。不同的编译器在内存布局的细节上可能
Tencent JCoder
2018/07/02
5.1K0
【ES三周年】C++多态
凡是面向对象的语言,都有三大特性,继承,封装和多态,但并不是只有这三个特性,是因为者三个特性是最重要的特性,那今天我们一起来看多态!
The sky
2023/04/11
4460
【ES三周年】C++多态
【C++】继承和多态扩展学习
继承的文章中我们讲到C++的多继承就会引发一些场景出现菱形继承,有了菱形继承,就会出现数据冗余和二义性的问题,C++又引入了虚继承来解决数据冗余和二义性。
ZLRRLZ
2025/07/23
990
【C++】继承和多态扩展学习
面试系列之C++的对象布局【建议收藏】
我们都知道C++多态是通过虚函数表来实现的,那具体是什么样的大家清楚吗?开篇依旧提出来几个问题:
C语言与CPP编程
2020/12/02
1.8K0
面试系列之C++的对象布局【建议收藏】
再探虚函数
也称为编译期间的多态,编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。
看、未来
2021/10/09
1K0
再探虚函数
【C++深度探索】全面解析多态性机制(二)
虚函数表(Virtual Function Table,VTable)是C++中实现动态多态性的一种机制。每个包含虚函数的类都有一个对应的虚函数表,用于存储该类的虚函数地址。
大耳朵土土垚
2024/07/16
1710
【C++深度探索】全面解析多态性机制(二)
【C++篇】虚境探微:多态的流动诗篇,解锁动态的艺术密码
虚函数表(Virtual Table, VTable)是 C++ 实现运行时多态的核心机制。它是一个存储虚函数指针的数组,每个包含虚函数的类都至少有一个虚表。当一个类的虚函数被调用时,程序并不是直接调用函数的地址,而是通过虚函数表间接调用。每个对象实例都会保存一个指向虚表的指针(vptr),通过 vptr,程序可以找到对象对应的虚函数实现。
半截诗
2024/10/11
2540
【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“
同样有关运算符重载的知识这里也不再过多讲解,在类和对象中已经讲的很详细了,忘了就快去复习一下吧!! 👉 C++ 类和对象 进阶篇
换一颗红豆
2025/04/01
2080
【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“
C++为什么要弄出虚表这个东西?
首先回顾一下C语言纯POD的结构体(struct)。如果用C语言实现一个类似面向对象的类,应该怎么做呢?
果冻虾仁
2021/12/08
6440
C++为什么要弄出虚表这个东西?
《逆袭进大厂》之C++篇49问49答
,这些都是我自己整理的秋招笔记,一把屎一把尿慢慢总结出来的那种,这些笔记可以说对我帮助良多。
DeROy
2021/02/05
2.2K0
《逆袭进大厂》之C++篇49问49答
一步步分析-C语言如何面向对象编程
在嵌入式开发中,C/C++语言是使用最普及的,在C++11版本之前,它们的语法是比较相似的,只不过C++提供了面向对象的编程方式。
IOT物联网小镇
2021/05/13
9570
一步步分析-C语言如何面向对象编程
【C++】多态 ⑦ ( 多态机制实现原理 | 虚函数表概念 | 虚函数表工作机制 | vptr 指针 | 虚函数表运行时机制 | 虚函数与动态联编 )
满足 ① 继承 , ② 虚函数重写 , ③ 父类指针/引用指向子类对象 三个条件 , 即可实现多态 ;
韩曙亮
2023/11/01
5140
【C++】多态 ⑦ ( 多态机制实现原理 | 虚函数表概念 | 虚函数表工作机制 | vptr 指针 | 虚函数表运行时机制 | 虚函数与动态联编 )
虚实穿梭:用C++多态解锁代码的“平行宇宙”(2)
"程序员阁下,您是否见过会自我进化的代码?" 在C++的奇幻大陆上,存在着这样一群神秘生物:
用户11295429
2025/05/19
1020
虚实穿梭:用C++多态解锁代码的“平行宇宙”(2)
【C++】从零开始认识多态
面向对象技术(oop)的核心思想就是封装,继承和多态。通过之前的学习,我们了解了什么是封装,什么是继承。
叫我龙翔
2024/05/08
1240
【C++】从零开始认识多态
深度解读《深度探索C++对象模型》之C++虚函数实现分析(一)
假如有这样的一段代码,代码中定义了一个Object类,类中有一个成员函数print,通过以下的两种调用方式调用:
爱分享
2024/04/23
4600
相关推荐
UAF Writeup - pwnable.kr
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档