Yozzang의 해킹일기 💻
article thumbnail
Published 2022. 7. 20. 00:38
Pwnable (16. uaf) Wargame/Pwnable
728x90

이번 포스트에서는 Pwnable의 uaf 문제에 대해 다루겠다.

 


문제 코드는 다음과 같다.

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

## 문제 해석 :

main() 함수 위주로 살펴보니, use, after, free 3가지의 선택지가 있고 각 선택지는 다음과 같이 동작한다.

  1. use : 각 개체의 introduce() 함수 실행
  2. after : char 객체 생성
  3. free : man, woman 객체 초기화

또한 Human 클래스의 give_shell() 함수를 통해 쉘을 딸 수 있는 것으로 보인다.

## 문제 풀이 :

man과 woman 객체를 free를 통해 초기화한 다음에, after를 통해 같은 크기의 새로운 char 객체를 생성한 다음에, introduce() 함수의 주소 대신 give_shell() 함수의 주소로 덮어씌우면 된다.

 

그럼 먼저 give_shell()의 주소를 알아보겠다.

main

286번째줄을 보면 call 함수를 통해 rdx가 호출된 것을 알 수 있다. 여기서 아마 rdx가 바로 introduce() 함수일 것이다. 또한 이전에 rdx는 rax에 0x8이 더해진 것을 알 수 있다. rax의 값을 확인해보겠다.

main+272

확인해본 결과 give_shell() 함수의 주소값이 0x40117a인 것을 알 수 있다. 즉, 0x401570가 가리키는 주소값이 0x40117a(give_shell())이다.

 

그러나 introduce() 함수가  rax+0x8 후에 실행한 것으로 보아 give_shell() 함수를 실행하려면 역시 rax+0x8 한 후의 값을 실행해야 하므로, 우리는 구해진 0x401570에다가 0x8를 빼야한다. 즉, 0x401568를 넣어야한다.

## 최종 결과 : 

### 공격문 : python -c "print '\x68\x15\x40\x00'" > /tmp/jy05un_uaf/exploit

### 실행 결과 :

공격 실행

Flag = yay_f1ag_aft3r_pwning


## 추가 해석 : 

 

after를 2번 실행한 이유는 free에 m과 w 객체를 동시에 delete() 했기 때문이다. 즉, after를 한 번 실행하면 LIFO(Last In First Out) 구조에 의해서 w만 할당되고 main() 함수에서 m이 w보다 먼저 실행하기 때문에 m까지 할당해주어야한다.

case 3:
	delete m;
	delete w;
	break;

'Wargame > Pwnable' 카테고리의 다른 글

Pwnable (18. asm)  (0) 2022.09.13
Pwnable (17. memcpy)  (0) 2022.07.21
Pwnable (15. cmd2)  (0) 2022.07.13
Pwnable (14. cmd1)  (0) 2022.07.12
Pwnable (13. lotto)  (0) 2022.07.11
profile

Yozzang의 해킹일기 💻

@요짱

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!