티스토리 뷰

보안/CTF

[SECCON] [misc] findflag Writeup(문제풀이)

돔돔이부하 2022. 11. 19. 23:45
728x90
반응형

Introduction

726팀 중에서 100팀이 푼 문제로 misc 분야에 해당하는 warmup 문제였습니다. 파이썬 CLI 서버였고, 문제의 소스코드는 주어졌습니다.

 

소스코드를 보기 전에 재밌는 실험을 정리해보고 넘아가겠습니다.

Test

try:
	print(1/0)
except:
	print('exception occured.')
	exit(1)
finally:
	print('finally!')

위 코드에서 try 내에 있는 print(1/0) 코드는 0으로 나누었기 때문에 Exception 이 발생할 겁니다. 그러면 except 내에 있는 코드를 보면 exception occured. 라는 문자열을 출력할 것이고, exit(1) 함수에 의해서 종료를 하는 것이 맞습니다.

 

근데 과연 종료가 되었을까요?

>python test.py
exception occured.
finally!

실행 결과는 위와 같습니다. finally 에 선언되어 있는 print('finally!') 가 실행된 것으로 보입니다.

 

그러면 아래 코드는 어떨까요?

import os

try:
	print(1/0)
except:
	print('exception occured.')
	# exit(1)
	os._exit(1)
finally:
	print('finally!')

이번에는 os 모듈에 있는 _exit 함수를 이용해보았습니다. 실행 결과를 보면 아래와 같습니다.

>python test.py
exception occured.

어떤가요? finally 가 출력되지 않았습니다. 이상한가요? 사실 이건 버그라기 보다 exit 함수가 그렇게 설계되어 있기 때문입니다.

https://docs.python.org/3/library/sys.html#sys.exit

 

sys — System-specific parameters and functions — Python 3.11.0 documentation

sys — System-specific parameters and functions This module provides access to some variables used or maintained by the interpreter and to functions that interact strongly with the interpreter. It is always available. sys.abiflags On POSIX systems where P

docs.python.org

해당 문서를 참고해보시죠. 문서에는 아래와 같이 설명하고 있습니다.

Raise a SystemExit exception, signaling an intention to exit the interpreter.
...어쩌구저쩌구...생략....
Since exit() ultimately “only” raises an exception, it will only exit the process when called from the main thread, and the exception is not intercepted. Cleanup actions specified by finally clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.

 

단순한 exit 함수 즉, sys.exit 함수와 os._exit 함수간의 차이점은 위와 같은 것을 이번 문제를 풀면서 알 수 있었던 것 같습니다. 이제 다시 문제로 돌아가서 문제의 소스코드를 살펴보겠습니다.

 

Code Analysis & Exploit

#!/usr/bin/env python3.9
import os

os.getenv("FLAG", "FAKECON{*** REDUCTED ***}").encode()


def check():
    try:
        filename = input("filename: ")
        if open(filename, "rb").read(len(FLAG)) == FLAG:
            return True
    except FileNotFoundError:
        print("[-] missing")
    except IsADirectoryError:
        print("[-] seems wrong")
    except PermissionError:
        print("[-] not mine")
    except OSError:
        print("[-] hurting my eyes")
    except KeyboardInterrupt:
        print("[-] gone")
    return False


if __name__ == '__main__':
    try:
        check = check()
    except:
        print("[-] something went wrong")
        exit(1)
    finally:
        if check:
            print("[+] congrats!")
            print(FLAG.decode())

문제에서도 위에 테스트한 것과 동일하게 try ~ except ~ finally 문을 쓰고 있습니다. 그리고 check 함수에서 선언된 Exception 외 적으로 발생한 예외의 경우에는 except 절에 작성되어 있는 exit(1) 함수로 떨어지게 되어 있습니다.

 

예외적인 Exception에는 어떤 것이 있을까요? 바로 EOFError라는 게 있습니다.

입력값을 받고 있는데 갑자기 input으로 Ctrl + Z가 들어오면 어떻게 될까요? (참고로 Windows 에서는 Ctrl + Z 이고 unix 계열에서는 Ctrl + D 입니다)

 

우선 input 함수가 정의된 문서를 살펴볼 필요가 있습니다.

https://docs.python.org/3.9/library/functions.html#input

 

Built-in Functions — Python 3.9.14 documentation

Built-in Functions The Python interpreter has a number of functions and types built into it that are always available. They are listed here in alphabetical order. abs(x) Return the absolute value of a number. The argument may be an integer, a floating poin

docs.python.org

문서를 읽어보면 중요한 것은 바로 여기 한문장입니다.

When EOF is read, EOFError is raised

EOFError 라는 Exception 은 문제에서 주어진 소스코드에는 예외처리 되어 있지 않기 때문에 except 절로 넘어올 수 있게 해줍니다.

 

그리고 exit(1) 함수에서 프로그램이 완전히 종료되기 전에 남은 action 인 finally 절에 있는 코드가 실행되면서 Flag 가 출력됩니다.

 

정말 유익한 문제였던 것 같습니다.

 

- 끝 -

728x90
반응형
댓글