-
-
[翻译]第四部分:Use-After-Free(Pwnable -> uaf)
-
发表于: 2019-5-27 11:08 7376
-
在下面的讲述中,我们将研究 pawnable.kr 上的 UAF 挑战。这是一个 64 位的 Linux UAF 漏洞。把 UAF 放在此处像是给新手一记耳光(为什么你的技术没有 b33f 的好?)事实上它并没有想象中那么可怕,让我直接开始把。
展开新的挑战
我们同样地会向大家展示二进制文件的源代码,如下所示。
#include <fcntl.h> #include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> 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. use\n2. after\n3. free\n"; 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; }
#include <fcntl.h> #include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> 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. use\n2. after\n3. free\n"; 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; }
多花费些时间仔细阅读代码。首先,当程序初始时,它会创建一个 "man" 和 "woman" 对象。请参阅下面主函数 prolog 的摘录。
注意分配给两个对象的大小 0x18(24字节)(这是 malloc 的最小分配?)。其中含有 str“jack” + 0x19(25) 和 str"jill" + 0x15(21)。
在 prolog 之后,我们到达带有分支选项的菜单。从源代码中明显可以看这里存在一个问题,如果先选择 "free" 再选择 "use",程序将尝试删除 "man" 和 "woman" 对象调用的
introduction 方法,进而导致一个段错误。
留下的 "after" 选项。它有个两个参数(在运行时提供)。第一个参数是整数,用于从文件中读取 x 个字节,第二个参数是文件路径,
现在,我们可以非常坦率地选择 "free" 选项,然后分配我们的自定义对象(具有相同的大小),我们应该可以在使用 "use" 菜单选项引用数据时获得某段代码的 exec 执行语句。
最后剩下的问题就是如何完成挑战目标? human 类有一个名为 "give_shell" 的私有方法,它将为我们生成一个 bash shell,这看起十分简单。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2019-5-28 09:15
被Liary编辑
,原因:
赞赏
他的文章
看原图
赞赏
雪币:
留言: