# [CH] How Is Your Math ###### tags: `Writeup` `Crypto` `Chinese` > [name=curious] ## 先備知識 ### Xor - Boolean's xor | $\oplus$ | True | False | | --------- | ----- | ----- | | **True** | False | True | | **False** | True | False | - Integer's xor ``` 53 ^ 79 = 122 53 = (bin) 110101 ^ 79 = (bin) 1001111 ---------------------- 122 = (bin) 1111010 ``` - Character's xor ``` 'e' ^ 'L' = (ASCII) 101 ^ 76 = 41 = ')' ``` - String's xor ``` 'lHQL)#$' ^ 'Curious' = '/=#%FVW' 'l' 'H' 'Q' 'L' ')' '#' '$' ^ 'C' 'u' 'r' 'i' 'o' 'u' 's' ------------------------------- '/' '=' '#' '%' 'F' 'V' 'W' ``` ### AES CBC Mode 我們不需要知道 AES 詳細的加密過程,只需要知道輸入一個 16, 24 或 32 bytes 的金鑰和 16 bytes 的明文,經過 AES 加密後就可以輸出一個 16 bytes 的密文。同樣輸入相同的密鑰和密文,經過 AES 解密就可以的到相應的明文。 > 想要知道詳細的 AES 加解密過程可以看:[Github](https://github.com/Curious-Lucifer/Crypto_Implementation) 因為基本的 AES 只能處理 16 bytes 的明/密文,為了要處理非 16 bytes 的加解密,所以 AES 會搭配不同的加密模式處理明/密文。 AES CBC Mode 就是一個處理 16 * n bytes 的加密方式。當輸入一個長度為 16 * n bytes 的明文和一個長度為 16 bytes 的 IV 時,CBC Mode 會先將明文分成各個 16 bytes 一個 block,然後做以下運算 ``` ################################################################## # AES CBC Mode (Encrypt) # ################################################################## # # # ----------- ----------- ----------- # # | plain1 | | plain2 | | plain3 | # # ----------- ----------- ----------- # # ------ | | | # # | IV | --> ⊕ *-------> ⊕ *-------> ⊕ # # ------ | | | | | # # ----------- | ----------- | ----------- # # | | | | | | | | # # | Encrypt | | | Encrypt | | | Encrypt | # # | | | | | | | | # # ----------- | ----------- | ----------- # # | | | | | # # ----------- | ----------- | ----------- # # | cipher1 |---* | cipher2 |---* | cipher3 | # # ----------- ----------- ----------- # # # ################################################################## ``` 相應的如果要解密一個長度為 16 * n bytes 的密文時,輸入密文和 16 bytes 的 IV 後,將密文分成各個 block,然後做以下運算 ``` ################################################################## # AES CBC Mode (Decrypt) # ################################################################## # # # ----------- ----------- ----------- # # | cipher1 |---* | cipher2 |---* | cipher3 | # # ----------- | ----------- | ----------- # # | | | | | # # ----------- | ----------- | ----------- # # | | | | | | | | # # | Decrypt | | | Decrypt | | | Decrypt | # # | | | | | | | | # # ----------- | ----------- | ----------- # # ------ | | | | | # # | IV | --> ⊕ *-------> ⊕ *-------> ⊕ # # ------ | | | # # ----------- ----------- ----------- # # | plain1 | | plain2 | | plain3 | # # ----------- ----------- ----------- # # # ################################################################## ``` --- ## 思路 從 `server.py` 中可以知道,`cipher` 和 `plain` 都是 48 bytes,所以可以把 `cipher` 分成 `cipher1`, `cipher2`, `cipher3`,`plain` 分成 `plain1`, `plain2`, `plain3`。 假設 `cipher3` 經過 AES 解密出來是 `plain3'`,所以 `plain3` = `plain3'` $\oplus$ `cipher2`。如果想要改變 `plain3` 成特定的值,要不就改變 `plain3'`,要不就改變 `cipher2`。 如果要改變 `plain3'`,就要透過改變 `cipher3`,但改變 `cipher3` 為 `plain3'` 帶來的改變是不可預期的,所以想要把 `plain3` 改成特定的值,就只有改變 `cipher2` 這條路可以走。 --- ## 解法 另 $C_2$ = `cipher2`, $P_3'$ = `plain3'`, $P_3$ = `plain3`, $P_{3, new}$ = `new plain3` 已知 $P_3 = C_2 \oplus P_3'$,若將 $C_2$ 改成 $C_2 \oplus P_3 \oplus P_{3, new}$ 則 $$ \begin{align} (C_2 \oplus P_3 \oplus P_{3, new}) \oplus P_3' &= (C_2 \oplus P_3') \oplus P_3 \oplus P_{3, new} \\ &= P_3 \oplus P_3 \oplus p_{3, new} \\ &= 0 \oplus P_{3, new} \\ &= P_{3, new} \end{align} $$ Solve Script : ```python from pwn import * r = remote('lotuxctf.com', 30000) r.recvlines(22) cipher = bytes.fromhex(r.recvline().strip().split(b': ')[1].decode()) ori_plain_block = bytes.fromhex(r.recvline().strip().split(b': ')[1].decode()) new_plain_block = bytes.fromhex(r.recvline().strip().split(b': ')[1].decode()) cipher = cipher[:16] + xor(cipher[16: 32], ori_plain_block, new_plain_block) + cipher[32:] r.sendlineafter(b'> ', cipher.hex().encode()) r.interactive() ``` {%hackmd M1bgOPoiQbmM0JRHWaYA1g %}