보안/암호학

[Dreamhack][암호학] 집가고시프다

playalone 2026. 7. 12. 08:25

[문제링크](https://dreamhack.io/wargame/challenges/3021)

 

문제를 다운로드하여보면 구성은 다음과 같다.

 

문제를 보니 일반 pwnable이랑 구성이 비슷하다. chall 파일이 있고, flag.txt가 있다.

 

chall.enc를 읽어보면

와.... 이거 쉽지 않다. 

 

hint.txt를 보면 다음과 같이 쓰여있다.

"X or going_to_home"

 

이게 뭘까... 곰곰이 생각해 보니

X or going_to_home

Xor going_to_home

xor "going_to_home"

이 된다. 

 

일단 chall.enc를 going_to_home으로 xor 해보겠다.

data = open("chall.enc", "rb").read()
key = b"going_to_home"
key = (key * (len(data) // len(key) + 1))[:len(data)]

print(bytes(a ^ b for a, b in zip(data, key)).decode())

오 뭔가 cpp 같은 코드가 나온다.

 

이를 cpp파일로 옮긴 후 분석을 해보겠다.

void read_flag(){
    ifstream itzfile("flag.txt");
    string flag;
    if(itzfile.is_open()){
        getline(itzfile,flag);
    }
    cout<<flag;
}

flag를 보여주는 것은 여기 있다.

 

이를 호출하는 함수는

void going_out(int n){
    if(n!=1){
        cout<<"hack detected! terminating...";
        return;
    }
    cout<<"i checked who you are. you need to pass the test\n";
    int a;
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<int> distrib(10000,100000);
    int door=distrib(gen);
    cout<<"type "<<door<<"\n";
    cin>>a;
    if(a==door){
        cout<<"bye! i'll give you a key~\n";
        read_flag();
        return;
    }
    cout<<"say the number!";
    //breaking bad reference
    return;
}

여기 있고, 이를 호출하는 함수는 

int main(){
    signal(SIGALRM,yaza_end);
    alarm(5);
    string a;
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<int> distrib(1,10);
    cout<<"어서 자신의 집가고시픔을 어필해 주세요!\n\n";//zip gagohipheum
    int auth=0;
    while(1){
        getline(cin,a);
        int luck=distrib(gen);
        if(luck==1)cout<<"응 안돼 돌아가\n";//return 0
        else if(luck==2)cout<<"되겠냐?\n";//yey!
        else if(luck==3)cout<<"집중 공부 실시\n";//shihumgigan
        else if(luck==4)cout<<"아따 이러고 자빠졌네잉~\n";//i fall down
        else if(luck==5)cout<<"얼마 줄건데~~~\n";//u-chi
        else if(luck==6){
            if(a.compare(0,3,"key")==0){
                cout<<"it's a ";//noice grammer~
                auth++;
            }
            cout<<"random text6\n";
        }
        else if(luck==7)cout<<"6번과 10번에서 내가 바로 대답하지 않은 이유는 당연해서가 아니다\n";
        else if(luck==8)cout<<"참고로 이거 java로 썼다\n";//hutsori
        else if(luck==9)cout<<"헛소리 집어치워!\n";//hutsori2
        else if(luck==10){
            if(a.compare(0,10,"secretcode")==0 && auth==1){
                going_out(auth);
                return 0;
            }else{
                cout<<"나갈 기회는 충분하다!\n";//or not?
            }
        }
    }
}

여기 있다.

 

going_out함수를 보면, 10000~100000이 uniform 분포로 door에 설정되고 door를 타이핑하면 된다.

going_out함수를 실행하는 부분을 보면, 입력이 secretcode여야 하며, auth는 1이어야 한다.

auth를 1로 하는 부분은 luck이 6일 때 입력이 key여야 한다.

 

즉, 정리하면

luck이 6일 때, 입력이 "key"

luck이 10일 때, 입력이 "secretcode"

type {n}이 출력되면, 입력이 "{n}"

하면 flag가 나온다.

 

이를 python 코드로 작성하면

 

from pwn import *

p = remote("host3.dreamhack.games", 23162)

p.recvuntil("어서 자신의 집가고시픔을 어필해 주세요!\n\n")

# luck이 랜덤이기에 6이 나올 때까지 반복
six_detected = False
while(not six_detected):
    p.sendline(b"key")

    response = p.recvline().decode()
	# luck이 6일때 나오는 텍스트
    if(response == "it's a random text6\n"):
        six_detected = True

# 마찬가지로 luck이 랜덤이기에 10이 나올 때까지 반복
ten_detected = False
while(not ten_detected):
    p.sendline(b"secretcode")

    response = p.recvline().decode()
	# luck이 10일때 나오는 텍스트
    if(response == "i checked who you are. you need to pass the test\n"):
        ten_detected = True

# 형식이 "type {n}"임
typeNumber = p.recvline().decode().split("type ")[1]

p.send(f"{typeNumber}".encode())

p.interactive()

다음과 같고, 이를 실행하면

flag를 얻을 수 있다.