在 CTF 中,程式碼分析是常見的題型之一,要求解題者從已編譯好的程式或不完整的提示中推理出原始程式的運作邏輯,進而找到 flag。相比一般程式設計題,逆向工程更加強調對底層結構、編譯過程及程式執行流程的深入理解。不僅需要分析表面的程式行為,還要善於利用工具和邏輯推理來揭開程式的內在運作機制。
通常分為靜態分析與動態分析兩種手法:
靜態分析: 指在不執行程式的情況下,直接閱讀或反編譯二進位碼來瞭解程式的結構與邏輯。這過程中需要善用反編譯工具來還原程式碼,並理清其中的核心邏輯與控制流程。
動態分析: 則是在執行程式的過程中,追蹤其行為以找出程式的運行路徑和變數變化情況。掌握程式在不同情況下如何回應輸入、生成輸出,並釐清哪些條件或流程會觸發關鍵的 flag。
今天我們來解一些需要 code review 的題目,大致需要以下步驟:
理解程式架構: 瞭解程式的主要功能與核心邏輯,確定哪些部分是可能藏有 flag 的關鍵區域。這一步通常使用反編譯或靜態分析工具。
分析運行邏輯: 深入追蹤程式的執行流程,判斷哪些條件或輸入會導致 flag 的輸出。在這過程中,可以結合除錯工具,分析變數變化和程式分支。
繞過保護機制: 有些程式可能設計了防範使用者直接獲取 flag 的保護機制,這時需要利用程式中的漏洞或邏輯瑕疵來獲取 flag。
那今天我們要分析的程式碼都是由 Python 撰寫的,事不宜遲直接開始吧!
Lab_1 - Picker I
首先題目給你一個能夠 nc
的網址,還有一個 .py
source code。來瞧瞧裡面都是什麼
可以看到第 5 行有一個 eval()
,我們能夠藉由這個函數來讓他執行一些我們想讓他做的事,像是印出 flag
eval() 是 Python 中的一個內建函數,它的主要功能是將傳遞給它的字串表達式作為 Python 表達式進行解析並執行。簡單來說,它可以動態地執行由字串形式表示的 Python 代碼。
eval() 有很大的安全風險,尤其是在處理來自外部或用戶的輸入時。因為 eval() 可以執行任何有效的 Python 程式碼,可能會導致任意代碼執行的風險。
while(True):
try:
print('Try entering "getRandomNumber" without the double quotes...')
user_input = input('==> ')
eval(user_input + '()')
except Exception as e:
print(e)
break
eval(user_input + '()')
能夠將使用者的輸入執行,也就是說如果輸入程式中的其他 function,那不就能執行他了嗎?剛好在題目給的 source code 中,有一個 win() 的函數,第 4 行做了讀檔的動作,能夠印出 flag.txt 給我們
def win():
# This line will not work locally unless you create your own 'flag.txt' in
# the same directory as this script
flag = open('flag.txt', 'r').read()
#flag = flag[:-1]
flag = flag.strip()
str_flag = ''
for c in flag:
str_flag += str(hex(ord(c))) + ' '
print(str_flag)
於是我們輸入 win
,吐出了一段 16 進制的字給我們,放進之前介紹過的 解碼工具,flag 成功 get
Lab_2 - Picker II
一樣是透過 eval(user_input + '()')
來觸發 flag,不過這次多了 filter(user_input)
這個驗證機制。
def win():
# This line will not work locally unless you create your own 'flag.txt' in
# the same directory as this script
flag = open('flag.txt', 'r').read()
#flag = flag[:-1]
flag = flag.strip()
str_flag = ''
for c in flag:
str_flag += str(hex(ord(c))) + ' '
print(str_flag)
while(True):
try:
user_input = input('==> ')
if( filter(user_input) ):
eval(user_input + '()')
else:
print('Illegal input')
except Exception as e:
print(e)
break
如果輸入等於 win
,eval()
不會被成功執行。
def filter(user_input):
if 'win' in user_input:
return False
return True
於是換另外一種方式,直接輸入讓其直接去讀 flag.txt
今天的練習就到這邊,以下是參考資料,請搭配服用:
eval wiki
eval() 函數使用
淺談 reverse engineering
內文如有錯誤,還請不吝指教~