# PWN週 - ROP (Return Oriented Programmimg) :::info 【課程大綱】 - [環境準備](#課前環境準備) - 套件安裝 - [課程開始](#課程開始) - 大名鼎鼎的 ROP - Q1: 什麼使用情境需要 - **bypass NX** - Q2: 技術原理 - **bof + gadgets + Basic ROP** - Q3: Calling Convention - **分別適用於 x86/x64 架構、 ROP Chain** - Q4: 工具包介紹 - **ROPgadget** - 來到 Lab 環節! - 關於 ROP 的緩解方法 - [參考資料](#參考資料) >[name= islab WIFI] ::: # 環境準備 ## 套件安裝 - **Pwntools** - 寫 payload 的好朋友 - **ROPgadget** - 用來找合適的 gadgets 們 - **pwndbg** or **gef** or **peda** - 就是不同的 GDB plug-in # 課程開始 ## 大名鼎鼎的 ROP ### Q1: 什麼使用情境需要 - bypass NX * 主要是預防被寫入 shellcode,所以「可執行 segments 不可寫,可寫入的不可執行」 * 而 bypass 的方法,就是使用 ROP ! * 透過拼湊 binary 檔案中的程式小片段 Gadgets,達到控制 rip 或修改 register 的傳遞參數。 :::warning 接下來的教學範例與實作,**以 x64 (64-bits) 架構爲主** 。 ::: ### Q2: 技術原理 - Return to Gadgets #### Gadgets - 透過 `ret` = `pop rip` 去執行其他包含 `ret` 的程式片段。 - 以下程式片段為 `ret` 結尾的範例: 1. ![image](https://hackmd.io/_uploads/ByU6O7lAC.png) 2. ![image](https://hackmd.io/_uploads/rJ6kFXgR0.png) 3. ![image](https://hackmd.io/_uploads/rkvxFQlCR.png) #### Buffer Overflow - 沒有檢查使用者輸入邊界的 function - 透過 `gets()` 可從 user 的輸入讀取直到 EOF 或換行符號才停止。 - 或是 `strcpy()` 將原始 string 複製到 buffer。但複製的字串具體長度取決於原始字串的長度。 ![image](https://hackmd.io/_uploads/BJ_5sHMRC.png) - 因此,想要控制程式流程,就是覆蓋 `return address` 上的儲存數值。 - 再者,藉由 `ret = pop rip` ,讓 `rip` 帶著被修改的值,跳去指定 address。 #### Basic ROP ``` c //假設: 有一個正常程式流程不會跑到的 win function void win ( parameter ) if ( parameter = 0xdeadbeef ){ FILE *fd = fopen("flag.txt", "r"); } ``` ![image](https://hackmd.io/_uploads/B1vV_KMC0.png) ![image](https://hackmd.io/_uploads/SJDUdFG0R.png) ![image](https://hackmd.io/_uploads/HyTwOtfAC.png) ![image](https://hackmd.io/_uploads/By7tuFzRC.png) ![image](https://hackmd.io/_uploads/rkTqdFf00.png) ![image](https://hackmd.io/_uploads/Byf6dKGAC.png) #### 小統整 > **Step1. Control Flow Hijacking** > 在基礎的 ROP 概念中,透過 buffer overflow ,從 return address 獲得程式流程的控制權。 > **Step2. Gadget Chaining** > 根據 calling convention 的「參數傳遞」順序,於程式片段中, 挑選你所需要的 gadgets 並拼湊起來。 > **Step3. Payload Execution** > 撰寫 payload 串起前兩步驟,並搭配具有漏洞的程式開始執行時,就可以使用 chain of gadgets 做出超乎預期的行為。 ### Q3: X86/X64 的架構下 #### 根據不同的 Calling Convention > **X86 (32-bits)** - 使用 stack 傳遞參數: - 將 parameter 以輸入相反的順序(從右到左) push in stack。 > **X64 (64-bits)** - 使用 register 傳遞參數或指針的順序: - rdi -> rsi -> rdx -> rcx -> r8 -> r9 #### 知識小補充 > **X86 (64-bits)** 1. 假設為 Program 預設參數和指針在 stack 上的位置。 ![image](https://hackmd.io/_uploads/ry-6MKf0R.png) 2. 可以覆蓋放在 function 後的 parameters,將被帶入執行function中。![image](https://hackmd.io/_uploads/rkDpMFMRR.png) > **X64 (64-bits)** - 對於前幾個參數使用 registers 暫存與傳遞,相較於 x86 架構增加了更多的暫存器與擴大 address 空間。 同時,也提高了查找或鏈接合適 gadgets 的難度。 ### Q4: 工具包介紹 [ROPgadget Tool](https://github.com/JonathanSalwan/ROPgadget) #### 常用指令 - `--binary`: 指定的執行檔名稱。 - `--ropchain`: 自動生成 ROP Chain,但很有可能失敗,還是需要手工藝。 - `--only`: 使用正則表達式篩選合適的 gadgets。 - --only "pop|ret" - `--string`: 查找單一指定的 string。 - --string win ## 來到 Lab 環節! - 請先至雲端硬碟區,下載 Lab 的相關檔案 (o🪄'▽')o🪄 [G00gle Dr1ve 在此](https://drive.google.com/drive/folders/17o1iYlUNYYhi4aAvUvfzV3N9iVIDTmsA?usp=sharing) ### ret2text single #### 題目敘述 > - 還記得 ret2win 嗎? > - 我們來個進階版,這次你需要把 usefulstring 與 win 串接起來,才能夠獲得 Flag。 > - (hint: 使用 short ROP chain,重新組合 usefulstring 和 win ) #### Payload 填空 - **更改 ? 的內容**,以符合正確的 Basic ROP Payload。 - 需自行建立一個新檔案寫入 payload,並與 Lab 執行檔放在同個資料夾下。 ``` python from pwn import * p = process("./split") context.arch = 'amd64' pop_rdi_ret = ? useful_string = 0x601060 system = 0x40074b # 32-bytes padding buffer + 8-bytes rbp payload = b'a'*40 payload += p64(?) payload += p64(?) payload += p64(?) p.sendline(payload) p.interactive() ``` #### 題目參考資訊 - ghidra - ![image](https://hackmd.io/_uploads/r1dX52G00.png) - ![image](https://hackmd.io/_uploads/BJrntnGCR.png) - ![image](https://hackmd.io/_uploads/B1jZ93zCA.png) ``` $ checksec ``` ![image](https://hackmd.io/_uploads/HyYb83MA0.png) ``` $ info functions ``` ![image](https://hackmd.io/_uploads/B1rd8nMCA.png) ``` $ create pattern 0x30 $ pattern search 0x6161616161616165 ``` ![image](https://hackmd.io/_uploads/HyCRu3GR0.png) #### 問與答 1. X64 calling convention 下,**第一個傳遞參數的 register** 為何? 2. 以此挑選合適的 gadgets。 :::spoiler 你要的是哪一個 gadget? - [ ] ![image](https://hackmd.io/_uploads/S1JXYpz0A.png) - [ ] ![image](https://hackmd.io/_uploads/HJ4NtTMCA.png) - [ ] ![image](https://hackmd.io/_uploads/r11MK6zAA.png) ::: 3. 符合題意,撰寫 payload 的正確順序為何? 4. 如果你已經下載好 pwntools ,嘗試將本題目 run 在你的 vm 上,查看是否可以成功獲取 **is1abPWN{}** 。 5. 祝你好運! ### ret2text multiple #### 題目敘述 > - 如何從 ROP Chain 中連續 call functions 並且不會造成 crash? > - 先不用逆向去看執行檔,直接把重點跟你說! > - 必須按該順序呼叫 callme_one()、callme_two()和callme_three()函數。 > - 且每個函數都需要帶參數 0xdeadbeef, 0xcafebabe,0xd00df00d。 > 例如,在 x86_64 的範例是 callme_one(0xdeadbeefdeadbeef, 0xcafebabecafebabe, 0xd00df00dd00df00d)。 #### Payload 填空 - **更改 ? 的內容**,以符合正確的 ROP Chain Payload。 - 需自行建立一個新檔案寫入 payload,並與 Lab 執行檔放在同個資料夾下。 ``` python from pwn import * p = process("./callme") context.arch = 'amd64' para_1 = p64(0xdeadbeefdeadbeef) para_2 = p64(0xcafebabecafebabe) para_3 = p64(0xd00df00dd00df00d) usefulGadgets = p64(?) callme_one = p64(0x400720) callme_two = p64(0x400740) callme_three = p64(0x4006f0) gadget_ret = p64(0x4006be) # target_parameters parameters = ? parameters += para_1 parameters += para_2 parameters += para_3 # 32-bytes padding buffer + 8-bytes rbp payload = b'a'*40 payload += ? payload += ? payload += ? payload += ? payload += ? payload += ? payload += ? p.recvuntil(b'> ') p.sendline(payload) p.interactive() ``` #### 題目參考資訊 - ghidra - ![image](https://hackmd.io/_uploads/SydIqnGCC.png) ``` $ checksec ``` ![image](https://hackmd.io/_uploads/rJzfi2fRR.png) ``` $ objdump ``` ![image](https://hackmd.io/_uploads/r1Fks2MAA.png) ``` $ create pattern 0x30 $ pattern search 0x6161616161616165 ``` ![image](https://hackmd.io/_uploads/rJ1rw3zRC.png) #### 問與答 1. X64 calling convention 下,**前三個傳遞參數的 register** 為何? 2. 以此挑選合適的 gadgets。 :::spoiler 你要的是哪一個 gadget? - [x] ![image](https://hackmd.io/_uploads/HyaRv2fCA.png) - [ ] ![image](https://hackmd.io/_uploads/SJ8WOhzAR.png) - [ ] ![image](https://hackmd.io/_uploads/rk6zu3zCC.png) ::: 4. 符合題意,撰寫 payload 的正確順序為何? 5. 如果你已經下載好 pwntools ,嘗試將本題目 run 在你的 vm 上,查看是否可以成功獲取 **ROPE{}** 。 6. 祝你好運! ## 關於 ROP 的緩解方法 ### 破解迷思之 ~~ASLR 可以阻擋 ROP 技巧~~ - 在開啟 ASLR 保護機制的情況下,並非所有位址都是隨機的。**如果同時有關閉 PIE ,.text address 是固定的,可以利用。** - RX 權限: 即使能夠執行的只有 `.text 區域`,仍然可以從有限的程式片段中,找到並拼湊適合的 gadgets。 - **但是,如果從 .text 區域真的沒有想要用的 gadgets 呢?** - 知道目標環境的 libc 版本,可以透過 leak 出 `libc 的位址`,使用 libc 中的程式片段建構 ROP。 ### 注意使用者可輸入的 Buffer 大小 - **基礎 ROP 的攻擊手法:** 主要是使用 buffer overflow,達到控制程式流程 (控制 rip )。 - **Stack Canaries:** 如果在開啟 NX & ASLR 的狀況下,增加 canary 保護機制,則無法輕易覆蓋 `return address` 上的值來製作 ROP ,以此增加攻擊手法的困難性。 ## 參考資料 【Stack Overflow】重要概念!!! - ret2text - ret2syscall - ret2plt - ret2libc - GOT表洩漏 [Day 28 - Pwn 0x2](https://ithelp.ithome.com.tw/m/articles/10252772) ( stack overflow 的相關介紹) [[Day8] Stack 攻擊手法 - ROP:靜態連結](https://ithelp.ithome.com.tw/articles/10356195) ( 從程式碼分析了解 ROP ,很新很詳細的文章 ) [ROP Chaining: Return Oriented Programming](https://www.ired.team/offensive-security/code-injection-process-injection/binary-exploitation/rop-chaining-return-oriented-programming#id-2nd-rop-chain) ( PPT 裡長得偏嚇人的流程圖出處 ) [PWN|入門 - 保護機制 (share) - 許貽昇](https://butternut-dinghy-bc9.notion.site/PWN-share-9d1bca4f1ec7432ea7d924f502dd658f) ( 關於 No eXecute-NX ) [PWN|入門 - x86/x64 Calling Convention (share) - 許貽昇](https://butternut-dinghy-bc9.notion.site/PWN-x86-x64-Calling-Convention-share-2a561c309e2e474e93a0f324fba9f9c0) ( 對,就是 calling convention ) [PWN|基礎 攻擊手法 1 (share) - 許貽昇](https://butternut-dinghy-bc9.notion.site/PWN-1-share-dd36626684024e4b85fc4118bd77f1d7) ( 簡單 ROP 說明 ) ------------------------------------------ 【ROP Emporium】Lab!!!! [ROP Emporium](https://ropemporium.com/index.html) ( Lab 練習題來源 ) [栈溢出练习:ROP Emporium](https://www.kn0sky.com/?p=938527f1-03c4-4349-8110-5510f7d4b84a) ( writeup 參考 ) ------------------------------------------ 【大神的 Slides】 [ROP輕鬆談 - Lays(L4ys)](https://www.slideshare.net/slideshow/rop-40525248/40525248#45) [Linux Binary Exploitation - Angelboy](https://www.slideshare.net/slideshow/binary-exploitation-ais3/79271260#106) ------------------------------------------ 【ELF 檔案】仙貝知識!!! [執行檔格式 - ELF](https://ithelp.ithome.com.tw/articles/10222650)