c++的逆向还是要熟悉下。
一、关于c++虚函数
虚函数使得c++能够实现多态,每个类有一个虚表,每个对象在实现的时候如果重新实现了虚函数,则修改虚表中对应的指针,否则将调用原本指针指向的函数。
在gdb中调试看看:
这里是Man对象实现的位置,先通过new从堆中申请了一块大小为0x18的空间,然后调用构造函数。gdb在0x400f00处下断:
执行外new后通过rax的值我们得知分配的地址为0x614c50,继续n直到执行完构造函数,此时再查看对象Man的结构:
其中0x19是年龄的整型数,0x614c38存放的是姓名字符串"Jack",那么0x401570呢?
ida中已经有了注释这是Man的vtable也就是传说中的虚表,而后面对Man::introduce的调用:
*v13+8即为Man结构体的第一项0x401570再加8,从而调用了introduce函数。
二、get shell
uaf的思路就是先选功能3,执行delete(Man) 、delete(Woman),接着再选2,申请两块大小为0x18的空间,此时分配给我们的空间就是原本应该属于Woman和Man的空间。
这里需要两个命令行参数,第一个是读取的字节数,第二个是读取的文件,这里把字节数设为0x18,则文件内容就会覆盖Man和Woman的结构体,从而可以修改虚表,从而执行give_shell (0x40117a)
先找到一块指向0x40117a的内存(其实也就是虚表中的项)
记得虚表第一项是give_shell的地址,功能1调用的introduce是第二项,需要+8,反过来我们需要构造-8
python -c "print '\x48\x15\x40\x00\x00\x00\x00\x00'+'A'*16" > data
功能1调用虚函数introduce时,实际上调用
0x614c50 ---> 0x401548
0x401548+8 --->0x40117a
getshell!
PS:最后还遇到一个小坑,ssh过去之后直接>data没有权限,最后查到是要写到/tmp/路径下
— — " linux下的tmp目录是一个系统产生临时文件的存放目录,其权限是drwxrwxrwt(777),就是对每个用户都可以对他进行读写操作 "
鶸泪目。
网友评论