---
# System prepended metadata

title: Chatroom
tags: [solved]

---

# 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}
```