# My First CTF/ Pre-exam 2024
題目前標`[MFC]`表在 My First CTF 解出來

[TOC]
## Misc
### [MFC] Welcome

flag in description
### Quantum Nim Heist
連上去玩遊戲, 玩了兩局發現這好像是個有必勝策略的遊戲, 所以基本無法依規則獲勝
翻一下原始碼後發現, 在 `server.py` 中的 `play` 函式控制大概的遊戲邏輯
```py=15
while not game.ended():
game.show()
print_game_menu()
choice = input('it\'s your turn to move! what do you choose? ').strip()
if choice == '0':
pile = int(input('which pile do you choose? '))
count = int(input('how many stones do you remove? '))
if not game.make_move(pile, count):
print_error('that is not a valid move!')
continue
elif choice == '1':
game_str = game.save()
digest = hash.hexdigest(game_str.encode())
print('you game has been saved! here is your saved game:')
print(game_str + ':' + digest)
return
elif choice == '2':
break
# no move -> player wins!
if game.ended():
win = True
break
else:
print_move('you', count, pile)
game.show()
```
在第18行的`input()`輸入的值並沒有限制輸入內容, 但如果在第一次詢問就輸入空字串會因為
第42行的`print_move('you', count, pile)`中的`count`未被賦值而拋出例外
所以必須先做一次正常的操作
因此只要在前面先做一次正常的移動後就可以什麼都不輸入直接`enter`讓 AI 動作
最後讓他動到只剩下一列就可以拿到flag
`AIS3{Ar3_y0u_a_N1m_ma57er_0r_a_Crypt0_ma57er?}`
---
想歪的部份:
因為遊戲有存/讀檔的功能, 就在想能不能建構出玩家必勝的棋局來獲勝
然後就開始看這驗證的hash沒有漏洞 浪費一堆時間
### Three Dimensional Secret
題目檔案載下來是個`.pcapng`
一開始都在看裡面沒看過的 SSDP 跟 MDNS
把每個封包翻過一遍後 想到好像有些基本的指令沒試
就`binwalk`、`strings` 一下
`strings`出來

注意到一些好像是座標的東西又想起標題提到Three Dimensional
然後想起pico上有一題 [speeds and feeds](https://play.picoctf.org/practice/challenge/116) 是 CNC 的移動路徑畫出來是 flag
Google 一下這座標的格式找到叫 `G code` 然後找線上工具
把整個 `strings` 的結果丟進 [webgcode](https://nraynaud.github.io/webgcode/)
flag就出來了

`AIS3{b4d1y_tun3d_PriN73r}`
### Emoji Console
一開始戳了幾下沒什麼頭緒
注意到🐱是`cat` 🚩是`flag`
理所當然嘗試了 cat flag
`cat: flag: Is a directory` 猜測flag可能在資料夾裡?
注意到💿是`cd` ⭐是 `*`
於是 `cat *` 看一下這裡有什麼 到這裡 python 的原始碼跟 emoji 轉換表就出來了
猜測的檔案結構

從 emoji 轉換的 json 檔知道, 有些emoji帶有 `;` 跟 `|` 可以用
想法: 進到 `flag` 資料夾(💿 🚩)把所有東西印出來(🐱 ⭐)
在這中間要先找個`;`截斷指令, 選了😓(;/)來用, 另外兩個結尾是`P` `)` 看起來就不好用
但`;/`會進到`/`還好但 permission denied 沒有進去
再來要在後面接`cat *` 所以接個pipe讓指令可以接下去
於是到目前的payload會是 `💿 🚩 😓 😑 🐱 ⭐` (cat flag ;/ :| cat *)
輸出得到

很明顯的是個 python script 再接個pipe丟進🐍(python)執行
就得到flag了
payload: `💿 🚩 😓 😑 🐱 ⭐ 😑 🐍`
`cd flag ;/ :| cat * :| python`
`AIS3{🫵🪡🉐🤙🤙🤙👉👉🚩👈👈}`
## Web
### [MFC] Evil Calculator
網頁打開是個計算機 可以做一步驟的運算
burp 攔個封包看到算式是包在json送到後端計算後再送回來
從原始碼可以看出有 `eval()`可以用, 但會過濾掉空格跟底線

既然是原本的`eval()`那就可以用python的內建函式
然後從解壓縮的檔案結構可以知道flag在上python程式碼的上一層資料夾
所以 payload 就會是 `open('./../flag').read()`
`AIS3{7RiANG13_5NAK3_I5_50_3Vi1}`
<!-- ### Login Panel Revenge Revenge (沒寫出來)
||但有一點點點點東西可以寫||
題目有給 source code 是 django 的網頁
裡面有看到一個`/image`可以把檔案載下來 但僅限於`loginPanel`的資料夾內
(有防path traversal)
就可以把DB載下來(`/image?file=L2xvZ2luUGFuZWwvZGIuc3FsaXRlMw==`)
就這樣
想說可以從DB裡面照session id撈登入要的2FA 結果有加密 key還是random的 -->
## Rev
### [MFC] The Long Print
丟進 ida 看一下 發現有一個等待很長的 `sleep`

開 r2 進去 patch

從`0x3674`改成`0x1`

然後儲存執行
但在最後會把 flag 清掉所以看過一遍後第二遍提早中斷來複製
`AIS3{You_are_the_master_of_time_management!!!!?}`
### 火拳のエース
丟 IDA 看

大致上是先給前面一小部份的flag
然後拿4個輸入做運算 算出來比對四個字串 如果4個都符合就是對的
這樣猜flag是我們要輸入進去比對的字串接起來
基本上就是逆推回去
先反推`complex_function`先把`string.ascii_uppercase`每個運算都先算出來在對應回去比對的字串
再撈xor的字串出來推回去

```python=
import string
def f(a2):
d = {}
for c in string.ascii_uppercase:
v8 = (17 * a2 + ord(c) - 65) % 26
v7 = a2 % 3 + 3
v2 = a2 % 3
if a2 % 3 == 2:
v8 = (v8 - v7 + 26) % 26
elif v2 <= 2:
if v2:
if v2 == 1:
v8 = (2 * v7 + v8) % 26
else:
v8 = (v7 * v8 + 7) % 26
d[chr(v8 + 65)] = c
return d
def xor_strings(a1, a2):
result = ""
for i in range(8):
v9 = hex(ord(a1[i]))[2:]
v8 = hex(ord(a2[i]))[2:]
v6 = int(v9, 16)
v5 = int(v8, 16)
v7 = hex(v6 ^ v5)[2:]
result += chr(int(v7, 16))
return result
with open('data.txt', 'r') as file: # xor string in data.txt
data = file.read()
data = data.split('\n\n')
for i in range(4):
data[i] = data[i].split('\n')
data[i] = [int(x, 16) for x in data[i]]
text = ["DHLIYJEG","MZRERYND","RUYODBAH","BKEMPBRE"]
data = [[14, 13, 125, 6, 15, 23, 118, 4], [109, 0, 27, 124, 108, 19, 98, 17], [30, 126, 6, 19, 7, 102, 14, 113], [23, 20, 29, 112, 121, 103, 116, 51]]
for s in range(4):
for i in range(8):
data[s][i] = chr(data[s][i])
s1, s2, s3, s4 = "", "", "", ""
for i in range(8):
d = f(i)
s1 += d[text[0][i]]
for i in range(8):
d = f(i+32)
s2 += d[text[1][i]]
for i in range(8):
d = f(i+64)
s3 += d[text[2][i]]
for i in range(8):
d = f(i+96)
s4 += d[text[3][i]]
print("AIS3{G0D", end='')
print(xor_strings(s1, data[0]), end="")
print(xor_strings(s2, data[1]), end="")
print(xor_strings(s3, data[2]), end="")
print(xor_strings(s4, data[3]))
```
`AIS3{G0D_D4MN_4N9R_15_5UP3R_P0W3RFU1!!!}`
data.txt
```
E
D
7D
6
F
17
76
4
6D
0
1B
7C
6C
13
62
11
1E
7E
6
13
7
66
0E
71
17
14
1D
70
79
67
74
33
```