---
# System prepended metadata

title: HW 0x04 Write Up
tags: [Course, CS, NCTU, SecureProgramming]

---

###### tags: `NCTU` `CS` `Course` `SecureProgramming`

HW 0x04 Write Up
==
yysung

## [Lab 4-1] Bof1
flag: FLAG{f1rst_b0f?_1tS_34sy}

輸入可以蓋掉 stack 16 bytes，將後面 8 bytes 蓋成指定的值就可以拿到 shell 了 

## [Lab 4-2] Bof2
flag: FLAG{B0f_1s_N0t_On1y_r34D_TrY_tH3_b0uNd!!!}

輸入可以蓋掉特定位置成指定的值，會輸出 `Passed` 但無法拿到 shell

程式中有一個 `debug_shell` 函式會呼叫 shell，所以目標是呼叫該函式

輸入的可以蓋的位置是 `0x601080 + 輸入值*8`，puts 的 .got.plt 是 `0x601018`

所以只要先輸入 `(0x601080-0x601018)/8` 再輸入 `debug_shell` 函式的位址

下一次執行 puts 就會跳到 `debug_shell`，拿到 shell 了

debug_shell 0x400697
puts .got.plt 0x601018
secret 0x601080

## [Lab 4-3] Bof3
flag: FLAG{R0P_1s_lNt3rST1ng_r1gh1_g4dg3t_g4dg3t_g4dg3t}

題目有給出 libc.so，所以可以使用 libc 上的 gadget 拿到 shell

要先得到 libc 的 base，可以先將 puts 實際上的位址印出

方法是使用 ROP，用 ROGgadget 找出能用的 gadget 並放在 return address 以上的 stack 空間

先放入 `pop rdi` 的 gadget，再放入 `puts_got` 的位址，執行後 rdi 裡就會是 `puts_got` 的位址

再放入 `puts_plt` 的位址就會執行 puts 並將 `puts_got` 位址裡的值，也就是 puts 實際上的位址印出

再放入 main 的位址重新執行程式

libc 的 base 就是 puts 實際上的位址減去 puts 在 libc 上的 offset

接下來就可以將 onegadget 找到的 gadget 再次使用 buffer overflow 蓋掉 return address ，就可以拿到 shell

## [HW4] goto
flag: FLAG{g0_b1n4ry_1s_pmu4d13_bnT_n0t_Th4t_34sy_QQ}

程式有兩次輸入，第一次輸入可以產生 buffer overflow

輸入 `'A' *152` 程式會終止並印出除錯訊息指出 `runtime.slicebytetostring` 執行失敗

原因是參數被 buffer overflow 修改而執行失敗。將代表複製長度的第二個參數改成零，也就是改輸入 `'A' * 144 + '\x00' * 8` 就不會產生錯誤

繼續增加長度直到 `'A' * 144 + '\x00' * 8 + 'A' * 184` 時程式會終止並印出除錯訊息表示 return address 被變動，代表已覆蓋到 return address

追蹤程式執行後會發現，第一次輸入會被複製進 stack 上的 `0xc420047e38`，而 return address 是 `0xc420047f80`，所以覆蓋 328 bytes 就會剛好覆蓋 return address

接下來使用 ROPgadget 可以找到許多可以使用的 gadget 來湊出 read 和 exec syscall，將 read 到的資料放在 bss 段記憶體並 exec

再次輸入 `/bin/sh\x00` 就可以執行執行 shell

使用到的 gadget 有 `pop_rax` `pop_rdi` `pop_rsi` `pop_rdx` `syscall`，read 和 exec 使用的 buf 選擇 `0x53f000`

其中 `pop_rsi` 的 gadget 後面會去修改 rax 指到的位址，所以在使用 `pop_rsi` gadget 之前要先使用 `pop_rax` 將 rax 修改成合法空間
