---
# System prepended metadata

title: Chatroom-revenge
tags: [solved]

---

# Chatroom-revenge
1. md5 = 4b09433eeeba9ff1db650d4c9febff91
2. By trying 0x00 to 0xff for each byte, we can breifly understand the structure of the flag. 
    - If it has 128 possibilities to get **`陌生人: 哈哈哈哈`**, that means it is a single byte utf-8 as **`0x0XXXXXXX`**.
    - If it has 15 possibilities to get **`陌生人: 哈哈哈哈`**, that means it is the first byte of a 3-byte word as **`0x1110XXXX`**.
    - If it has 64 possibilities to get **`陌生人: 哈哈哈哈`**, that means it is the remaining byte of a  multibyte word as **`0x10XXXXXX`**.
3. Then the structure of the flag be like: 
**`{single byte}*5 + {3-byte}*4 + {single byte}*7`**
total: 3 blocks = 24 bytes (not including iv)
4. There is are only two conditions to make a 2-byte utf-8 to get UnicodeDecodeError, which are **`0x11000000`** and **`0x11000001`** for the first byte. Thus, we can get 2 possibility of each byte by trying to change the byte to begin with **`0x110`** and make the byte behind begin with **`0x10`**. Sometimes we have to make the orginally related bytes to be set as single byte utf-8 by letting it begin with **`0x0`**.
5. Code below is an example for finding the second bit of the second block.

<!-- 我註解掉了 你想留哪些 再改
https://man7.org/linux/man-pages/man7/UTF-8.7.html
可能可以用2~6個bytes的utf8去得到一個block這幾個對應位置的值
最後再暴搜有沒有符合md5的hash
`1111110x 1111110x 1111110x 111110xx 11110xxx 1110xxxx 110xxxxx 10xxxxxx`

然後再嘗試把一個byte變成底下的其中一種 噴error應該就可以反過來decrypt
> The bytes 0xc0, 0xc1, 0xfe, and 0xff are never used in the UTF-8 encoding.


既然是中文字然後flag形式是 FLAG{中文字}
去掉iv總共3個block
24 byte 扣掉FLAG{} 6個byte 除以3
最多有6個中文字
我覺得是既然知道是中文字 3個byte 就可以把6個byte組起來 
滿足 這條 1111110x ...

兩個3byte中文字 1110xxxx 10xxxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx

一個6byte 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

這樣就可以獲得更多最高位的資訊 幫助decode 當然換成2個byte配4個byte又可以得到不同位置 (任意組合一下) 1配5之類的

最優就解成這樣一個block 如果是有意義的中文字 可能可以猜出來? 可以知道哪幾個byte合起來是一個字 這樣就會更好猜一點
實際上就是5到6個中文字 FLAG{}也占掉幾個byte了 每個中文字有8個candidate 但可以組成一句話的不多吧
**`1111110x 1111110x 1111110x 111110xx (四byte 11110xxx (三byte 1110xxxx (兩byte 110xxxxx 10xxxxxx)))`**

那就只能先跳過吧... 能先還原一些資訊我覺得也不錯

- [x] step one: 戳戳看padding有多長 padding就是 `}\x00\x00` 之類的 都是一個byte
- [x] step two: 戳出中文字的byte再block裡面哪裡
- [ ] step three: 還原出 utf 8 各種長度byte可以的樣子

期望之中的FLAG: s 是還有機會拿到的
```
(F)01000110 (L)01001100 (A)01000001 (G)01000111 ({)01111011 1110xxxx 10'0'xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx 1110xxxx 10xxxxxx 
10xxxxxx 0'01'xxxxx (})01111101 00000000 00000000 00000000 00000000 00000000
```
```
(F)01000110 (L)01001100 (A)01000001 (G)01000111 ({)01111011 1110xxxx 10xxxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx 1110xxxx 10xxxxxx 
10xxxxxx 0xxxxxxx (})01111101 00000000 00000000 00000000 00000000 00000000
```
假設pad一個byte
那就讓他 ^ 101xxxxx 10xxxxxx看會不會 哈
依此類推
1001xxxx ([10xxxxxx] * 2)

(})01111101 ^ ascii 最高位 最後一個block都是ascii 應該不會隨便 哈
只要改了第一個 他就會認為他是一組的 可是前後不成一組 也會噴錯 就是讓它不要是0 然後看幾個byte湊起來可以過

我算pad了5個byte 還需要驗證一下就是了

應該沒有padding

目前我測的都符合這個假設
以下是我測過每個byte的可能姓
(128)*5(15)(64)(64) (15)(64)(64)(15)(64)(64)(15)(64) (128)*8


```
0x00000000 - 0x0000007F:
   0xxxxxxx

0x00000080 - 0x000007FF:
   110xxxxx 10xxxxxx

0x00000800 - 0x0000FFFF:
   1110xxxx 10xxxxxx 10xxxxxx

0x00010000 - 0x001FFFFF:
   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

0x00200000 - 0x03FFFFFF:
   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

0x04000000 - 0x7FFFFFFF:
   1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
```
```python=
# -*- coding: utf-8 -*-
from pwn import *
from hashlib import md5
from Crypto.Cipher import Blowfish

r = remote('eofqual.zoolab.org',10111)
print(r.recvline().decode()) # ===== 免費寂寞交友聊天室，24 小時真人在線聊天 =====
get = r.recvline().decode() # 聊天室房間號碼:
print(get)
get = get[9:-1]
c_hex = get[:-32]
block = [c_hex[0:16],c_hex[16:32],c_hex[32:48],c_hex[48:64]]
md5 = get[-32:]
print(r.recvline().decode()) # 系統訊息: 加密連線完成，開始聊天囉！
count=0
t = 12
b = 1
for tmp in range(256):
	# target = block[2][14:16]
	# x = tmp ^ int(target,16)
	val = ('00'+hex(tmp)[2:])[-2:]
	send_text = block[b][:t] + val + block[b][t+2:] + block[b+1] + block[b+2]
	r.sendlineafter('輸入訊息: ', send_text)
	rec = r.recvline().decode()
	if("哈" in rec):
		print('輸入訊息:',send_text)
		print(rec)
		count+=1
```


```python=
from pwn import *

def isEnglish(s):
    try:
        s.encode('ascii')
    except UnicodeEncodeError:
        return False
    else:
        return True 
        
def isUtf(s):
    try:
        s.decode('utf-8')
    except UnicodeEncodeError:
        return False
    else:
        return True 

#p = process('./server.py')
p = remote('eofqual.zoolab.org',10111)

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']
kzero = ['0','1','2','3','4','5','6','7']
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)

#FLAG{xHx

# 1110
# 0100

# 1010

for a in ['b']:
    xor = a+'f80'
    tmp = int.from_bytes(b1, 'big') ^ (int(xor,16)<< (32)) ^ (int('80',16)<< 56)
    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(xor,16)
        tmp = tmp.to_bytes(8,'big')
        print(tmp)
found = 0
    
for a in k:
    xor = '9'+a+'8080'
    tmp = int.from_bytes(b1, 'big') ^ (int(xor,16)<< (24)) ^ (int('80',16)<< 56)
    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(xor,16)
        tmp = tmp.to_bytes(8,'big')
        print(tmp)
found = 0
    
for a in kone:
    xor = '8'+a+'808080'
    tmp = int.from_bytes(b1, 'big') ^ (int(xor,16)<< (16)) ^ (int('80',16)<< 56)
    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(xor,16)
        tmp = tmp.to_bytes(8,'big')
        print(tmp)
found = 0

#o = bytes.fromhex("fd8080808080")
o = bytes.fromhex("c280")
print(o.decode('utf-8'))
print(isUtf(o))

                
p.interactive()
```
尋找第二個block第二個byte，原本為10xxxxxx
-->
```python
# -*- coding: utf-8 -*-
from pwn import *
from hashlib import md5
from Crypto.Cipher import Blowfish

r = remote('eofqual.zoolab.org',10111)
print(r.recvline().decode()) # ===== 免費寂寞交友聊天室，24 小時真人在線聊天 =====
get = r.recvline().decode() # 聊天室房間號碼:
print(get)
get = get[9:-1]
c_hex = get[:-32]
block = [c_hex[0:16],c_hex[16:32],c_hex[32:48],c_hex[48:64]]
md5 = get[-32:]
print(r.recvline().decode()) # 系統訊息: 加密連線完成，開始聊天囉！
b = 1 # block
s = 6 # byte from behind
for i in range(2,4):
    num2 = i<<5
    tmp_b = int(block[b],16) ^ (num2<<s*8) ^ (0x80<<(s+1)*8)
    send_text =  ('0'*16+hex(tmp_b)[2:])[-16:] + block[b+1] + block[b+2]
    r.sendlineafter('輸入訊息: ', send_text)
    rec = r.recvline().decode()
    print('輸入訊息:',('0'*16+hex(tmp_b)[2:])[-16:], block[b+1])
    print(rec)
    if("哈" in rec):
        for j in range(32):
            new_tmp_b = tmp_b ^ (j<<s*8)
            send_text =  ('0'*16+hex(new_tmp_b)[2:])[-16:] + block[b+1] + block[b+2]
            r.sendlineafter('輸入訊息: ', send_text)
            rec = r.recvline().decode()
            print('輸入訊息:',('0'*16+hex(new_tmp_b)[2:])[-16:], block[b+1])
            print(rec)
            if("哈" not in rec):
                print(hex(num2^0xc0^j))
                print(chr(num2^0xc0^j))
```
6. Discovered one by one:
F L A G { 0xe6 0x82or0x83 0x10xxxxxx
0xe6 0xa2or0xa3 0xb2 0xe6 0xacor0xad 0xb5 0xe6 0x94or0x95
0xb6or0xb7 0x38or0x39 } 0x00 0x00 0x00 0x00 0x00
7. Got the flag by comparing with md5.
```python=
from hashlib import md5
for a in ['82','83']:
    for b_t in range(128,192):
        b = hex(b_t)[2:]
        for c in ['a2','a3']:
            for d in ['ac','ad']:
                for e in ['94','95']:
                    for f in ['b6','b7']:
                        for h in ['38','39']:
                            for i in ['ae','af']:
                                for j in ['b8','b9']:
                                    tmp = bytes.fromhex('e6'+a+b+'e6'+c+i+
                                        'e6'+d+j+'e6'+e+f+h)
                                    flag = 'FLAG{' + tmp.decode('utf-8') +'}'
                                    encoded_flag = flag.encode('utf-8')
                                    md = md5(encoded_flag).hexdigest()
                                    if(md == '4b09433eeeba9ff1db650d4c9febff91'):
                                        print(flag)
```
**`FLAG{悠梯欸敷8}`**

###### tags: `solved`