AIS3 pre-exam 2021 – microchip


題目給了一個 micorchip.cpp 與 python.h
但 microchip.cpp 卻是一個長得很 python 的 cpp 檔

當下就對 code 做大概的清理,轉換成 python 能跑的格式

import string

def track(name, id) -> str :

    if len(name) % 4 == 0 :
        padded = name + "4444"
    elif len(name) % 4 == 1 :
        padded = name + "333"
    elif len(name) % 4 == 2 :
        padded = name + "22"
    elif len(name) % 4 == 3 :
        padded = name + "1"

    keys = list()
    temp = id
    for i in range(4) :
        keys.append(temp % 96)
        temp = int(temp / 96)

    result = ""
    for i in range(0, len(padded), 4) :

        nums = list()
        for j in range(4) :
            num = ord(padded[i + j]) - 32
            num = (num + keys[j]) % 96
            nums.append(num + 32)

        result += chr(nums[3])
        result += chr(nums[2])
        result += chr(nums[1])
        result += chr(nums[0])

    return result


def main() -> int :

    name = open("flag.txt", "r").read().strip()
    id = int(input("key = "))

    print("result is:", track(name, id))
    return 0

main()Code language: PHP (php)

所以程式大概就是傳進 flag 跟 key,並轉換成加密的文字
題目也有提供加密後的 flag : =Js&;*A`odZHi’>D=Js&#i-DYf>Uy’yuyfyu<)Gu

但問題是 flag 也不知道,key 也不知道,要解出來也不簡單
或者是….其實已經有flag的一部分了?

加密的函式 track 的第一段中,可以看到是在將 plaintext padding 到長度為 4 的倍數
第二段則是將 key 轉換成 96 進位的 4 digit keys
第三段也能看到 i 是 4的倍數在跳的
所以能發現 plaintext 是 4 個 4 個一組在做加密的

而 Flag 的形式是 AIS3{___________}
最前面的 4 個字剛好是已知的 AIS3
又 track 最後是反向的將 4 個字填入 result
所以在這邊能知道 encrypted 的前 4 個字 “=Js&” 為 “AIS3” + key 轉換而成

因此先將 encrypted 反向回來 “&sJ=”,且會分別對應到 A I S 3 這四個字
加密的公式是 (ord(plain) – 32) + keys[i] %96 = ord(encrypted) – 32
能寫成 python script

plain = "AIS3"
encrypted = "&sJ="
keys = []
for i in range(4):
    ch = ord(text[i]) - 32
    num = ord(cipher[i]) - 32
    key = num - ch
    if key < 0:
        key += 96
    keys.append(key)
key = 0
for i in reversed(keys):
    key *= 96
    key += i
print(key)Code language: HTML, XML (xml)

如果 num < ch 的話代表過程中有被 %96 去掉
所以要加回來

其中的 keys 在原加密函式中是左邊最小右邊最大
如 key = 124 , keys = [28,1,0,0]
所以倒過來算 key 的時候要由右往左算

透過這個 script 能得到 key = 9653253
有 key 了,就能很輕鬆的 decrypt 

寫個 python script 跑一下

text = "AIS3"
keys = []
# cipher = ";&sJ"
true_flag = "=Js&;*A`odZHi'>D=Js&#i-DYf>Uy'yuyfyu<)Gu"

keys = list()                                                               
key = 9653253                                                                   
for i in range(4) :                                                         
    keys.append(key % 96)                                                  
    key = int(key / 96) 

for i in range(0, len(true_flag), 4) :
    seg = true_flag[i:i+4]
    seg = seg[::-1]
    for j in range(4):
        num = ord(seg[j]) - 32
        num -= keys[j]
        if num < 0:
            num += 96
        print(chr(num + 32),end="")Code language: PHP (php)