# Chatroom
###### tags: `solved`
```python
md5(flag).hexdigest() = 'c0bdcfc620a83e9063a0da44917fdeca'
```
<!--
我在嘗試爆搜最後一個cypher看能不能用出'男'
```
系統訊息: b"'utf-8' codec can't decode byte 0xed in position 1: invalid continuation byte\x00\x00\x00"
系統訊息: b"'utf-8' codec can't decode byte 0xf8 in position 2: invalid start byte\x00\x00"
```
有時候會pad 2個 有時候會pad 3個
這樣的error code大概是9到10個block 應該可以從block個數 推是哪一種error
把md5的那串hash丟進去 通常是解不出utf-8可以看懂的東西
我覺得是要從error code你知道plaintext和ciphertext去回推什麼key之類的
我覺得輸出男不是重點 只知道有或沒有 而且就會break掉 不能繼續用了
我自己跑然後print他encrypt之前的東西
感覺每次encrypt都會生成他的iv
"但你丟cipher進去會哈哈哈" 因為解出來是字串 都屬於utf-8?
key 有2^64吧 8 byte random
我找網路上md5 decrypt的 都沒有
**cbc mode好像只有padding oracle attack?**
```
except UnicodeDecodeError as e:
print(f'系統訊息: {encrypt(str(e).encode()).hex()}')
```
你做什麼會跑出這個error
要丟cypher才可以吧
他會decrypt
然後check decrypt出來的值有沒有'男'
你從哪裡得到這個errorcode的
我發現同樣的input error code不一樣
每次都不一樣
但你丟cipher進去會哈哈哈
但他iv其實會付給你
所以用你已經找到的兩個可能性
我感覺md5是不是有弱點
男 = e794b7
```python=
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
from pwn import *
from hashlib import md5
from Crypto.Cipher import Blowfish
key = 0
def pad(m):
padlen = 8 - len(m) % 8
return m + bytes([0] * padlen)
def decrypt(c):
iv, c = c[:8], c[8:]
fish = Blowfish.new(key, Blowfish.MODE_CBC, iv=iv)
return fish.decrypt(c)
def encrypt(m):
fish = Blowfish.new(key, Blowfish.MODE_CBC)
return fish.iv + fish.encrypt(pad(m))
r = remote('eofqual.zoolab.org',10110)
print(r.recvline().decode())
get = r.recvline().decode()
print(get)
get = get[9:-1]
c_hex = get[:-32]
md5 = get[-32:]
print(c_hex)
print(md5)
boy_hex = '男'.encode('utf-8').hex()
print('男 = '+ boy_hex)
base = 16
target = 10
for value in range(1,16777216):
val_hex = ('00000' + hex(value)[2:])[-6:]
send_text = c_hex[base:base+target]+val_hex+c_hex[base+target+6:]
print(send_text)
r.sendlineafter('輸入訊息: ', send_text)
print(r.recvline().decode())
```
```python=
from pwn import *
#p = process('./server.py')
p = remote('eofqual.zoolab.org',10110)
p.recvuntil('間號碼: ')
res = p.recvuntil('系統訊息:',drop=True)[:-1]
res = str(res)[2:-1]
print(res)
res = bytes.fromhex(res)
print(res)
iv = res[:8]
c = res[8:-16]
b0 = res[8:16]
b1 = res[16:24]
b2 = res[24:32]
md5 = res[-16:]
print(iv.hex(),b0.hex(),b1.hex(),b2.hex(),md5.hex())
boy_hex = '男'.encode('utf-8').hex()
print('男 = '+ boy_hex)
#男 = e794b7
kone = ['8','9','a','b','c','d','e','f']
k = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
flag = ""
prev = bytes([0] * 2)
found = 0
print(prev)
for pos in range(6):
for a in kone:
for q in k:
xor = (a+q+"94b7")
tmp = int.from_bytes(b1, 'big') ^ (int(xor,16)<< (8*pos)) ^ (int.from_bytes(prev,'big')<< (8*pos))
tmp = tmp.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp.hex()+b2.hex())
get = p.recvline().decode()
#print(get)
if '離' in get:
print(b1.hex(), xor)
tmp = int(boy_hex,16) ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
print(tmp)
flag = tmp.decode()[-3] + flag
print(flag)
prev = tmp.decode()[-3].encode() + prev.decode()[0].encode()
print(prev)
found = 1
break
if found == 1:
break
found = 0
for a in kone:
for q in k:
xor = (a+q+"94b7")
x = int(xor,16) ^ int.from_bytes(prev,'big')
tmp1 = (int.from_bytes(b1, 'big')) ^ ((x & 0x00ffff)<<48)
tmp0 = (int.from_bytes(b0, 'big')) ^ ((x & 0xff0000)>>16) ^ ((x & 0x00ffff)<<48)
tmp1 = tmp1.to_bytes(8,'big')
tmp0 = tmp0.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp0.hex()+tmp1.hex()+b2.hex())
get = p.recvline().decode()
#print(get)
if '離' in get:
print(b1.hex(), xor)
tmp = int(boy_hex,16) ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
print(tmp)
flag = tmp.decode()[-3] + flag
print(flag)
prev = tmp.decode()[-3].encode() + prev.decode()[0].encode()
print(prev)
found = 1
break
if found == 1:
break
p.interactive()
```
-->
1. In the oracle, we can query if the output contains `男`. Since CBC block cipher XORs the IV with the decrypted string, try searching through the IVs and XOR back the modified bits with `男` and the plain text can be recovered.
2. UTF-8 encodes Chinese characters into 3 bytes, following the rules below. For a single byte ASCII character, the leading bit is always `0`, while 3-bytes Chinese characters, the first byte starts with `1110` and the following 2 bytes starts with `10`.
```
0x00000000 - 0x0000007F:
0xxxxxxx
0x00000080 - 0x000007FF:
110xxxxx 10xxxxxx
0x00000800 - 0x0000FFFF:
1110xxxx 10xxxxxx 10xxxxxx
```
ref: https://man7.org/linux/man-pages/man7/UTF-8.7.html
3. Assume the flag contains only ASCII characters and the padding is at least two bytes. Then for the last block, we only need to search through `(hex with leading 1)*(all possible hex)`. The complexity is `O(2^(3+4))` for each byte.
4. For the blocks without padding, we have to search through the bytes that matches the utf-8 encoded convention (printing 哈), and then try if '男' appears. Practice this part by trial and error.
5. Repeat step 4 until all blocks are decrypted, and the flag is found.
```python
from pwn import *
#p = process('./server.py')
p = remote('eofqual.zoolab.org',10110)
p.recvuntil('間號碼: ')
res = p.recvuntil('系統訊息:',drop=True)[:-1]
res = str(res)[2:-1]
print(res)
res = bytes.fromhex(res)
print(res)
iv = res[:8]
c = res[8:-16]
b0 = res[8:16]
b1 = res[16:24]
b2 = res[24:32]
md5 = res[-16:]
print(iv.hex(),b0.hex(),b1.hex(),b2.hex(),md5.hex())
boy_hex = '男'.encode('utf-8').hex()
print('男 = '+ boy_hex)
#男 = e794b7
kone = ['8','9','a','b','c','d','e','f']
k = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
flag = ""
prev = bytes([0] * 2)
found = 0
print(prev)
for pos in range(6):
for a in kone:
for q in k:
xor = (a+q+"94b7")
tmp = int.from_bytes(b1, 'big')
tmp = tmp ^ (int(xor,16)<< (8*pos)) ^ (int.from_bytes(prev,'big')<< (8*pos))
tmp = tmp.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp.hex()+b2.hex())
get = p.recvline().decode()
if '離' in get:
print(b1.hex(), xor)
tmp = int(boy_hex,16) ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
print(tmp)
flag = tmp.decode()[-3] + flag
print(flag)
prev = tmp.decode()[-3].encode() + prev.decode()[0].encode()
print(prev)
found = 1
break
if found == 1:
break
found = 0
def isEnglish(s):
try:
s.encode('ascii')
except UnicodeEncodeError:
return False
else:
return True
for a in ['a']: #kone
for b in ['c']: #kone
for c in ['d']: #kone
xor = (a+'0'+b+'0'+c+'0')
tmp = int.from_bytes(b0, 'big') ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp.hex()+b1.hex())
get = p.recvline().decode()
if '離' in get:
found = 1
elif ('哈' in get
and isEnglish((int(boy_hex,16) ^ int(xor,16)).to_bytes(8,'big').decode()[-3:])):
print(xor)
for q in ['2']: #k
for r in ['2']: #k
for s in ['2']: #k
xor = (a+q+b+r+c+s)
tmp = int.from_bytes(b0, 'big') ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp.hex()+b1.hex())
get = p.recvline().decode()
if '離' in get:
print(b1.hex(), xor)
tmp = int(boy_hex,16) ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
print(tmp)
flag = tmp.decode()[-3:] + flag
print(flag)
prev = tmp.decode()[-3:-1].encode()
print(prev)
found = 1
break
if found == 1:
break
if found == 1:
break
if found == 1:
break
if found == 1:
break
if found == 1:
break
found = 0
for pos in range(6):
for a in kone:
for q in k:
xor = (a+q+"94b7")
tmp = int.from_bytes(b0, 'big')
tmp = tmp ^ (int(xor,16)<< (8*pos)) ^ (int.from_bytes(prev,'big')<< (8*pos))
tmp = tmp.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp.hex()+b1.hex())
get = p.recvline().decode()
if '離' in get:
print(b1.hex(), xor)
tmp = int(boy_hex,16) ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
print(tmp)
flag = tmp.decode()[-3] + flag
print(flag)
prev = tmp.decode()[-3].encode() + prev.decode()[0].encode()
print(prev)
found = 1
break
if found == 1:
break
found = 0
for a in ['d']: #kone
for b in ['e']: #kone
for c in ['8']: #kone
xor = (a+'0'+b+'0'+c+'0')
tmp = int.from_bytes(iv, 'big') ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp.hex()+b0.hex())
get = p.recvline().decode()
for q in ['7']: #k
for r in ['6']: #k
for s in ['3']: #k
xor = (a+q+b+r+c+s)
tmp = int.from_bytes(iv, 'big') ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp.hex()+b0.hex())
get = p.recvline().decode()
if '離' in get:
print(b1.hex(), xor)
tmp = int(boy_hex,16) ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
print(tmp)
flag = tmp.decode()[-3:] + flag
print(flag)
prev = tmp.decode()[-3:-1].encode()
print(prev)
found = 1
break
if found == 1:
break
if found == 1:
break
if found == 1:
break
if found == 1:
break
if found == 1:
break
found = 0
for pos in range(6):
for a in kone:
for q in k:
xor = (a+q+"94b7")
tmp = int.from_bytes(iv, 'big')
tmp = tmp ^ (int(xor,16)<< (8*pos)) ^ (int.from_bytes(prev,'big')<< (8*pos))
tmp = tmp.to_bytes(8,'big')
p.sendlineafter('輸入訊息: ',tmp.hex()+b0.hex())
get = p.recvline().decode()
if '離' in get:
print(b1.hex(), xor)
tmp = int(boy_hex,16) ^ int(xor,16)
tmp = tmp.to_bytes(8,'big')
print(tmp)
flag = tmp.decode()[-3] + flag
print(flag)
prev = tmp.decode()[-3].encode() + prev.decode()[0].encode()
print(prev)
found = 1
break
if found == 1:
break
found = 0
p.interactive()
```
```
FLAG{0r4cL3_nEVeR_D1e}
```