2021 AIS3 EOF Final - Mugyu, Raffle 官方解
這次 EOF Final 擔任出題者出了兩題 Reverse,感覺再多加一點難度會更有意思。
題目:Mugyu, Raffle
Before we start
- 原始碼 & 題目:https://github.com/Artis24106/My-CTF-Challenges/tree/main/2021-AIS3-EOF-Final
- mugyu 原始碼:https://github.com/Artis24106/mugyu
Mugyu
244 points / 13 solves

Challenge Info
むぎゅ〜〜〜

File: mugyu, n3k0, lov3, README.md
Solution
README.md
| |
n3k0
n3k0 看起來是一個 flag checker

解完得到假 flag:
| |
直接執行 ./n3k0 時假 flag 可以通過檢查,但用 ./mugyu n3k0 就不能,明顯程式流程不一樣。
還有在 main 之前會執行 sub_1188,呼叫 syscall 0x8763。

mugyu
Symbol 給好給滿,應該不難發現 mugyu 是改過的 qemu。
n3k0 會呼叫不存在的 syscall,所以可以朝這方面去觀察。
syscall 在 do_syscall1() 實作(main() -> cpu_loop() -> do_syscall() -> do_syscall1()),F5 下去跟原始碼沒兩樣:

也就是說 syscall 0x8763 有兩個參數:
- edi:addr offset (
0x4000000000 + edi) - esi:crystal index (
crystal[esi])
會把 crystal[esi] 的 machine code patch 到 0x4000000000 + edi。
另外 crystal 會在 load_elf_binary() 做初始化:讀入 lov3 並解密,然後存在 crystal。

Patch n3k0
寫個腳本自己上 patch,n3k0 變成下面那樣,其實就是把 checker 內容換掉而已:

Flag
EOF{sin6u14r_uni7_de73ct3d_id_tr4cing_c0ordin4te_fixed_r3p0rt_c0mple7e.}
Raffle
436 points / 7 solves

Challenge Info
I will not raffle anything…
File: raffle
Solution
raffle 是 golang binary,並且有給 symbol。
這題逆向部分很簡單:main() 會建立三個 goroutine(node_XXXX()),每個 goroutine 又會再叫三個 goroutine,總共三層,共 39 個 node 被叫起來;每個 node 會對輸入做三個小運算。
運算都很簡單,重點在 node 的執行順序:
Method1: 靜態解
goroutine 的執行順序由 GMP 排程器決定,理論上不會固定。
但因為在 main() 之前會執行 runtime.GOMAXPROCS(1),這讓 goroutine 的執行順序與「從 runnable queue」取出順序一樣,原始碼在 /usr/lib/go-1.13/src/runtime/proc.go:
| |
基本上就是一個 queue,但是最後一個放進去的 goroutine 會第一個執行,舉個例子:
| |
執行順序會是:node_3() -> node_0() -> node_1() -> node_2()
Method2: 動態解
解法由
@frozenkp提供
在 node 設斷點會導致之後的執行順序亂掉,因此:
- 對全部 node 設斷點,如此一來第一個撞到斷點的 node 是第一個執行的 node。
- 把第一個 node 的斷點去掉,並重新執行程式,第一個撞到斷點的 node 是第二個執行的 node。
- 總共重複 39 次就能爆破出執行順序
Method3: 模仿(?)解
直接寫一隻程式模仿 raffle 創建 goroutine,把順序印出來。
知道執行順序之後就看要用 z3 或是寫個解密腳本拿 flag。
Flag
EOF{w3_4r3_901ng_70_raffl3_0fF_A_g0...g0-r0u71n3!}