반응형
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
고생하셨습니다.
반응형
'[ ★ ]Study > War Game' 카테고리의 다른 글
[Toddler's Bottle] pwnable.kr asm 풀이 (0) | 2017.09.16 |
---|---|
[Toddler's Bottle] pwnable.kr codemap 풀이 (0) | 2017.09.15 |
[Toddler's Bottle] pwnable.kr cmd2 풀이 (3) | 2017.09.15 |
[Toddler's Bottle] pwnable.kr cmd1 풀이 (0) | 2017.09.15 |
[Toddler's Bottle] pwnable.kr lotto 풀이 (0) | 2017.09.15 |
댓글