###### tags: `CTF Write Up`
# 2019 AIS3 EOF quals
## Reverse1: H0W
這題作者用 編譯了 一個 c share library 並用 python
這題解題上分成幾個步驟
1. 了解 在 python 上使用 c 的shared library 方式
2. trace shared library 每個呼叫到的函式作用(gdb+ida)
3. 配合 python 腳本分析整體流程
4. 逆推流程與撰寫腳本
Debug 是我花最久時間的,因為以前完全沒遇過過要debug python 的狀況
### python shared library
因為C 的速度比python快很多,因此 python share library 常用在一些要加速的功能上,編譯的方式可以看下方ref
https://stavshamir.github.io/python/making-your-c-library-callable-from-python-by-wrapping-it-with-cython/
### trace shared library
接著就直奔主題吧,針對debug python 的部分,官方就有一些文件了,[請看這](https://wiki.python.org/moin/DebuggingWithGdb)
這題的sharedlibrary 我不確定是不是故意的但作者好像故意把會 call 到的 function symbol 給刪除了,導致沒辦法直接用靜態分析就對應 function 名,因此我用 GDB 下斷點加上修改 python script去讓他每 call 完一個 lib function 後停住,這樣會比較方便抓出call的是哪個function
抓出每個function後,就可以開始靜態加動態分析去了解整個流程,下面是我理解出的每個 function 功能
nini3: 開檔 output.txt
nini1: 抓時間
nini4: srand(time)
nini5: 做混淆(會用到rand去生成隨機數)
nini2: 將時間寫入output(包含年月星期時分秒)<-沒有日期所以有4種可能
nini6: 寫檔 output.txt
下面這些會再nini4 被 call 到
ichinokata: 混淆函數1
ninokata: 混淆函數2
sannokata: 混淆函數3
yonnokata: 混淆函數4
### 程式整體流程
1. 抓現在 timer 暫存器的值: X
2. 在同個資料夾下開啟output.txt,準備寫入
3. 將剛剛抓得到的 X 丟進 srand
4. 將一個文檔分成4byte 一組 for 迴圈執行 5,6
5. 用 c rand function 得出一個隨機數後 mod 3 這個值會被拿來決定混淆的方式
6. 將混淆過後的結果寫入 output.txt
7. 最後將時間用 gmtime 的形式寫進 output.txt
### 逆推流程與撰寫腳本

這題的關鍵就在它有在最後附上他的時間點,因此我們可以推算出傳進 srand 的值進而拿到同樣的rand值,由於他的寫法是 Year Month Week Hour Min Sec,可以發現作者這邊故意設計不把day印出所以總共可能的時間有四個
我們的攻擊腳本要有以下功能
- time 轉成 timestamp
- 利用 c 的 rand 得出所有的隨機值 (這邊記得不要用 python 的 random 因為實作有點不同)
- 反推每個混淆過程,做成function
順利的話就可以跑出四個 binary,稍微看一下就可以發現是 png 圖檔,其中一張是正常的,其他是都壞的
ref
https://www.tutorialspoint.com/c_standard_library/c_function_gmtime.htm
https://www.geeksforgeeks.org/rotate-bits-of-an-integer/
## Reverse2: pokemonGO
這題是Go的逆向題,整體追code還蠻算蠻容易的,但畢竟是沒學過的語言稍微學了一下語法
解題步驟如下
1. 找出 log 的規則
2. 關鍵程式 log
3. 整理成公式 & Get FLAG
### 找出規則
這份 trace log 有很多方法可以追蹤,那我的作法是先利用scanf (因為有source code)去稍微讀懂 source code 和 trace log 的關係。我這邊舉出兩個我覺得比較重要的
#### for 迴圈格式
從0開始到t3 index 放在 t12
```go
t12 = phi [0: 0:int, 5: t14, 17: t32] #i
t13 = t12 <= t3
if t13 goto 2 else 3
.2:
t6 = slice format[t12:]
t7 = (*ss).advance(s, t6)
Entering (*fmt.ss).advance at /usr/lib/go-1.10/src/fmt/scan.go:1067:14.
.0:
jump 3
.3:
t5 = phi [0: 0:int, 14: t10, 41: t65, 30: t10, 33: t10] #i
t6 = len(format)
t7 = t5 < t6
if t7 goto 1 else 2
```
#### func回傳值
```
//t2,t3 := func...
t2 = extract t1 #0
t3 = extract t1 #1
```
### 關鍵程式 log
分析程式很重要的一點是挑重點看,log在呼叫到function後會去往下 CALL go 原生的source 那種我們就可以不用看了。
第一段 call scanf ,這邊用 scanf 是在輸入密碼
```go
Entering main.main at /home/terrynini38514/Desktop/PokemonV2.go:38:6.
.0:
t0 = new string (input)
t1 = new [1]interface{} (varargs)
t2 = &t1[0:int]
t3 = make interface{} <- *string (t0)
*t2 = t3
t4 = slice t1[:]
t5 = fmt.Scanf("%s":string, t4...)
```
第二段 呼叫 關鍵副程式 PikaCheck
```go
Leaving fmt.Scanf, resuming main.main at /home/terrynini38514/Desktop/PokemonV2.go:40:14.
t6 = *t0
t7 = PikaCheck(t6)
```
第三段 進入PikaCheck(input)
建立一個 int a[20]
並 for loop 20次,每次都執行 a[i] = ascii(input[i]) + ascii(input[(i+1)%20])
還原程式碼
```
for (i=0;i<len(input);i++)
a[i] = ascii(input[i]) + ascii(input[(i+1)%20])
```
附上原log
```go
Entering main.PikaCheck at /home/terrynini38514/Desktop/PokemonV2.go:6:6.
.0:
t0 = local [20]int (a)
jump 3
.3:
t92 = phi [0: 0:int, 1: t10] #i
t93 = len(input)
t94 = t92 < t93
if t94 goto 1 else 2
.1:
t1 = &t0[t92]
t2 = input[t92]
t3 = convert int <- uint8 (t2)
t4 = t92 + 1:int
t5 = len(input)
t6 = t4 % t5
t7 = input[t6]
t8 = convert int <- uint8 (t7)
t9 = t3 + t8
*t1 = t9
t10 = t92 + 1:int
jump 3
.3:
t92 = phi [0: 0:int, 1: t10] #i
t93 = len(input)
t94 = t92 < t93
if t94 goto 1 else 2
.1:
t1 = &t0[t92]
t2 = input[t92]
t3 = convert int <- uint8 (t2)
t4 = t92 + 1:int
t5 = len(input)
t6 = t4 % t5
t7 = input[t6]
t8 = convert int <- uint8 (t7)
t9 = t3 + t8
*t1 = t9
t10 = t92 + 1:int
jump 3
...
...
...
.3:
t92 = phi [0: 0:int, 1: t10] #i
t93 = len(input)
t94 = t92 < t93
if t94 goto 1 else 2
.1:
t1 = &t0[t92]
t2 = input[t92]
t3 = convert int <- uint8 (t2)
t4 = t92 + 1:int
t5 = len(input)
t6 = t4 % t5
t7 = input[t6]
t8 = convert int <- uint8 (t7)
t9 = t3 + t8
*t1 = t9
t10 = t92 + 1:int
jump 3
.3:
t92 = phi [0: 0:int, 1: t10] #i
t93 = len(input)
t94 = t92 < t93
if t94 goto 1 else 2
```
再來就做了加減法的動作後做compare
```go
if (a[0]-185+a1[1]-212+a[2]-172+a[3]-145+a[4]-185+a[5]-212+a[6]-172+a[7]-177+a[8]-217+a[9]-212+a[10]-204+a[0]-177+a[11]-185+a[12]-212+a[13]-204+a[14]-209+a[15]-161+a[6]-124+a[17]-172+a[18]-177==0){
return true
else
return false
}
```
``` go
.2:
t11 = &t0[0:int]
t12 = *t11
t13 = t12 - 185:int
t14 = 0:int + t13
t15 = &t0[1:int]
t16 = *t15
t17 = t16 - 212:int
t18 = t14 + t17
t19 = &t0[2:int]
t20 = *t19
t21 = t20 - 172:int
t22 = t18 + t21
t23 = &t0[3:int]
t24 = *t23
t25 = t24 - 145:int
t26 = t22 + t25
t27 = &t0[4:int]
t28 = *t27
t29 = t28 - 185:int
t30 = t26 + t29
t31 = &t0[5:int]
t32 = *t31
t33 = t32 - 212:int
t34 = t30 + t33
t35 = &t0[6:int]
t36 = *t35
t37 = t36 - 172:int
t38 = t34 + t37
t39 = &t0[7:int]
t40 = *t39
t41 = t40 - 177:int
t42 = t38 + t41
t43 = &t0[8:int]
t44 = *t43
t45 = t44 - 217:int
t46 = t42 + t45
t47 = &t0[9:int]
t48 = *t47
t49 = t48 - 212:int
t50 = t46 + t49
t51 = &t0[10:int]
t52 = *t51
t53 = t52 - 204:int
t54 = t50 + t53
t55 = &t0[11:int]
t56 = *t55
t57 = t56 - 177:int
t58 = t54 + t57
t59 = &t0[12:int]
t60 = *t59
t61 = t60 - 185:int
t62 = t58 + t61
t63 = &t0[13:int]
t64 = *t63
t65 = t64 - 212:int
t66 = t62 + t65
t67 = &t0[14:int]
t68 = *t67
t69 = t68 - 204:int
t70 = t66 + t69
t71 = &t0[15:int]
t72 = *t71
t73 = t72 - 209:int
t74 = t70 + t73
t75 = &t0[16:int]
t76 = *t75
t77 = t76 - 161:int
t78 = t74 + t77
t79 = &t0[17:int]
t80 = *t79
t81 = t80 - 124:int
t82 = t78 + t81
t83 = &t0[18:int]
t84 = *t83
t85 = t84 - 172:int
t86 = t82 + t85
t87 = &t0[19:int]
t88 = *t87
t89 = t88 - 177:int
t90 = t86 + t89
t91 = t90 == 0:int
if t91 goto 4 else 5
```
回傳是錯誤
```go
.5:
return false:bool
Leaving main.PikaCheck, resuming main.main at /home/terrynini38514/Desktop/PokemonV2.go:41:17.
if t7 goto 1 else 3
.3:
t23 = new [1]interface{} (varargs)
t24 = &t23[0:int]
t25 = make interface{} <- string ("Nothing here my d...":string)
*t24 = t25
t26 = slice t23[:]
t27 = fmt.Println(t26...)
Entering fmt.Println at /usr/lib/go-1.10/src/fmt/print.go:263:6.
.0:
```
### 整理成公式 & Get FLAG
解法就是 a[0] = input[0]+input[1] = 185 依此類推,就可以找出幾組成功的解,從中找到有意義的那個就是答案了
```go
var a[20]int
for (i=0;i<len(input);i++)
a[i] = ascii(input[i]) + ascii(input[(i+1)%20])
if (a[0]-185+a1[1]-212+a[2]-172+a[3]-145+a[4]-185+a[5]-212+a[6]-172+a[7]-177+a[8]-217+a[9]-212+a[10]-204+a[0]-177+a[11]-185+a[12]-212+a[13]-204+a[14]-209+a[15]-161+a[6]-124+a[17]-172+a[18]-177==0){
return true
else
return false
}
```
## Reverse3: YugiMuto
這題的難度應該算是 debugging 工具麻煩加上不熟悉的處理器架構,我這邊是過蠻多工具的,後來是使用 bgb 和 radare2 當我的調試工具
解題步驟:
1. 找到合適的中斷點以及關鍵 function
2. document 嗑下去
3. 找到密碼
### 找到合適的中斷點以及關鍵 function
進入輸入密碼的環節後就會發現程式一直loop在 0x10d6 ~ 0x128a 因此大膽推測這邊就是在等待使用者操作,所以直接先breakpoint在下一行,測試一下就發現抓對了

### document 嗑下去
抓到密碼認證關鍵程式碼後,就必須開始trace code 了但是這個架構以前完全沒看過,因此在trace的過程最好搭配 [官方 document](http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
)
主要程式我就不細講,下面這個是用radare2畫出來的graph,藍色線路徑是一個loop,loop次數是0x14 不難猜到應該就是每個字會進行一次回圈判斷那個字是否正確,因此框起來的部分就是我們要看注意的,

分析到最後會發現他會把密碼放在stack上,因此抓下來就是答案了
ref
https://github.com/VoidHack/write-ups/tree/master/Square%20CTF%202017/reverse/gameboy
https://github.com/devdri/awake
http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
## Reverse5: DuRarara
這題好玩了一點,簡單來說會有一隻程式開一隻新程式,但這支子程式並沒有辦法attach 上去,因此要想辦法繞過,
解題步驟:
1. 主程式 trace code
2. 動態提取 memory 成執行檔
4. 子程式 trace code
5. 找到關鍵運算程式 & get password
### 1. 主程式 trace code
追進去看code 就會發現有一個子程式是由父程式動態被噴進記憶體的,知道這個之後我們的目標不在是看這些實際上複製哪些程式碼,而是去將子程式抓出來調試

我的方法是在 resumethread 前停住,然後開啟另一個x64 dbg attach 新開的子程式後,在 qDbgUiRemoteBreakin 這個函式時下一個斷點,因為個函式會檢查 dbgsymbol,因此要手動去 PEB 表那裡將 DEBUGGING FLAG 設為 0,這樣就可以進入 entrypoint,進入entrypoint 會發現 address 跟原本的 0x951xxx 是不一樣的,子程式會被放在0x401a59

接著我們就可以用dbg的插件將這段記憶體 dump 成一個PE 檔,利用x64dbg的套件把整個memory dump下來成為一個 PE file

接下來就是過驗證,這邊應該沒幾下就可以看到關鍵function了,作者在這邊做了一些複雜的計算,所以要稍微仔細看一下,最後就可以找出密碼了 `FLAG{D-Day:2020/01/14}`

**補充資訊**
qDbgUiRemoteBreakin 是用來讓一些debug參數用的
ZwContinue 傳進去的兩個參數 其中一個是entrypoint 進入點的指針結構塊
ZwContinue 呼叫前會看到存放PIE指針的結構塊
https://docs.microsoft.com/zh-tw/windows/win32/api/winnt/ns-winnt-arm64_nt_context?redirectedfrom=MSDN
https://aaaddr.wordpress.com/2015/01/08/%E4%BB%A5debugger%E5%8E%9F%E7%90%86%E6%8B%86%E8%A7%A3line%E7%9A%84anti-debug-attach/
https://www.unknowncheats.me/forum/assembly/316066-dbguiremotebreakin-bypass.html