Home 2021 AIS3 Write-up
文章
取消

2021 AIS3 Write-up

(the same as MFCTF)雖然沒有解很多題,但還是放上來好了XD

Cat Slayer ᶠᵃᵏᵉ | Nekogoroshi

trial and error

Microchip

從原始碼來看,他是 4 個 4 個為一組進行運算,再反過來輸出,而其中的 key 因為只會用到 4 個,所以用 Output 中的前四個 bytes 對應 AIS3 便可解出 key[4] = [69, 42, 87, 10],接著就寫個程式逆回去吧

1
2
3
4
5
6
7
8
output = "=Js&;*A`odZHi'>D=Js&#i-DYf>Uy'yuyfyu<)Gu"
key = [69, 42, 87, 10]
for i in range(0, 40, 4):
    for j in range(4):
        num = ord(output[i+3-j])-key[j]
        while num < 33 or num > 126:
            num += 96
        print(chr(num), end='')

Microcheese

我原本沒發現 bug,還在理解 splitmix64(),結果官方宣告有 bug 並修改釋出後的題目,對照兩者的程式碼發現當遊戲進行到一半,如果選擇 0, 1, 2 以外可以跳過自己的回合,於是就一直跳過,在最後一步的時候拿走最後一顆,就拿到 FLAG了

Microchess

這題是上面 Microcheese 修改後的版本,當我看了 splitmix64() 這個函式很久但還是找不到漏洞

於是就點開了 hint,裡面寫到某一部跟 md5、sha1 類似,因為原先看到能輸入遊戲代碼就大概想到要從那邊突破,原本是想把 secret 找出來然後重製我要的局面,但看到 hint 就想到了 LEA。

然後又看到這個結構,它會把上一個 block 運算過後的值拿去跟下一個 block 再運算一次

而這個函數會把字串填滿到八的倍數

所以我們可以想辦法把局面控制到 8 的倍數(e.g. 1,2,15,1)這樣就不需要 padding,而我們希望在後面加一堆,一進入遊戲就把那堆取走,這樣就換我們必勝了(如果會玩的話)。因此我們可以多製造一段 b',1/x00/x00/x00/x00/x00/x00'。把原先 hash 出的值,跟我們新加的 block 再 hash 一次,就有新局面的代碼了,接著就是玩遊戲,拿 flag (我不會玩遊戲,試了快 10 分鐘才贏)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def splitmix64(x: int) -> int:
    U64_MASK = 0xFFFFFFFFFFFFFFFF
    x = (x + 0x9E3779B97F4A7C15) & U64_MASK
    x = ((x ^ (x >> 30)) * 0xBF58476D1CE4E5B9) & U64_MASK
    x = ((x ^ (x >> 27)) * 0x94D049BB133111EB) & U64_MASK
    return x ^ (x >> 31)

def f(a: int, b: int) -> int:
    for i in range(16):
        a, b = b, a ^ splitmix64(b)
    return b

result = "2ae827becef7c60c"
mes = b',1\x00\x00\x00\x00\x00\x00'
blocks = [int.from_bytes(mes[i:i+8], 'big') for i in range(0, len(mes), 8)]
result_int = int(result, 16)
for block in blocks:
    fake_int = f(result_int, block)
    print(fake_int.to_bytes(8, 'big').hex())
本文章以 CC BY 4.0 授權