GiCS 決賽 2025 WriteUp

team: 我們是被炸的魚
rk. 2 (高中職組)
規則: 不得用 AI 輔助

今年是我高中最後一年打gics,雖然不像上次一樣第一名,但也覺得雖敗猶榮(?)
我們 CTF 分數遙遙領先,只是可惜闖關(micro:bit)硬體疑似有點問題加上我也不擅長那個,所以闖關分就掛零

然後,CTF 部分題型變得更神奇了 Ex. 機器人、晶片…,題目品質也…
我解出的是兩題 crypto 變crypto人了(?) 第10題靠隊友通靈出 ORZ

image

Level 1 (賽後解出)

關卡類型:Binary
image
image
image
變更副檔名: level1.arj
可直接右鍵解壓縮
得到 lv1-10.bin
image
PE32UPX compressed
脫殼

1
└─$ upx -d lv1-10.bin

image
沒殼了
image
可拖進 IDA
shift + F12 看字串
image
去看 FLAG{%s}
image
追到 sub_4026A0
image
flag 是 Buffer
image
sub_402670 看起來是在把一個字串輸出到一個 buffer

sub_402670(Buffer, 33u, "%s%s", (char)&v8[17]) ida 反編譯錯了,(char)&v8[17] 後面還有一個參數,因為 %s%s 對應兩個指標
(v8 rename 為 tmp)
image
[esp+9C+var_90] 是第一個指標 &tmp[17],[esp+9C+var_8C] 是第二個指標 tmp
所以完整 Buffer 會變成
“95640f2e4b7cc189” + “b4bfc934605ae514”
FLAG{"95640f2e4b7cc189b4bfc934605ae514}

Level 2 (賽後解出)

關卡類型:Web
image

1
└─$ dirsearch -u "http://10.100.215.1/lv2"

image
去看所有 200 中特別大那個
image
往下滑超級長,隨便試幾個 url 點開都是
image
猜測其中一個通往 flag

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests
from bs4 import BeautifulSoup

res = requests.get("http://10.100.215.1/lv2/sitemap.xml")

soup = BeautifulSoup(res.content, 'xml')

urls = [loc.text for loc in soup.find_all('loc')]

for url in urls:
err = requests.get(url).text
if "FLAG" in err:
print(url)

image
找到兩個都是一樣flag
image

Level 3

關卡類型:Cryptography
image
image
要解密 level3.txt
通靈出 strings XOR key = encoded

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
from Crypto.Util.number import *
import base64

# level3.txt
c = "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"
c = base64.b64decode(c)
strings = "GiCS2025 Level#3"
encoded = "krypto9095 woah!"
key = xor(strings,encoded)
# pwntool 的 xor 會將較短的參數循環反覆使用

print(xor(c, key))

image

Level 4 (賽後解出)

關卡類型:Web
image
image
點上面這些 page 會改變
image
推測 LFI
image
image
看 apache log
var/log/apache2/access.log 看到更多 apache 路徑
image
var/log/apache2/error.log 看到 lv4 下的一個路徑
image
image

Level 5 (賽後解出)

關卡類型:Network
image
image
在 Burp 開
image
猜測 images/ 可能有其他圖片
在 Repeater 加 X-Forwarded-For,讓 server 辨識出特定地理位置 IP
image
image

Level 6

關卡類型:Steganography
image
image
是 PCB 檔案,跟電路設計有關
開啟工具 https://www.pcbway.com
image

Level 7

關卡類型:Cryptography
image
image
給了 SSH 公鑰和密文
把 SSH 公鑰存在 7.pub
從 SSH 公鑰提取 RSA 公鑰
發現 e 太小 N 太大,可直接將密文開 e 次方根得到明文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
import base64
from gmpy2 import *

enc = b"IqQZV8+h0x0j2NExugSs1lXpQun70GwKmXCjEp5913f/XpzOoMqEhRqu4cC/C1HptlVx8zeAqDPII4pCZdX/ENGeqeGaFMEn3mjg1gaa/DjmCIw8d+66uIsOH8PBzwccdAlzJ77dPib7bpmGoYZGQ9KaNinhf+hifFQpLMauvJSNvbZsmcBUixAR7FK/n2HvxtV4+z4RoRsrGq78bjUwNYquQgf+G0jsAJN2ehjUvFKuSgYgGbIkpkgw9VE70vG95K4q2g902CeAoqfOV7SSVFC3MnAyLSDPJ4VAu3I/K+SFK2o+3b868V/xxydfexbBkonDw/tY2fIdOBH8ABS37+n2TAYOwRYqUbN9ruRAIQqmX5QleukJkZgg1UroIeI7LDJGG/uKaKgBr+LE7d2kOIbCCKJjsAeTEeL+cHKQL5puyGpYMKosaHhDU0gBvJmMjCY9V1evLEorcDX4CuqzKQnFKzEdRNDp7T5eVyvEoFhyJWcGAU8QHTybO65SCJE4VynBCYbTi6qzfszVgniBWIuo9km5aOKqwrfZIDNDnWkgnfjS/gh4IVFXvq3k//xJ4tEa8OhmQaXo+9k0wUWXfMd9oGSuld5mNFk1bPZOahCu6CCj6IBSlo3/7O2Xw95ZJGlWSmkvjxd+XIuiJqZOyPN2h9aGlTk3ztn3XPjFsXN5+VXXqKPRKv5/EvTDrzOs+IL0wgjwpw3k8oNXGTQ3txuHaJxdG+ZpHerNk2ND6y2gr5sCNFOwImZO0Pijx2mZSM1rytOaR8Al5tdVznitkfHJ+jrIQeX947Lo4TRMbbAkZOrasNauMc1ch4LTqQ243pWkoCGIHazWTeqWlbD1rOxDQGGufv+zqdt0q4WgjNdGyRcjINHiYAIdsnBVnJMDxLDYcrDxFYUpDFxefrBsB7ctzyrlCghwCfWF18DmKoA7fV7SG6BfuaDGJJdcKuzAeWW+QKRnvwQySjxAEu3zOSV6O3aak0VhGeGFx8Qmb6+fcspTitwxfav3QMPG3TC5Ql/hIj5tjMMi9twY8mYXV7KMY0d5ra4UNdZbEigvPoVbkaiygMJuGUP9Asgtn/V4zfef9JXIz4wJT0kbF5mS8gNkvnJbOdNWdf/KcL47IVhmmXdpjMM3bRcK0cFD2bbb3eWAQzU="
enc = base64.b64decode(enc)
enc = bytes_to_long(enc)
pub = open("7.pub",'rb').read()
key = RSA.importKey(pub)

print(key.n)
print(key.e)

'''
m ^ 23 % n = c
'''

print(long_to_bytes(int(gmpy2.iroot(enc, 23)[0])))

image

Level 8 (賽後解出)

關卡類型:Chips
image
這個頁面每請求一次 data 會加 4
image
但 data 要小於 0 才拿的到 flag
透過多 thread 使出現 data 小於 0

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
import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor

THREAD_COUNT = 10

found = 0

def fetch_data():
global found

response = requests.get("http://10.100.215.1/lv8/chips.php")
soup = BeautifulSoup(response.text, 'html.parser')

data_value = int(soup.find_all('td')[1].text)

if data_value < 0:
print(response.text)
found = 1
elif data_value < 100:
print(data_value)

def main():

with ThreadPoolExecutor(max_workers=THREAD_COUNT) as executor:
while True:
executor.submit(fetch_data)

if __name__ == "__main__":
main()

image

Level 9 (未解出)

關卡類型:Network
image
BACKDOOR
掃 port
但 rustscan 只掃出 22 和 80,換 nmap
image
連上 8888 port
image
後得知要查這個服務的 CVE

Level 10

關卡類型:Robot
經測試,只要在第三句開始,含有 f-l-a-g 就會達條件
image

micro:bit (未解出)

給一台裝有 micro:bit 開發板自走車和讓車走的板子

  • 第一題: 開啟無線電竊聽模式,接收無線電訊號
    image
    要接收廣播訊號
    image
    用這個積木調到正確的頻道(5)
    image
    讓接收到的東西顯示在開發版的 LED
  • 第二題: (沒仔細看) 大致是要讓自走車走在板子上的黑線,並用車上的鏡頭偵測板子上的東西