前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >二进制学习系列-堆溢出

二进制学习系列-堆溢出

作者头像
安恒网络空间安全讲武堂
发布2018-09-21 15:03:35
9110
发布2018-09-21 15:03:35
举报
文章被收录于专栏:安恒网络空间安全讲武堂

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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Pwnable-UAF
    • 1.虚函数的内存地址空间:
      • 总结
        • 2.Use-After-Free
          • Dangling pointer:
            • UAF:
              • 3.SLUB:
                • Pwnable-UAF详解:
                相关产品与服务
                对象存储
                对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档