Try   HackMD

HKCERT CTF 2022: Writeup on ★☆☆☆☆ (I)

美麗都大廈 / spyce (Web)

  1. 打開網站
  2. 隨便點一個頁面,例如 "Hello, world"
  3. 該頁面顯示 "Hello from Spyce version 2.1!",下面有個連結顯示 "Source for this page",按它。
  4. 網址的 query string 部份顯示 path=%2Fhome%2Fspwnce%2Fwww%2Fdocs%2Fexamples%2Fhello.spy
  5. 將此 query string 部份改成 path=/flag1,然後瀏覽此網址
  6. 拿到旗幟了!

海山樓 / Flawed ElGamal (Crypto)

題目大意

當玩家連線到伺服器時,他們都會收到一個被加密的旗幟

(c1,c2)。以下是用作加密的公鑰:

p = 1444779821068309665607966047026245709114363505560724292470220924533941341173119282750461450104319554545087521581252757303050671443847680075401505584975539
g = 2
h = 679175474187312157096793918495021788380347146757928688295980599009809870413272456661249570962293053504169610388075260415234004679602069004959459298631976

根據原始碼,密文是由一個有缺陷的 ElGamal 算法加密而成的。它會根據以下步驟算出密文

(c1,c2)

  1. 產生一個隨機的
    y[1,p1]
  2. 計算
    s:=hy mod p
  3. 計算
    c1:=gy mod p
  4. 計算
    c2:=ms

我們的目標是解密密文,並取得旗幟

m

題解

在我們的 ElGamal 算法裡面,

c2:=ms 並沒有取模數。因此
c2
將會是
m
的倍數。如果我們多次連線到伺服器的話,我們將可得到數個密文
(c1,c2)
(c1,c2)
等等。由於
c2,c2,...
m
的倍數,所以

m=gcd(c2,c2,...).

我們可以用歐幾里德算法來計算兩個數字的最大公倍數,其 Python 程式碼如下:

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

我們亦可使用下列關係來算出

a,b,...,c 之最大公倍數:

gcd(a,b,...,c)=gcd(...gcd(gcd(a,b),...),c).

得出

m 後,我們要把它變成一個字串。由 chall.py 得知,旗幟是以 m = int.from_bytes(flag, 'big') 這一行來轉換成一個數字的。你可以研究一下怎麼使用 Python 的 int.to_bytes 來把數字變回來。

🏁 我把

m 變成一個字串了,可是旗幟呢? 那代表你所得到的 m 不正確。這很大機會是因為你所得到的數字還不等於
m
,而是
m
的一個(很小的)倍數。你可以獲取更多的
c2
來計算最大公倍數,從而算出一個正確的
m

沙田大會堂 / echo (Pwn)

  1. 理解源碼
    • 程式會讀取使用者的輸入然後打印出來。
    • 不斷重複直至使用者輸入""而且全局變數can_leave不是0。 (但看完源碼以後總覺得can_leave一定是0?)
  2. 尋找漏洞
    • scanf("%s", buf)不會去限制使用者輸入的字數,令程式弱於Buffer overflow attack
    • printf(buf)看上去很奇怪,因為通常在c語言中打印字串會是printf("%s", buf)
    • 如果使用者能夠控制printf函數的第一個參數的內容,使用者可以用Format string attack攻擊程式。
    • Format string attack可以達到任意內存讀取任意內存寫入的效果.
  3. 檢查程式的保護
    • 在gef裡面運行Checksec以檢查程式開啟的保護。
    • 由於PIE(Position Independent Executable)開啟了,get_shell函數的內存地址是隨機的。
    • 由於Canary開啟了,除非能知道canary的值,否則Buffer overflow attack是行不通的。
  4. 攻擊
    • 利用Format string attack去洩露一個PIE地址(指一個受PIE影響到地址),然後計算出get_shell函數的內存地址。 (洩露出來的地址跟get_shell函數地址之間的差是固定的)
    • 利用Format string attack去洩露canary的值。
    • 利用Format string attack去覆蓋can_leave的值,因此程式可以離開while循環以及main函數 (以觸發Buffer overflow attack)。
    • 利用Buffer overflow attack去覆蓋main函數‘返回地址’的值到get_shell函數的地址。
  5. 漏洞利用
    • 寫個python腳本解題。安裝pwntools能給你很多解pwn題時有用的函數。 (pwntools相關的用法可以參考這年/去年底hkcert ctf賽前工作坊)
    • 理解第4步描述的攻擊,寫出有效的攻擊載荷(payloads)
    • 目標是調用get_shell函數去獲取shell和cat旗幟。
    • 這是給你起手用的解題腳本的骨架:
from pwn import *

host = ??
port_number = ??
io = remote('<host>', port_nubmer)
elf = ELF('./chall')

# leak canary
payload0 = ??
io.sendlineafter(b'\nInput:\n', payload0)

# now the canary is leak on screen, script to get the canary value
canary = ??

# leak address
payload1 = ??
io.sendlineafter(b'\nInput:\n', payload1)

# now the address is leak on screen, script to get the leaked address
leaked_address = ??
pie_base = leaked_address - fixed_offset
canLeave = pie_base + elf.symbols['can_leave']
getShell = pie_base + elf.symbols['get_shell']

# overwrite canLeave to non-Zero
payload2 = ??
io.sendlineafter(b'\nInput:\n', payload2)

# Calling system (in get_shell function) requires stack be aligned.
# Add ret_gadget (to add rsp by 8) before calling get_shell to align the stack.
ret_gadget = getShell + 25
len_of_input_before_canary = ??
payload3 = b'a' * len_of_input_before_canary + p64(canary) + p64(0), + p64(ret_gadget), p64(getShell)
io.sendlineafter(b':\n', payload3)
io.sendlineafter(b':\n', b'--')

io.interactive()

米埔自然護理區 / Fiddler Crab (Reverse)

可以用好多方法黎做呢條題目, 但係最簡單就應該係睇隻game既 network traffic黎感覺下佢入面到底係做緊咩.

我地可以setup 一個proxy 黎偷睇中間既所有traffic, 甚至可以用黎改入面既內容.

件事係, 你setup 一個係game server 問埋中間既proxy server, game client 就連去個proxy, proxy就連過去game server. 咁個proxy就可以睇曬兩邊傳送出黎既data, 又或者send 俾對面之前改左個內容佢.

你可以用求其一個proxy/mitm工具黎做, 如果係HTTP request 既話, 你可以用mitmproxy, 但係依家用TCP proxy會好d (因為mitmproxy 會好難setup non TLS traffic)

其中一個TCP proxy 會係 tcpproxy.

setup 類似係咁:

python tcpproxy.py -ti <ip> -tp <port> -lp 8000 -im textdump -om textdump

咁你就可以直接用chess client 黎connect去個proxy:

./chess_client 127.0.0.1:8000

係proxy 果邊就會睇到啲traffic data, 你會睇到個client send 啲咩俾server, server 又回應啲咩俾個client.

你都可以用tcpproxy黎改啲traffic data, 好似咁

python tcpproxy.py -ti <ip> -tp <port> -lp 8000 -im replace:search=<SEARCH>:replace=<REPLACE> -om textdump

想知點config 就上github睇下佢地啲source code

你試下改唔同既野就可能會發現唔係下下改咩都會得. 要點改先會唔炒? (可能關於頭果幾古怪bytes?)

依家你應該可以用改野黎出到千. 祝你好運!

珍寶海鮮舫 / SD Card (Forensics)

題解

下載 sdcard.zip, 解壓縮並找到 sdcard.dd. 把它放入數位鑑識工具當中。

在以下的 writeup 中,我將使用 Autopsy 作爲示範。你應找到在 $CarvedFiles 之中找到 f0000000.png

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Autopsy 亦提供副檔名的搜尋功能。使用此方法則會找到 _lag.png

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

f0000000.png_lag.png 爲同一照片。我匯出 f0000000.png 並繼續進行調查。

若你不打算使用 Autopsy 並使用其他工具,照片名稱可能會有差異。

我們直接打開照片但沒有看到什麼。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

同時可交換圖檔格式中的資料亦與檔案大小不符。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

我們可以在以下方向繼續調查:

  • 隱寫術
  • 修復損壞照片

由於檔案副檔名爲 PNG, 我們決定以修復損壞照片作爲調查方向。 你可以在下方閱讀更多有關 PNG 數據塊結構的資料:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

PNG © corkami, CC BY-NC-SA 2.0

我們決定將 f0000000.png 放入 PNG file chunk inspector。發現有多個 IHDR 數據塊結構。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

可是一個正常的 PNG 檔案只有一個 IHDR 數據塊。我們可以使用任意的十六進位編輯器修正照片 f0000000.png

我使用 HexEd.it 修正照片。你亦可使用 HxD 修正。

在 PNG file chunk inspector 中我們得知我們可以移除以下其中之一的 IHDR 數據塊:

  • 位元 8 - 32 (0x00000008 - 0x00000020)
  • 位元 33 - 57 (0x00000021 - 0x00000039)

第一個 IHDR 數據塊 (位元 8 - 32) 顯示照片只有 1 像素。這個數據塊令人生疑,所以我們先嘗試把它去除。一個 IHDR 數據塊應爲 25 位元。

當你祓除第一個 IHDR 數據塊後,儲存照片並嘗試把它打開。你現在應該可以正常地瀏覽 PNG 照片。

以下只是旗幟的一部分。現在嘗試自行解一次題吧!