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 ...
随机推荐
- AtCoder Grand Contest 012 B
B - Splatter Painting Time limit : 2sec / Memory limit : 256MB Score : 700 points Problem Statement ...
- Windows下DVWA安装指南
注意:DVWA需要依赖httpd.PHP.MySQL.php-mysql等应用或组件,最简单的方法是安装wampserver(http://www.wampserver.com/),安装完了所需的各种 ...
- JSP九大内置对象的作用和用法总结【转】
JSP九大内置对象的作用和用法总结? JSP中一共预先定义了9个这样的对象,分别为:request.response.session.application.out.pagecontext.c ...
- 【转】Java集合:HashMap源码剖析
Java集合:HashMap源码剖析 一.HashMap概述二.HashMap的数据结构三.HashMap源码分析 1.关键属性 2.构造方法 3.存储数据 4.调 ...
- 【转】android技术栈
android技术栈-现有使用的进行一个汇总(初稿) 2017年04月24日 16:19:40 阅读数:2004 android技术栈 开发工具 Android studio 开发语言 Java 自动 ...
- T4312 最大出栈顺序
题目描述 给你一个栈和n个数,按照n个数的顺序入栈,你可以选择在任何时候将数 出栈,使得出栈的序列的字典序最大. 输入输出格式 输入格式: 输入共2行. 第一行个整数n,表示入栈序列长度. 第二行包含 ...
- JS编写自己的富文本编辑器
富文本编辑器,网上有很多功能齐全种类丰富的如百度的Ueditor,简单适用型的如WangEditor等等.在经过一番挑选后,我发现都不适用现在的项目,然后决定自己造轮子玩玩.富文本编辑器中主要涉及到J ...
- IOS之UIStepper控件详解
在iOS5中新增了一个数字输入控件UIStepper,它可以递进式输入数量.UIStepper继承自UIControl,它主要的事件是UIControlEventValueChanged,每当它的值改 ...
- Quartz使用一 通过getJobDataMap传递数据
Quartz定时器使用比较广泛,介绍一点简单的使用 上代码:定义一个Job,执行具体的任务 package org.tonny.quartz; import java.text.SimpleDateF ...
- RFS自动化测试(一)
RFS 即 Robot Framework + Selenium RFS 的安装 1. python https://www.python.org/ RF框架是基于python的,所以要先安装有pyt ...