題目來源:picoCTF — vault-door-1(Java 版)
目標:分析 VaultDoor1.java 原始碼,找出判定密碼的邏輯,還原出完整 flag,並整理成可重複的解題步驟與思路。
馬後炮:原始碼內並未直接放完整 flag,而是透過一系列 password.charAt(index) == 'x' 的驗證條件判斷是否正確。只要把每個條件合併,就能還原出目標字串(flag 的中間部分)。
解題步驟與思路
一、下載題目檔案並閱讀程式碼:
wget https://jupiter.challenges.picoctf.org/static/87e103a8db01087de9ccf5a7a022ddf8/VaultDoor1.java
head -n 200 VaultDoor1.java
重要程式片段(摘錄):
String userInput = scanner.next();
String input = userInput.substring("picoCTF{".length(),userInput.length()-1);
if (vaultDoor.checkPassword(input)) {
System.out.println("Access granted.");
}
原始碼 main() 會要求使用者輸入完整 flag 字串(含 picoCTF{ 與 }),然後把中間內容擷取出來傳給 checkPassword() 檢查。
password.length() == 32(中間內容長度為 32),並列出了 32 個位置中若干的 charAt(index) == 'x' 比對條件(並非按照順序逐一出現)。
二、還原 flag:
理解輸入格式:
注意程式在 main() 先把 picoCTF{ 的前綴及最後 } 去掉,然後對中間 password 做 checkPassword。因此你要還原的是中間的 32 字元字串,最後再套回 picoCTF{...}。
蒐集所有比對條件:
把 checkPassword 中的每個 password.charAt(i) == 'x' 條件列出來,記錄 index 與對應字元。
建立一個長度為 32 的字元陣列:
先用"?"或空字元填滿 32 個位置(索引 0–31),再把蒐集到的比對條件依 index 放入對應位置。
檢查是否有遺漏或衝突:
確認每個 index 都被賦值(或有合理缺省值)。若有衝突(同一 index 被兩個不同字元要求),需回頭確認程式碼是否存在其他運算或 offset。
串接結果與驗證:
把陣列連成字串作為中間內容,套回 picoCTF{...} 就是完整 flag。
實作:
python3 - <<'PY'
s = list('?'*32)
checks = {0:'d',1:'3',2:'5',3:'c',4:'r',5:'4',6:'m',7:'b',8:'l',9:'3',10:'_',11:'t',12:'H',13:'3',14:'_',15:'c',16:'H',17:'4',18:'r',19:'4',20:'c',21:'T',22:'3',23:'r',24:'5',25:'_',26:'f',27:'6',28:'d',29:'a',30:'f',31:'4'}
for i,ch in checks.items(): s[i]=ch
print("picoCTF{"+''.join(s)+"}")
PY
即可獲得Flag:picoCTF{d35cr4mbl3_tH3_cH4r4cT3r5_f6daf4}!!
小小心得
讀懂程式碼比盲目嘗試更有效率,把條件式逐一列出並填回字元陣列,這類題通常可以一步到位還原。
小心細節(長度檢查、substring 的開始/結尾是否被包含),原程式會把 "picoCTF{" 與 "}" 去掉再比對,所以不要把它們也算進 charAt 的位置。
變數順序不一定是 0→31:題目作者常為了混淆會把 charAt 條件寫成無序的,務必依 index 放回正確位置。
會有位移或運算:有些題目索引會是 charAt(i+1) 或字元會被運算(XOR、加減),遇到這種情況需追蹤程式中是否有其他運算步驟。
這題有練習到逆向閱讀與邏輯重建能力,超讚ㄉ啦!