#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;
}
uaf에 대한 공부는 했었지만 실제로 문제로 접해본 것은 처음이었다.
개념은 간단히 heap 영역에 메모리를 할당과 해제할 때,
메모리 할당 크기에 따라서 bin이라는 그룹 개념으로 관리한다.
그리고 메모리 해제 후 해당 메모리와 같은 그룹의 메모리를 재할당하면, 이전에 해제한 주소에 할당을 하게 된다.
이 때 파일 시스템에서 flags값만 지우고 데이터가 남아있는 것처럼
heap에서도 남아있는 데이터가 leak과 reuse가 가능해지는 취약점이다.
이 문제에서는 가장 작은 그룹인 fastbin을 사용하는 것으로 보인다.
애매하게 적은 이유는 fastbin의 경우 8~64byte의 메모리를 할당할 경우
80byte씩 할당을 해준다고 하는데, man과 woman 다 80byte를 할당 받았지만
data에 할당을 8~24의 크기로 할 때만 해당 영역을 할당 받았다.
bin에 대한 자세한 정보는 나중에 필요하면 더 보는 거로 ㅎ
위 함수가 new Man("Jack", 25)에 해당하는 코드로 보인다.
할당되는 heap 주소가 arg[0]이다.
Woman의 경우 main+173에 new Woman("Jill", 21)이 있다.
할당을 한경우 위와 같이 데이터가 들어간다.
입력값 1을 사용했을 경우 ->introduce();를 실행하는 부분인데,
할당된 주소에서 +8값을 rdx에 넣고, rdx를 콜한다.
해당 주소와 rdx값을 확인해보면 introduce()함수를 호출하는 것을 재확인 할 수 있다.
이후 free된 상태에서의 메모리 정보이다.
Linked list의 형태로 사용가능한 영역들을 가리키고 끝에는 0을 가리킨다.
메모리 할당을 통해 해당 주소를 한번 덮고, 다시 call rdx 부분으로 돌아가면
원래 m->introduce();의 코드가 [[m]+8]을 호출하는 거에서
내가 재할당해서 덮은 값 +8(0x401568+8 == 0x401570 --> 0x40117a <give_shell>)을 호출하게 된다.
call rdx 시점에서의 rdx값이다.
이렇게 하면 give_shell 함수 호출로 쉘을 얻게되고 플래그를 얻을 수 있다.
주소값은 그냥 tmp폴더에 파일에다가 주소값 넣어주고, argv[2]로 전해주면 된다.
'Pwnable.kr' 카테고리의 다른 글
Pwnable.kr [asm] (0) | 2019.05.08 |
---|---|
Pwnable.kr [memcpy] (0) | 2019.05.08 |
Pwnable.kr [cmd2] (0) | 2019.05.03 |
Pwnable.kr [cmd1] (0) | 2019.05.02 |
Pwnable.kr [lotto] (0) | 2019.05.02 |