CTF

[2023 JBU CTF] solve it write-up

e_yejun 2023. 10. 28. 22:42

๋ถ„์•ผ : Reversing

๐Ÿง ๋ฌธ์ œ

๋ฌธ์ œ๋ช… : solve it

ํžŒํŠธ : ๋ฌธ์ œ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์–ด์„œ ๋ฌธ์˜๋ฅผ ํ–ˆ๋”๋‹ˆ, ๋‚˜๋ณด๊ณ  ์ง์ ‘ ์ˆ˜์ •ํ•˜๋ผ๊ณ  ํ•œ๋‹ค. ์ด๊ฒŒ ๊ฐ€๋Šฅํ•ด?

 

๊ฐ€์งœ ๋ฌธ์ œ๋“ค์„ ๋ชจ๋‘ ํ’€๋ฉด fake flag๊ฐ€ ๋‚˜์˜จ๋‹ค. ์ง„์งœ ํ”Œ๋ž˜๊ทธ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ํ•ด๋‹น exeํŒŒ์ผ์ด pyinstaller๋กœ ๋งŒ๋“ค์–ด์ง์„ ์ธ์ง€ํ•˜๊ณ , ์ด๋ฅผ ๋””์ปดํŒŒ์ผ ํ•˜๋ฉด ์†Œ์Šค์ฝ”๋“œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ  ํ”Œ๋ž˜๊ทธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

 

 

๐Ÿšจ ๊ฐ€์งœ ๋ฌธ์ œ ๋ชฉ๋ก

self.questions = [
            {
                'question': "Q1. ์›น ํ•ดํ‚น ๊ธฐ๋ฒ•์ด ์•„๋‹Œ ๊ฒƒ์€?",
                'choices': [
                    "SSTI",
                    "CSP",
                    "SSRF",
                    "CSRF",
                    "SQLi"
                ],
                'correct_choice': "CSP",
            },
            {
                'question': "Q2. 2022๋…„๋„ NIST์— ์„ ์ •๋œ ์–‘์ž ๋‚ด์„ฑ ์•”ํ˜ธ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์€?",
                'choices': [
                    "FALCON",
                    "SPHINCS+",
                    "CRYSTALS-KYBER",
                    "Lizard",
                    "CRYSTALS-DILITHIUM"
                ],
                'correct_choice': "Lizard"
            },
            {
                'question': "Q3. ๋‹ค์Œ ์ค‘ ์Šคํƒ์˜ ์ตœ์ƒ๋‹จ์„ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ ˆ์ง€์Šคํ„ฐ๋Š”?",
                'choices': [
                    "ebp",
                    "edx",
                    "eax",
                    "eip",
                    "esp"
                ],
                'correct_choice': "esp"
            },
            {
                'question': "Q4. ๋‹ค์Œ ์ค‘ ํœ˜๋ฐœ์„ฑ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์€?",
                'choices': [
                    "๋ ˆ์ง€์ŠคํŠธ๋ฆฌ",
                    "์›๊ฒฉ ์‚ฌ์šฉ์ž ์ •๋ณด",
                    "๋„คํŠธ์›Œํฌ ์นด๋“œ ์ •๋ณด",
                    "ARP ํ…Œ์ด๋ธ”",
                    "์ธํ„ฐ๋„ท ์‚ฌ์šฉ ๊ธฐ๋ก"
                ],
                'correct_choice': "๋ ˆ์ง€์ŠคํŠธ๋ฆฌ"
            },
            {
                'question': "Q5. 0x16 + 0b10110 = ?(10์ง„์ˆ˜)",
                'choices': [
                    "39",
                    "40",
                    "42",
                    "44",
                    "45"
                ],
                'correct_choice': "44"
            }
        ]

 

 

๐Ÿšจ ์ง„์งœ ํ”Œ๋ž˜๊ทธ

def check_answer(self):
        flag_arr = [[115, 99, 112, 67, 84, 70, 123, 102, 97, 107, 101, 95, 102, 108, 97, 103, 32, 58, 32, 80, 125],
                                        [115, 99, 112, 67, 84, 70, 123, 104, 101, 49, 49, 111, 95, 112, 89, 116, 104, 48, 110, 95, 53, 48, 85, 114, 99, 51, 67, 111, 100, 51, 125]]        ... ์ค‘๊ฐ„ ์ƒ๋žต ...
        if self.current_question_index < len(self.questions):
            self.set_question()
        else:
            result_str = ''
            for _ in flag_arr[0]:
                result_str += chr(_)
            QMessageBox.information(self, "๊ฒŒ์ž„ ์ข…๋ฃŒ", result_str)
            self.close()

flag_arr[0]์€ ๊ฐ€์งœ ํ”Œ๋ž˜๊ทธ์ด๊ณ , flag_arr[1]์€ ์ง„์งœ ํ”Œ๋ž˜๊ทธ์ด๋‹ค. ๋”ฐ๋ผ์„œ, exeํŒŒ์ผ๋กœ ๊ตฌ์„ฑ๋œ pythonํ”„๋กœ๊ทธ๋žจ์˜ ์†Œ์Šค๋ฅผ ๋””์ปดํŒŒ์ผํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค.

 

 

๐Ÿง ๋ฌธ์ œ ํ’€์ด

 

python pyinstxtractor.py Hide_on_Problem.exe

pyinstxtractor.pyํŒŒ์ผ๋กœ pyinstalle๋กœ ๋งŒ๋“  exe ํŒŒ์ผ์„ ๋””์ปดํŒŒ์ผ ํ•ด์ค€๋‹ค.

 

ํด๋”๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค.

 

 

ํด๋” ์•ˆ์—๋Š” ์—ฌ๋Ÿฌ ํŒŒ์ผ๋“ค์ด ์žˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋ณผ ํŒŒ์ผ์€ ๋‘๊ฐœ์ด๋‹ค.

 

 

์†Œ์Šค ํŒŒ์ผ์˜ ๋ฒ„์ „์„ ํ™•์ธํ•˜์—ฌ ํŒŒ์ผ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ์•ž์— ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

 

55 0D 0D 0A 01 00 00 00 00 00 00 00 00 00 00 00

์ด ๊ฐ’์€ base_library.zip ํŒŒ์ผ ์•ˆ์— ์žˆ๋Š” pyc ํŒŒ์ผ๋กœ ํ™•์ธํ•œ๋‹ค.

 

์ด ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๊ฐ’์„ ์•ž์„  ํŒŒ์ผ ๋งจ ์•ž์— ์ถ”๊ฐ€ํ•ด์„œ pyc ํŒŒ์ผ๋กœ ์ €์žฅํ•ด๋ณด์ž.

 

uncompyle6 result_src.pyc

uncompyle6 ๋ชจ๋“ˆ๋กœ ํ•ด๋‹น ์†Œ์Šค๋ฅผ ์ฝ๋Š”๋‹ค.

 

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPixmap

class QuizForm(QMainWindow):
    def __init__(self):
        super().__init__()

        # ๋ฌธ์ œ์™€ ์„ ํƒ์ง€๋“ค ๋ฆฌ์ŠคํŠธ๋กœ ๊ด€๋ฆฌ
        self.questions = [
            {
                'question': "Q1. ์›น ํ•ดํ‚น ๊ธฐ๋ฒ•์ด ์•„๋‹Œ ๊ฒƒ์€?",
                'choices': [
                    "SSTI",
                    "CSP",
                    "SSRF",
                    "CSRF",
                    "SQLi"
                ],
                'correct_choice': "CSP",
            },
            {
                'question': "Q2. 2022๋…„๋„ NIST์— ์„ ์ •๋œ ์–‘์ž ๋‚ด์„ฑ ์•”ํ˜ธ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์€?",
                'choices': [
                    "FALCON",
                    "SPHINCS+",
                    "CRYSTALS-KYBER",
                    "Lizard",
                    "CRYSTALS-DILITHIUM"
                ],
                'correct_choice': "Lizard"
            },
            {
                'question': "Q3. ๋‹ค์Œ ์ค‘ ์Šคํƒ์˜ ์ตœ์ƒ๋‹จ์„ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ ˆ์ง€์Šคํ„ฐ๋Š”?",
                'choices': [
                    "ebp",
                    "edx",
                    "eax",
                    "eip",
                    "esp"
                ],
                'correct_choice': "esp"
            },
            {
                'question': "Q4. ๋‹ค์Œ ์ค‘ ํœ˜๋ฐœ์„ฑ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์€?",
                'choices': [
                    "๋ ˆ์ง€์ŠคํŠธ๋ฆฌ",
                    "์›๊ฒฉ ์‚ฌ์šฉ์ž ์ •๋ณด",
                    "๋„คํŠธ์›Œํฌ ์นด๋“œ ์ •๋ณด",
                    "ARP ํ…Œ์ด๋ธ”",
                    "์ธํ„ฐ๋„ท ์‚ฌ์šฉ ๊ธฐ๋ก"
                ],
                'correct_choice': "๋ ˆ์ง€์ŠคํŠธ๋ฆฌ"
            },
            {
                'question': "Q5. 0x16 + 0b10110 = ?(10์ง„์ˆ˜)",
                'choices': [
                    "39",
                    "40",
                    "42",
                    "44",
                    "45"
                ],
                'correct_choice': "44"
            }
        ]

        self.setWindowTitle("๋ฌธ์ œํ’€์ด ๊ฒŒ์ž„")
        self.setGeometry(500, 300, 400, 150)

        self.main_widget = QWidget(self)
        self.layout = QVBoxLayout(self.main_widget)

        self.label_question = QLabel()
        self.layout.addWidget(self.label_question)

        self.radio_buttons = []
        for _ in range(len(self.questions[0]['choices'])):
            radio_button = QRadioButton()
            self.layout.addWidget(radio_button)
            self.radio_buttons.append(radio_button)

        self.submit_button = QPushButton("์ œ์ถœ", self)
        self.submit_button.clicked.connect(self.check_answer)
        self.layout.addWidget(self.submit_button)

        self.setCentralWidget(self.main_widget)

        self.current_question_index = 0
        self.set_question()

    def set_question(self):
        current_question = self.questions[self.current_question_index]
        self.label_question.setText(current_question['question'])


        for i, choice in enumerate(current_question['choices']):
            self.radio_buttons[i].setText(choice)

    def check_answer(self):
        flag_arr = [[115, 99, 112, 67, 84, 70, 123, 102, 97, 107, 101, 95, 102, 108, 97, 103, 32, 58, 32, 80, 125],
                    [115, 99, 112, 67, 84, 70, 123, 104, 101, 49, 49, 111, 95, 112, 89, 116, 104, 48, 110, 95, 53, 48, 85, 114, 99, 51, 67, 111, 100, 51, 125]]
        selected_choice = None
        for radio_button in self.radio_buttons:
            if radio_button.isChecked():
                selected_choice = radio_button.text()
                break

        if selected_choice is None:
            QMessageBox.warning(self, "๊ฒฝ๊ณ ", "๋‹ต์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.")
        else:
            current_question = self.questions[self.current_question_index]
            if selected_choice == current_question['correct_choice']:
                QMessageBox.information(self, "์ •๋‹ต", "์ •๋‹ต์ž…๋‹ˆ๋‹ค!")
            else:
                QMessageBox.information(self, "์˜ค๋‹ต", "์˜ค๋‹ต์ž…๋‹ˆ๋‹ค.")
                self.close()

        self.current_question_index += 1
        if self.current_question_index < len(self.questions):
            self.set_question()
        else:
            result_str = ''
            for _ in flag_arr[0]:
                result_str += chr(_)
            QMessageBox.information(self, "๊ฒŒ์ž„ ์ข…๋ฃŒ", result_str)
            self.close()

app = QApplication(sys.argv)
window = QuizForm()
window.show()
sys.exit(app.exec_())

๋ฌธ์ œ ์ถœ์ œ ์˜๋„์™€ ๊ฐ™์ด flag_arr ๋ฐฐ์—ด์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

flag_arr = [[115, 99, 112, 67, 84, 70, 123, 102, 97, 107, 101, 95, 102, 108, 97, 103, 32, 58, 32, 80, 125],
            [115, 99, 112, 67, 84, 70, 123, 104, 101, 49, 49, 111, 95, 112, 89, 116, 104, 48, 110, 95, 53, 48, 85, 114, 99, 51, 67, 111, 100, 51, 125]]

 

๐Ÿง ๋ฌธ์ œ ํ•ด๊ฒฐ

flag_arr = [[115, 99, 112, 67, 84, 70, 123, 102, 97, 107, 101, 95, 102, 108, 97, 103, 32, 58, 32, 80, 125],
            [115, 99, 112, 67, 84, 70, 123, 104, 101, 49, 49, 111, 95, 112, 89, 116, 104, 48, 110, 95, 53, 48, 85, 114, 99, 51, 67, 111, 100, 51, 125]]
FLAG = ''
for ascii in flag_arr[1]:
        FLAG += chr(ascii)
print(FLAG)

๊ฐ„๋‹จํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ํ”Œ๋ž˜๊ทธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.