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

}


User After Free


동적할당(Dynamic memory allocated) 된 heap을 free하고 다시 재사용(Dynamic memory reuse) 할 때에 취약점이 발생할 수 있다.


Deferred Coalescing (병합 지연)

malloc -> caching free된 heap이 다음에 realloc될 때에 같은 사이즈로 요청받을 수 있습니다. 이 때 heap을 병합하거나 분할하는 시간을 절약하고자 free된 heap을 남겨뒀다가 reuse할 때 그대로 쓰게 해주는 방법입니다.



         --->>>gdb--->>>>


분기문이 있고 1을 입력했을 경우를 introduce()가 실행되는 과정에서 introduce 주소의 위치를 알아야 하기 때문에 main+265에 bp를 걸고 프로그램을 실행시켜 보자.  0x400fcd로 jmp하고 차례대로 코드가 실행 될 것이다. 



코드를 보면 Human 클래스의 virtual function인 give_shell()을 호출하는 부분이 보이지 않는다하지만 같은 클래스의 객체끼리 가상함수를 모아 놓고 사용하는 개념인 vtable을 이용해 1 use에서 introcude() 호출 대신 give_shell()를 호출하도록 만든 것이다.



main+286에서 함수를 call하는데 introduce() 함수를 실행하는 부분이다.

main+272 부분에서 rax에 give_shell 함수의 주소에 +8을 해준다 이 값이 rdx로 들어가는 것을 알 수 있다.

아래와 같이 간단하게 확인해 보니까 맞다는 것을 알 수 있다.



다음으로 힙에 할당된 Man객체를 내부를 보기로 한다.

heap에 이름이 있는데 객체는 name 문자열의 포인터를 가지고 있다.



Man의 객체아래 바로 Woman의 객체도 함께 생성되어 있는 것을 볼 수 있다.



tmp/oieh/file에 "AAAA"를 써주고 프로그램을 실행 시켰다.




3 -> 2 ->1 한번만 free를 해주고 데이터를 썻더니 w->introduce()는 덮혔지만

m->introduce() 주소가 0x00000000으로 되어 프로그램 segment fault가 떠 종료된다.


그리하여 3 -> 2 -> 3 -> 2 -> 1 과 같이 두번 free와 data을 썻다.

아래와 같이 의도한 메모리 위치에 값을 넣어 줄 수 있었다.


"AAAA"문자열 대신에 0x401570(introduce함수) -0x8 = 0x401568(give_shell함수)값을 넣어주면 쉘이 실행된다. 




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

18.pwnable asm  (0) 2018.02.28
17.pwnable memcpy  (0) 2018.02.28
15.pwnable cmd2  (0) 2018.02.23
14.pwnable cmd1  (0) 2018.02.23
13.pwnable lotto  (0) 2018.02.23

+ Recent posts