본문 바로가기
[ ★ ]Study/War Game

[Toddler's Bottle] pwnable.kr uaf 풀이

by nroses-taek 2017. 9. 15.
반응형

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#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;    
}
cs
 
문제의 힌트는 uaf 공부해보라고 하네요.
uaf 구글에서 직접 공부해봅시다.
 
------------시간이 흐르고-------------
(잡담)
흐미 삽질 엄청나게 했네요… uaf 제대로 공부안해서 그런가…
제가 생각한 여러가지 방법들이 있는데, 하나가 case2 브레이크를 걸어서 제가 보낸 파일 값이랑 after 값들을 비교하면서 exploit 해보려고 했는데, 진짜 3시간 삽질한 같네요… 여러가지 방법은 쓸모가 없으니 풀이를 해봅시다.
(끝)
 
main 함수에서 case2 보시면 인자 2개를 넣어줘야 되는 사실을 있습니다
argv[1] argv[2] read 길이를 입력해주면 됩니다.
argv[2] open 함수를 사용했네요.
그러면 argv[1] 길이만큼 argv[2] 파일을 읽어오겠답니다.
우선 exploit하기전에 준비물이 필요하겠죠…
<준비물>
1. give_shell 의 주소
2. open 인자로 보낼 파일
 
이제 프로그램의 흐름을 보겠습니다. Human 아래의 자식 Man Woman 있습니다. 가장 먼저 나온 Man break 걸고 따라가보겠습니다.


ni 명령으로 내려가보겠습니다.


main+272 위치에 왔을 보면, 0x401570 그대로 실행하면 give_shell 따고 기분도 좋을텐데, add rax, 0x8 해주네요. 
, give_shell 피해가게 됩니다.
0x401578 되어서 남자 소개를 하게 되겠죠?
 

이제 저희가 넣어준 인자를 확인해볼 시간입니다.


다시 인자값을 넣어준 , free after 하고 use 해봅시다.
free -> after -> use


1번으로는 부족하니… 2번을 해봅시다.

free -> after -> after -> use
 
똑같이 브레이크 걸린 main+265부분 부터 ni 명령어로 차근차근 내려가보니


이제 인자값이 RAX 레지스터에서 읽혀지는 것을 있습니다.
 
값을 우리가 직접 넣어줄 있는 값이라는 것을 알게되었으니
여기에다가 give_shell 주소를 넣어주면 되겠네요.
아참… 이걸 대충 넘어갔네요.
아까 확인한 give_shell 주소는 0x401570 이었는데 +8 되어서 소개하는 곳으로 넘어갔죠? 그러면 사진에 DDD 분명 +8 더해질 것이란 말입니다.
그러니 give_shell 주소에 -8 해주면 give_shell 주소가 들어갈 것입니다.
add rax, 0x8 있으니깐요! 8 뺏다가 8 더하면 원점이니 !
 
그러면 확인해봅시다.
파일에 write 파이썬 코드를 하나 작성하고
401570 - 8 값을 입력해줍시다.


제대로 들어갔네요 !
 
다시 처음으로 돌아와서

free -> after -> after -> use
하고 ni 명령어로 차근차근 내려가면


입력해준 0x401568값이 들어갔습니다.



add rax, 0x8 명령어를 실행하니 0x401570값이 되었습니다.
이대로 실행하면 give_shell 실행이 되겠죠?


이제 공격을 해봅시다.


yay_f1ag_aft3r_pwning
 
고생하셨습니다.


반응형

댓글