uaf

Mommy, what is Use After Free bug?

ssh [email protected] -p2222 (pw:guest)
#include 
#include 
#include 
#include 
#include 
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;
}

从IDA中可以看出,C++中对一个对象的实例化操作(如Human *m = new Man(“Jack”, 25);)分为6个调用的过程.

std::allocator::allocator(void)
std::allocator>::basic_string
operator new(ulong)
Man::Man()
std::allocator>::~basic_string()
std::allocator::~allocator()

uaf_第1张图片
其中,第3步代表new分配内存的过程.从mov edi,30h中可以看出,这个对象占用48字节的内存空间.第4步相当于是执行构造函数的过程.当第4步执行完成了之后,该对象对应的虚表指针和虚表都已经分配了内存并进行了初始化.我们可以从gdb-peda中看出这一过程.
uaf_第2张图片
其中A,即0x555555768e70代表的是实例化对象m的地址.地址A指向的内容的前8个字节是B,即0x555555755c88.指针B指向的内容的前8个字节是C,即0x555555555504.可以看出,C对应的正是虚函数Human::give_shell()的地址.由此可见,指针B代表的正是实例化对象m的虚表指针.根据虚函数的知识我们知道,虚表指针B指向的内存块中存放的是各个虚函数的地址.如C代表的正是这样的第一个虚函数的地址.即虚函数Human::give_shell()的地址.uaf_第3张图片
从上图中可以看出,指针A指向的内容分别是指针B(实例化对象m的虚表指针),0x0000000000000019(代表m的年龄,25岁),其中0x000000006b63614a代表的是’Jack’,4ah代表J,61h代表a,63h代表c,6bh代表k.
指针B指向的内容分别是虚函数Human::give_shell()的地址,虚函数Man::introduce()的地址,ZTI5Human的地址,虚函数Human::introduce()的地址,虚函数Human::give_shell()的地址.

在释放m和w占用的内存之后,m和w占用的内存就空闲出来了.所以后续分配的内存会占用在释放m和w之前它们占用的内存.而m或者w对象占用的内存的前8个字节都是虚表指针,因此将虚表指针的值,即地址减去8,
uaf_第4张图片
如上图所示,即可以完成执行introduce虚函数时实际上执行的是give_shell虚函数.

参考:
virtual function in C++

你可能感兴趣的:(Linux)