# [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 %}