###### tags: `NCTU` `CS` `Course` `SecureProgramming` HW 0x09 Write Up == yysung ## [Lab 9-1] Crypto Lab 1 題目有兩個 command register 可以輸入 Username 並用 urllib encode `{'usr': Username 'admin': 'N'}`,再用 AES-ECB 加密後作為 token 回傳 login 可以輸入 token 解密後檢查 admin 欄位是否為 'Y'來回傳 flag 可以用程式建構兩個 token ``` usr=aaaaa&admin=|N...............|................| usr=aaaaaaaaaaaa|YOOOOOOOOOOOOOOO|&admin=N........| ``` 因為是用 ECB 做區塊加密,所以直接替換加密過的區塊也可以成功被解密,所以可以用以上資訊再自行建構 token ``` A = token1[0] B = token2[1] token = A + B * 5 ``` 因爲 unpad 的行為是看最後一個 bytes 的值往前刪去值, 所以放入 O 就可以剛好往前刪去 79 個 bytes,所以建構 5 個區塊,就可以刪到只剩下 Y 了 回傳 token 後,就可以拿到 flag 了 ## [Lab 9-2] Crypto Lab 2 題目會一直讀入兩個 plaintext 並以相同的 key 和 iv 來以 AES-CBC 加密 plaintext 再用 AEC-ECB 來對最後一個 ciphertext 的 block 加密當作 MAC 輸入的 plaintext 必須不同,如果 MAC 不同就回傳兩者的 MAC,如果 MAC 相同就回傳 flag ``` enc 為 AES-CBC-MAC E 為 AES encrypt A = 'a' * 30 B = 'b' * 30 X = enc(A) Y = enc(B) A' = A with padding B' = B with padding O = '0' * 32 證明 E(A'OX) == E(B'OY) enc(A') = E(E(A' ^ IV)) = X E(A'OX) = E(E(A'O) ^ X) = E(E(E(A' ^ IV) ^ O) ^ X) = E(E(E(A' ^ IV)) ^ X) = E(X ^ X) = E(O) E(B'OY) 如上,最後也會等於 E(O) ``` 以上面方法建構 plaintext 後就可以拿到 plaintext 不同但 MAC 相同的兩個 plaintext,回傳後就可以拿到 flag 了 ## [Lab 9-3] Crypto Lab 3 題目有兩個 command register 可以輸入 Username,並用 md5('Crypto is fun' + usr + key) 算出 MAC,接下來用 AEC-CTR 對 usr + mac 作加密並和 iv 一起回傳,在程式裡註冊 Username login 會將 usr 和 mac 解密出來,並用解密的 usr 再用相同的做法算出 mac2,檢查 mac != mac2 和 usr 是否之前沒有在程式註冊過,都符合就可以拿到 flag 首先先找出前綴為 'Crypto is fun' 並且 md5 相同的兩組 值 可以使用 fastcoll 在兩秒左右的時間找到 因爲前面區塊的 md5 已經相同,所以在後面放入相同的字串 md5 也會相同。可以在後面放 0 做 padding 到 16 bytes 的倍數 將以上的字串作為 Username 傳給程式得到 iv 和加密過的 usr + mac 因為 AES-CTR 的加密方法是 ``` aes(iv + counter) ^ plaintext = ciphertext ``` 所以在有 plaintext 的情況下可以生成任意 plaintext 的 ciphertext ``` ciphertext ^ plaintext ^ new_plaintext = aes_encrypt(iv + counter) ^ plaintext ^ plaintext ^ new_plaintext = = aes_encrypt(iv + counter) ^ new_plaintext = new_ciphertext ``` 就可以把 usr 換成另一組 md5 相同的字串,使用這個 usr 算出的 mac2 會和 mac 相同,並且 usr 沒有在程式裡註冊過,符合條件,就可以拿到 flag 了 ## [HW 0x09] Oracle's Revenge 題目有兩個 command login 是讀入 usr 和 pwd,隨機生成 vc,組成 `{'usr': usr, 'pwd': pwd, 'vc': vc}` 用 msgpack 編碼,再用 AES-CBC 加密作為 token 回傳,然而 vc 卻沒有回傳 verify 是讀入 token 和 vc,將 token 解密後,檢查 token 裡帶的 vc 和輸入的 vc 是否相同,不過程式會在 vc 相同時將 usr 的值以 ascii 印出,所以不太能任意修改 因為 AES-CBC 的解密方法是 ``` aes-cbc-dec(ciphertext[i]) = aes_decrypt(ciphertext[i]) ^ ciphertext[i - 1] = plaintext[i] ``` 所以可以用以下的方法建構任意 new_plaintext ``` fake_cihpertext = ciphertext[i - 1] ^ plaintext[i] ^ new_plaintext aes-cbc-dec(ciphertext[i]) = aes_decrypt(ciphertext[i]) ^ fake_ciphertext = aes_decrypt(ciphertext[i]) ^ ciphertext[i - 1] ^ plaintext[i] ^ new_plaintext = plaintext[i] ^ plaintext[i] ^ new_plaintext = new_plaintext ``` 所以就可以將 ciphertext 換掉,讓 vc 可控 ``` Username: a * 5 Password: a * 27 plaintext: \x83\xa3usr\xa5aaaaa\xa3pwd\xbb|aaaaaaaaaaaaaaaa|aaaaaaaaaaa\xa2vc\xda\x00|... new_plaintext: \x83\xa3usr\xa5aaaaa\xa3pwd\xbb|decrypt(fake ciphertext)|aaaaaaaaaaa\xa2vc\xa10 aes_decrypt(token[64:96]) ^ (fake ciphertext) == aaaaaaaaaaa\xa2vc\xa10 aes_decrypt(token[64:96]) = plaintext[64:96] ^ token[32:64] = aaaaaaaaaaa\xa2vc\xda\x00 ^ token[32:64] fake ciphertext = aaaaaaaaaaa\xa2vc\xa10 ^ aaaaaaaaaaa\xa2vc\xda\x00 ^ token[32:64] {usr: aaaaa, pwd: (courrpted data)aaaaaaaaaaa, vc: 0} ``` 將 vc 換成 0 後輸入 0 就可以拿到 flag 了
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up