Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Master of ROP:PWN Advanced

Avatar for YJK YJK
June 13, 2025
2

Master of ROP:PWN Advanced

Avatar for YJK

YJK

June 13, 2025
Tweet

Transcript

  1. Whoami • YJK • 逢甲大學黑客社學術部長 • AIS3 Junior 2024 助教

    • MyFirstCTF 2024 銅質獎 • 2022 & 2023 T 貓盃資安基礎實務能力競賽 佳作 • ICPC 2023 Taoyuan Regional High Honors • Pwn & Reverse & IoT Security & 演算法
  2. Demo • 編譯選項 ◦ gcc test.c -o dynamic ◦ gcc

    test.c -o static -static • 觀察一下 ◦ file ◦ ls ◦ objdump ◦ gdb
  3. ls

  4. ASM

  5. 差異 • static 很大,dynamic 很小 • static linking 會將所有程式碼包進去 ◦

    call 到任何外部 function 都會包進去 ▪ scanf、printf… • 浪費空間
  6. ASM

  7. Dynamic Linking • 一個程式會呼叫許多 library function • libc.so • .so、.dll

    • 上週提到的 plt、got 就是如此 • 需要使用時再呼叫 libc • 可以重複利用,不浪費空間
  8. ROP • ROP (Return Oriented Programming) • 重複利用編譯的程式碼繞過 NX •

    透過多段可以執行的 gadget 串出 rop chain • 控制執行流程
  9. ROP Gadgets • 片段可執行的程式 • 通常結尾為 ret 或是 jump <addr>

    • 較常利用 ◦ 可以控制 register ◦ 可以寫入資料 ◦ syscall • 如何找到 gadget ◦ ROPgadget Tool
  10. ROP 原理 • Overflow 並串成右方後 • 0x419afc:pop rax ; ret

    • 0x40a48d:pop rsi ; ret • 0x402020:pop rdi ; ret AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  11. ROP 原理 • 0x419afc:pop rax ; ret AAAAAAAA 0x419afc (pop

    rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  12. ROP 原理 • 0x419afc:pop rax ; ret • rax =

    0x3b AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  13. ROP 原理 • 0x40a48d:pop rsi ; ret AAAAAAAA 0x419afc (pop

    rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  14. ROP 原理 • 0x40a48d:pop rsi ; ret • rsi =

    0 AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  15. ROP 原理 • 0x402020:pop rdi ; ret AAAAAAAA 0x419afc (pop

    rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  16. ROP 原理 • 0x402020:pop rdi ; ret • rdi =

    0 AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  17. ROP 原理 • 執行到最後 Register 會變成 • rax:0x3b • rsi:0

    • rdi:0 AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  18. ROP 原理 • 執行到最後 Register 會變成 • rax:0x3b • rsi:0

    • rdi:0 • 串成可以成功 ROP 的樣子 AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
  19. Static ROP • static linking binary • 先將 ROP Gadget

    全部找出來存到檔案 ◦ ROPgadget --binary <binary> > gadget • 利用 grep 找到想要的 gadget ◦ cat gadget | grep "pop rdi"
  20. Static ROP • 常用 ◦ pop <reg>;ret 控制 register ◦

    mov qword ptr [reg], reg ; ret; 寫入 memory ◦ syscall
  21. Static ROP • 目標:execve(“/bin/sh”, argv, envp) • Linux System Call

    Table NR Syscall references %rax arg0 (%rdi) arg1 (%rsi) arg2 (%rdx) 59 execve man/cs/ 0x3b const char *filename const char *const *argv const char *const *envp
  22. 整理 • execve 的 argv、envp 可以放 NULL • 用 mov

    qword ptr [reg], reg ; ret; 寫 “/bin/sh” ◦ 用 gdb 開 vmmap 找可寫區域
  23. 整理 • execve 的 argv、envp 可以放 NULL • 用 mov

    qword ptr [reg], reg ; ret; 寫 “/bin/sh” ◦ 用 gdb 開 vmmap 找可寫區域 • 用 pop <reg> ; ret ; 調整 register • 最後 syscall
  24. 整理 • syscall number = rax = 0x3b • rdi

    = &"/bin/sh" (pointer to string "/bin/sh") • rsi = 0 • rdx = 0
  25. solution • Static linked、No PIE • 無腦 ROPgadget 直接找 •

    理論上絕對會有適合的 gadget 可以用
  26. 偷吃步 • 利用 ROPgadget 生成 ROP chain • ROPgadget --binary

    <file> --ropchain • 有機會長出很白癡的 ROP chain
  27. Change libc • Remote、Local 環境可能不同 • libc 和 linker version

    影響 offset 程度較大 • 盡量讓 Local、Remote 環境一致 ◦ 換 libc、linker • 過去的題目可能不會給 libc ◦ libc database
  28. 沒給 libc 有給 Dockerfile • 把題目架起來 ◦ docker-compose up -d

    ◦ docker exec -it [ID] /bin/bash 開 shell ◦ ldd [執行檔] 查看 libc、ld 路徑 ◦ docker cp [ID]:[路徑] .
  29. patchelf • 可以自己編 Debug Symbol ◦ https://hackmd.io/@u1f383/S1CNu-1SO • 將 ld

    跟 libc patch 到執行檔 • dynamic linking 會 link 到指定 ld / libc • https://github.com/NixOS/patchelf • patchelf --replace-needed libc.so.6 ./[libc] --set-interpreter ./[ld] ./[執行檔]
  30. return to libc • 透過 libc 裡面的 gadgets、現存 function •

    execve("/bin/sh", argv, envp)? ◦ system("/bin/sh")
  31. return to libc • system("/bin/sh") ◦ pop rdi ; ret

    ◦ &"/bin/sh" (pointer to string "/bin/sh") ◦ system • &"/bin/sh"? ◦ 正好 libc 裡面也有 ◦ strings -a -t x <path to libc> | grep /bin/sh
  32. return to libc • 優點 ◦ 比手動做 syscall 簡單很多 ◦

    gadgets 數量少很多 • 缺點 ◦ 有 ASLR -> 需要 leak libc base
  33. solution • 可以隨意輸入、讀取任意 index 的內容 ◦ Out of bound (OOB)

    read、write ◦ 可以 leak libc base 或各種資訊 ◦ gdb 看會是哪個 index 可能有所需內容 ◦ 不斷輸入不同 index 看有沒有 libc address ◦ 減去 offset • system("/bin/sh") • SIGSEGV????
  34. One gadget • rbp useless? No ◦ one gadget 和

    stack pivoting 會用到 • 使 gadgets 的長度最短 • 只需控制 rbp 和 return address • one_gadget • david942j - 一發入魂 One Gadget RCE
  35. One gadget • libc 有呼叫 execve("/bin/sh", argv, envp) 片段 •

    可以開啟 shell • system(cmd) ◦ fork() + execve("/bin/sh", ["sh","-c",cmd], environ) ◦ 跳到 execve("/bin/sh", ["sh","-c",cmd], environ)
  36. solution • 可以 overflow 的部分空間變小,其餘相同 • 能 overflow 的部分只到 rbp

    跟 return address ◦ oob to leak libc base ◦ 選好 rbp ◦ return address -> one_gadget
  37. ret2plt • 看一下 write(1, "string", 7) pop rdi 0x1 pop

    rsi ["string"] pop rdx 0x7 pop rax 0x1 syscall
  38. solution • 有 system@plt、gets • 沒有 Canary 和 PIE •

    pop rdi、gets@plt 將 /bin/sh 寫到 BSS • 再用 pop rdi 將 BSS 的資料傳給 system@plt
  39. plt to libc • GOT 如果解析完會有 library function address •

    如果用 GOT 當參數傳給輸出 function (printf、puts) • puts(got_address) • 成功拿到某個 function 在 libc 的 address • 需要減掉 offset,才會是 base address
  40. solution • 有 read 的 overflow,可以 control flow • 動態鏈結

    -> gadgets 不夠 -> 用 libc -> leak libc • 沒有 format string bug、OOB • 有 puts -> ret2plt leak libc
  41. stack pivoting • 分次將 ROP chain 寫在指定區域 • 將 stack

    移過去執行 • Stack 由 rsp 控制 -> 控制 rsp ◦ leave ; ret ◦ leave -> mov rsp , rbp ; pop rbp ; ◦ ret -> pop rip; • 把 return address 蓋成 leave; ret;
  42. Demo • rbp 是 0x7ffe65dea290、rsp 是 0x7ffe65dea280 • leave 後,rbp

    換成 save rbp、rsp 變 rbp + 0x8 • 再 leave 一次,rsp 就會再改變
  43. solution • 有全域變數 name 可以寫入內容 • 有 message 可以輸入並存在 buffer

    overflow • 編譯參數使用了 –static 有很多 gadgets • 不能直接透過 return address 堆 ROP • 將 ROP chain 寫在 name,利用 stack pivoting ROP