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!}