iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 7
1
Security

CTF 的三十道陰影系列 第 7

Day7: [Crypto] Encode? Encrypt? Hash?

前言

前陣子看到靠北工程師版在討論某個資外洩的服務,提到了大家經常搞錯的三件事情:encode、encrypt、hash,今天就簡單聊聊這三個的差別,BTW,這也是我之前在面試來投 security 時經常問的問題,如果答不出來的面試者... 基本上就抱歉了 XD"

Encode

中文翻譯為 編碼,其實跟 security 沒什麼關係,主要是因為需要傳輸資料而衍伸的一種技術,像是將文字編碼 (big5, utf-8)、音訊編碼 (mp3)、影像編碼 (mp4, 3gp)

如果我們把 encode 以數學函數的方式表達 raw = f(data),一定存在另一個反函數 data = f'(raw) 可以將資料 decode 回原本的內容

  • raw 和 data 會是 1-to-1 的關係
  • 我們常用的 base64 就是編碼的一種,base64 最大的好處就是可以把任何字元轉換成由 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 所組成的字串,這樣我們就可以用 printable 的資料流來處理 non-printable 的資料
    • printable char 表示 ascii 碼在 0x20~0x7f 之間,這範圍之外的稱為 non-printable
  • 壓縮 (Compress) 廣義來說也算編碼的一種,但有些壓縮演算法是屬於破壞性壓縮無法還原,因此不完全等於編碼

Encrypt

中文翻譯為 加密,是真正因為需要保護資料不讓別人知道而發展的一種技術,如果有修過密碼學的課程,一般都會從 凱薩密碼 開始講 到 二次世界大戰 XD

以數學函式表達加密會是 c = f(p, k),同樣也會存在反函數 p = f'(c, k),知道 key 和哪一種加密函式,就能把 cipher 轉回原本的 plaintext,也就是俗稱的 解密 (decrypt)

  • c = cipher (密文), p = plaintext (明文), k = key (金鑰)
  • 選用相同的加密演算法和 key 時,cipher 和 plaintext 會是 1-to-1 的關係
  • 如果加密和解密用的 key 是同一把,就是 對稱式加密;反之如果加密和解密用不同把 key,會是非對稱式加密

Hash

中文翻譯為 雜湊,跟前面兩者最大的不同是,hash 沒有辦法還原回原本的 data,因此不存在反函數可以直接將 hash 算回原本的 data

  • hash 在數學上來說會把比較大的資料範圍對應到一個比較小的資料範圍,是 n-to-1 的對應關係,如果有兩個不同的 data 對應到同一個 hash,我們就稱呼為發生 collision
  • 常見的 hash 演算法像是:md5, sha256, sha512 等

希望以上的說明可以幫大家快速了解三者的區別,如果之後聽到有人說 base64 加密md5 加密 這種說法,請不要客氣的糾正過來 XD

最後提一下 rot13 ,有些人會說他是加密的一種,不能說完全錯誤,rot13 從原理上來說是凱薩加密,但 key 固定取 13 得到的結果,但由於 key 固定就表示不是可變動的參數,因此從數學的角度來看, rot13 就很明顯屬於編碼,而不是加密了

0x06: BCTF 2014 PPC & CRYPTO 100 混沌密碼鎖

先提一下 PPC 這個題目分類,全名是 Professionally Program Coder,主要會考大家 coding 的能力,題目會類似 ACM 的形式,在早些年的 CTF 中經常出現這個分類,但近年來已經很少看到,可喜可賀 XD 話說回來這題其實也沒有太多 PPC 的成分就是了

這題是用 python 寫的 server,連上 server 後會先得到一個 answer_hash,然後問兩個問題,如果兩題都答對 server 就會印出 flag

第一個問題要回答 server 是透過哪些 function 將 answer 計算成 answer_hash,需要輸入四個數字,server 會根據四個數字取四個 function 去計算 answer_hash,部分 source 如下

f['fun1']=reverse
f['fun2']=base64.b64decode
f['fun3']=zlib.decompress
f['fun4']=dec2hex
f['fun5']=binascii.unhexlify
f['fun6']=gb2312
f['fun7']=bin2dec
f['fun8']=hex2bin
f['fun9']=hex2dec

answer = 78864179732635837913920409948348078659913609452869425042153399132863903834522365250250429645163517228356622776978637910679538418927909881502654275707069810737850807610916192563069593664094605159740448670132065615956224727012954218390602806577537456281222826375
answer_hash = f['fun6'](f['fun2'](f[f1](f[f2](f[f3](f[f4](answer))))))
  • 由於 fun6 和 fun2 已經被使用過就先排除,answer 是純數字因此可推測最早被呼叫的 function 會是 dec2hex,剩下的組合全部試一遍看哪個正確,可以得到正確答案是 3, 5, 1, 4
  • answer_hash = base64(gb2312(zlib.decompress(binascii.unhexlify(reverse(dec2hex(answer))))))

第二個問題是要輸入一組 passcode,passcode 不能與 answer 相同,但 passcode 經過與問題一相同的 function 處理後要得到和 answer_hash 一樣的結果

  • base64(gb2312(zlib.decompress(binascii.unhexlify(reverse(dec2hex(passcode)))))) == answer_hash && passcode != answer

  • 由於所使用到的的 function 都是 encode,input 和 output 是 1-to-1 對應,沒有製造 collision 的可能性,只有 zlib.decompress 是 壓縮 所以有機會做手腳

  • zlib.decompress 的演算法有容錯空間,會自動捨去無法被解壓縮的資料,所以我們可以隨便在 zlib.decompress 要處理的資料後面隨便塞個資料,就可以得到與 answer 不同的 passcode

    tmp = binascii.hexlify(((ff2))) + '01'
    assert f['fun6'](f'fun2' == answer_hash, 'failed'
    passcode = hex2dec(reverse(tmp))

最後得到結果:

Your passcode: 2046914671302815174999479572879926709311623516344310480161044657024943192185778242098416328741805906729519967582134066703522565680955045139113850683617281109011304982006585757796402695817434740126949224951202731646556997125542758488503105749434074546856689060231
Welcome back! The door always open for you, your majesty! 
BCTF{py7h0n-l1b-func7i0ns-re4lly-str4nge}


上一篇
Day6: [Web] Path Traversal
下一篇
Day8: [Forensic] Steganography
系列文
CTF 的三十道陰影31

尚未有邦友留言

立即登入留言