echoCTF Argum E Nvative (ID#10) writeup (zh-TW)

類別:Reverse Engineering / easy / 1,500pts
檔案:Argum_E_Nvative.zip
(內含 statically-linked ELF x86_64 binary)
題目連結: https://echoctf.red/challenge/10
一、目標
分析 binary,回答題目要求的 4 個問題:
- Q1: 程式應如何執行?
- Q2: 預期的 env flag(ETSCTF)為何?
- Q3: 預期的 begging argument 為何?
- Q4: 在滿足前置條件後,binary 印出的正確 source answer為何?
二、靜態檢視
- 先直接執行看看並觀察
└─$ ./Argum_E_Nvative.bin
Checking argv0... incorrect
Checking argc... 1 incorrect
Checking path[] exists... exists, Checking st_size==4096... correct
Checking ets_env... null
Checking home_env... incorrect
Checking argv[2]... incorrect
The ETSCTF source answer is... (drum roll please)
&wX%!*'hmrkOOPiy'')
file
顯示:ELF 64-bit LSB executable、static、not stripped(可反編譯)。- 使用 Ghidra 對
main
反編譯後可直接讀出程式的檢查流程
三、深入ghidra反編譯後的main
- 先讀取兩個環境變數:
local_118 = getenv("HOME")
、local_110 = getenv("ETSCTF")
。 - 檢查
argv[0]
:strcmp((char *)*argv, "./fdd35ef750404db0be89f31f116c2d23")
。- 若相等 → 標示
argv0
correct,並把argv0[3]
、argv0[2]
放入輸出陣列(ETSCTF result buffer)。 - 否則放兩個隨機字元(rand)。
- 若相等 → 標示
- 檢查
argc
:如果argc == 3
才進一步檢查argv[1]
,否則argc
判定為 incorrect 並填 rand。 - 檢查
argv[1]
:strcmp(argv[1], "-e")
。若相等,放argv1[0]
(也就是'-'
)到輸出陣列,否則放 rand。 - 檢查路徑
"/."
(stat(local_78,&st)
)——如果存在則呼叫setFlagFileProperties()
- 若相等 →
ets_env correct
,程式從該 env 字串取出 6 個指定位置的字元(index:10, 0x16(=22), 6, 0x11(=17), 0x12(=18), 9)依序 append 到輸出陣列。 - 否則 append 6 個 rand。
- 若相等 →
- 檢查
HOME
與是否以 root 執行(geteuid()
):- 若
HOME
非空且geteuid()==0
→home_env correct
,appendHOME[0]
與HOME[2]
。 - 否則 append
HOME[1]
與HOME[3]
(程式仍會取 HOME 中的字元來組字串)。
- 若
- 檢查
argv[2]
:strcmp(argv[2], "PleaseGiveMeTheFlag")
。- 若相等 → append 一系列
argv2
上特定索引的字元(次序:+0x12, +0x0f, +3, +10, +5, +9, +1, +8, +0, +0x12),共 10 個字元。 - 否則 append 10 個 rand。
- 若相等 → append 一系列
- 最後印出
"The ETSCTF source answer is... (drum roll please) "
與組好的ETSCTF
字串(即題目要的 source answer)。
檢查 ETSCTF
環境變數是否存在,並與整段長字串比對:
"Would it save you a lot of time if I just gave up and went mad now? ETSCTF_02ea5de333a4f296b8aa8bf0925a90ae"
因此要得到 deterministic(非隨機)的 source answer,必須讓所有那些判斷都走到「correct」分支(即:argv0
、argc
、argv1
、ETSCTF
env、HOME
(與 euid==0)及argv2
都滿足預期值)。
四、Q1–Q4 的說明
Q1(簡短說明)
程式在 main
裡直接用
strcmp(argv[0], "./fdd35ef750404db0be89f31f116c2d23"
)
檢查執行時的程式名稱(argv[0]
),所以 正確的執行方式就是以 ./fdd35ef750404db0be89f31f116c2d23
這個名稱去呼叫它。
Q2 — What is the expected env flag? (350 pts)
答案:
Would it save you a lot of time if I just gave up and went mad now? ETSCTF_Redacted
說明:程式用 getenv("ETSCTF")
取得該 env,並和上面整段字串用 strcmp
比較;只有完全吻合才走 correct
分支並抽出其中的指定字元。
Q3 — What is the expected begging argument? (350 pts)
答案(精確字串):
PleaseGiveMeTheFlag
說明:程式用 strcmp(argv[2], "PleaseGiveMeTheFlag")
進行判斷,若相等則從 argv[2]
的多個指定索引處抽出字元組成輸出的一部分。
Q4 — What is the correct source answer? (500 pts)
答案:
完整執行這個即可~
sudo env HOME=/root ETSCTF='Would it save you a lot of time if I just gave up and went mad now? ETSCTF_02ea5de333a4f296b8aa8bf0925a90ae' bash -c "exec -a './fdd35ef750404db0be89f31f116c2d23' ./Argum_E_Nvative.bin -e PleaseGiveMeTheFlag"
說明:
- 當所有檢查都走到
correct
(argv0、argc、argv1、ETSCTF env、home_env 與 argv2 都符合程式內部期望)時,程式依序從這些來源抽取特定位元並 append 成最終字串,印出該字串即為 Q4 要求的 source answer。
└─$ sudo env HOME=/root ETSCTF='Would it save you a lot of time if I just gave up and went mad now? ETSCTF_02ea5de333a4f296b8aa8bf0925a90ae' bash -c "exec -a './fdd35ef750404db0be89f31f116c2d23' ./Argum_E_Nvative.bin -e PleaseGiveMeTheFlag"
Checking argv0... correct
Checking argc... 3 correct
Checking argv[1]... correct
Checking path[] exists... exists, Checking st_size==4096... correct
Checking ets_env... not null, correct
Checking home_env... correct
Checking argv[2]... correct
The ETSCTF source answer is... (drum roll please)
df-%!*'ati as/ogFaMeelvPg
經驗分享
關於三:
這邊是利用ghidra,去抓出整個"main"的反編譯邏輯喔!方法其實可以透過在ghidra先搜尋所有strings,後來去特定找一些關鍵字,好比我是找argv,就找到main了。
