首页
社区
课程
招聘
[翻译]第四部分:Use-After-Free(Pwnable -> uaf)
发表于: 2019-5-27 11:08 7376

[翻译]第四部分: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编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//