Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Master of ROP:PWN Advanced
Search
YJK
June 13, 2025
0
2
Master of ROP:PWN Advanced
YJK
June 13, 2025
Tweet
Share
More Decks by YJK
See All by YJK
From 0 to Shell PWN Basic
yjk0805
0
2
Basic Reverse-逆要做什麼@THUHC
yjk0805
0
11
Reproducing Vulnerability in IoT@HackerSir StudyGroup
yjk0805
0
21
你 PWN 不動我@HackerSir 10th
yjk0805
0
8
Reverse 0x1@HackerSir 10th
yjk0805
0
9
Reverse 0x2@HackerSir 10th
yjk0805
0
8
不要亂 PWN 我@HackerSir 10th
yjk0805
0
11
Assembly@HackerSir 10th
yjk0805
0
9
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
YesSQL, Process and Tooling at Scale
rocio
172
14k
Statistics for Hackers
jakevdp
799
220k
Stop Working from a Prison Cell
hatefulcrawdad
269
20k
RailsConf 2023
tenderlove
30
1.1k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
657
60k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
7
640
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
106
19k
Bash Introduction
62gerente
614
210k
Automating Front-end Workflow
addyosmani
1370
200k
Building Better People: How to give real-time feedback that sticks.
wjessup
368
19k
Transcript
Master of ROP:PWN Advanced YJK @ HackerSir
Whoami • YJK • 逢甲大學黑客社學術部長 • AIS3 Junior 2024 助教
• MyFirstCTF 2024 銅質獎 • 2022 & 2023 T 貓盃資安基礎實務能力競賽 佳作 • ICPC 2023 Taoyuan Regional High Honors • Pwn & Reverse & IoT Security & 演算法
Environment • ubuntu:22.04 • 可以自己架環境 • 內含 pwndbg、pwngdb、pwntools、常用工具... • environment
01 03 02 ROP ret2libc ret2plt Outline 04 Stack Pivoting
ROP 01 Basic ROP concept、static linked ROP
Demo • 編譯選項 ◦ gcc test.c -o dynamic ◦ gcc
test.c -o static -static
Demo • 編譯選項 ◦ gcc test.c -o dynamic ◦ gcc
test.c -o static -static • 觀察一下 ◦ file ◦ ls ◦ objdump ◦ gdb
file
ls
ASM
差異 • static 很大,dynamic 很小 • static linking 會將所有程式碼包進去 ◦
call 到任何外部 function 都會包進去 ▪ scanf、printf… • 浪費空間
ASM
Dynamic Linking • 一個程式會呼叫許多 library function • libc.so • .so、.dll
• 上週提到的 plt、got 就是如此 • 需要使用時再呼叫 libc • 可以重複利用,不浪費空間
ROP • ROP (Return Oriented Programming) • 重複利用編譯的程式碼繞過 NX •
透過多段可以執行的 gadget 串出 rop chain • 控制執行流程
ROP Gadgets • 片段可執行的程式 • 通常結尾為 ret 或是 jump <addr>
• 較常利用 ◦ 可以控制 register ◦ 可以寫入資料 ◦ syscall • 如何找到 gadget ◦ ROPgadget Tool
Control Register • pop rax; ret pop rax 0x3b ret
Control Register • rax = 0x3b pop rax 0x3b ret
Control Register • 繼續串 gadget pop rax 0x3b ret
ROP 原理 • Overflow 前 old rbp Return address
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 ……
ROP 原理 • 0x419afc:pop rax ; ret AAAAAAAA 0x419afc (pop
rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
ROP 原理 • 0x419afc:pop rax ; ret • rax =
0x3b AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
ROP 原理 • 0x40a48d:pop rsi ; ret AAAAAAAA 0x419afc (pop
rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
ROP 原理 • 0x40a48d:pop rsi ; ret • rsi =
0 AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
ROP 原理 • 0x402020:pop rdi ; ret AAAAAAAA 0x419afc (pop
rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
ROP 原理 • 0x402020:pop rdi ; ret • rdi =
0 AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
ROP 原理 • 執行到最後 Register 會變成 • rax:0x3b • rsi:0
• rdi:0 AAAAAAAA 0x419afc (pop rax ; ret) 0x3b 0x40a48d (pop rsi ; ret) 0 0x402020 (pop rdi ; ret) 0 ……
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 ……
Practice • rop
Static ROP • static linking binary • 先將 ROP Gadget
全部找出來存到檔案 ◦ ROPgadget --binary <binary> > gadget • 利用 grep 找到想要的 gadget ◦ cat gadget | grep "pop rdi"
Static ROP • 常用 ◦ pop <reg>;ret 控制 register ◦
mov qword ptr [reg], reg ; ret; 寫入 memory ◦ syscall
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
整理 • execve 的 argv、envp 可以放 NULL • 用 mov
qword ptr [reg], reg ; ret; 寫 “/bin/sh” ◦ 用 gdb 開 vmmap 找可寫區域
整理 • execve 的 argv、envp 可以放 NULL • 用 mov
qword ptr [reg], reg ; ret; 寫 “/bin/sh” ◦ 用 gdb 開 vmmap 找可寫區域 • 用 pop <reg> ; ret ; 調整 register • 最後 syscall
整理 • syscall number = rax = 0x3b • rdi
= &"/bin/sh" (pointer to string "/bin/sh") • rsi = 0 • rdx = 0
solution • Static linked、No PIE • 無腦 ROPgadget 直接找 •
理論上絕對會有適合的 gadget 可以用
偷吃步 • 利用 ROPgadget 生成 ROP chain • ROPgadget --binary
<file> --ropchain • 有機會長出很白癡的 ROP chain
ret2libc 02 Use glibc function to ROP、one_gadget
Change libc • Remote、Local 環境可能不同 • libc 和 linker version
影響 offset 程度較大 • 盡量讓 Local、Remote 環境一致 ◦ 換 libc、linker • 過去的題目可能不會給 libc ◦ libc database
沒給 libc 有給 Dockerfile • 把題目架起來 ◦ docker-compose up -d
沒給 libc 有給 Dockerfile • 把題目架起來 ◦ docker-compose up -d
◦ docker exec -it [ID] /bin/bash 開 shell
沒給 libc 有給 Dockerfile • 把題目架起來 ◦ docker-compose up -d
◦ docker exec -it [ID] /bin/bash 開 shell ◦ ldd [執行檔] 查看 libc、ld 路徑 ◦ docker cp [ID]:[路徑] .
沒給 libc 有給 Dockerfile • 注意檔案有沒有 link 到其他地方
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] ./[執行檔]
確認狀態 • gdb ./[執行檔] • 跑起來看 vmmap 路徑、ldd 確認
return to libc • 透過 libc 裡面的 gadgets、現存 function •
execve("/bin/sh", argv, envp)? ◦ system("/bin/sh")
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
return to libc • 優點 ◦ 比手動做 syscall 簡單很多 ◦
gadgets 數量少很多 • 缺點 ◦ 有 ASLR -> 需要 leak libc base
Practice • ret2libc
solution • 可以隨意輸入、讀取任意 index 的內容 ◦ Out of bound (OOB)
read、write ◦ 可以 leak libc base 或各種資訊 ◦ gdb 看會是哪個 index 可能有所需內容 ◦ 不斷輸入不同 index 看有沒有 libc address ◦ 減去 offset • system("/bin/sh") • SIGSEGV????
One gadget • ret2libc 疊出 system("/bin/sh") 還是太長?
One gadget • rbp useless? No ◦ one gadget 和
stack pivoting 會用到 • 使 gadgets 的長度最短 • 只需控制 rbp 和 return address • one_gadget • david942j - 一發入魂 One Gadget RCE
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)
Usage • one_gadget ./libc.so.6
Practice • ret2libc_adv
solution • 可以 overflow 的部分空間變小,其餘相同 • 能 overflow 的部分只到 rbp
跟 return address ◦ oob to leak libc base ◦ 選好 rbp ◦ return address -> one_gadget
ret2plt 03 Use plt、got leak libc base and ROP
ret2plt • 沒有足夠的 gadgets 使用 • 無法 leak libc •
無解????
ret2plt • 看一下 write(1, "string", 7) pop rdi 0x1 pop
rsi ["string"] pop rdx 0x7 pop rax 0x1 syscall
ret2plt • 看一下 write(1, "string", 7) • puts("string") pop rdi
["string"] puts@plt
ret2plt • 看一下 write(1, "string", 7) • puts("string") • 都可以輸出字串
pop rdi ["string"] puts@plt
ret2plt • 看一下 write(1, "string", 7) • puts("string") • 都可以輸出字串
• system("/bin/sh") pop rdi ["/bin/sh"] system@plt
Practice • ret2plt
solution • 有 system@plt、gets • 沒有 Canary 和 PIE •
pop rdi、gets@plt 將 /bin/sh 寫到 BSS • 再用 pop rdi 將 BSS 的資料傳給 system@plt
plt to libc • GOT 如果解析完會有 library function address •
如果用 GOT 當參數傳給輸出 function (printf、puts) • puts(got_address) • 成功拿到某個 function 在 libc 的 address • 需要減掉 offset,才會是 base address
Practice • ret2plt_adv
solution • 有 read 的 overflow,可以 control flow • 動態鏈結
-> gadgets 不夠 -> 用 libc -> leak libc • 沒有 format string bug、OOB • 有 puts -> ret2plt leak libc
stack pivoting 04 A trick to control flow
stack pivoting • 沒有足夠的長度或方法 leak libc、堆 ROP chain • 沒辦法
PWN???
stack pivoting • 沒有足夠的長度或方法 leak libc、堆 ROP chain • 沒辦法
PWN??? • stack pivoting (Stack Migration)
stack pivoting • 分次將 ROP chain 寫在指定區域 • 將 stack
移過去執行 • Stack 由 rsp 控制 -> 控制 rsp ◦ leave ; ret ◦ leave -> mov rsp , rbp ; pop rbp ; ◦ ret -> pop rip; • 把 return address 蓋成 leave; ret;
Demo • rbp 是 0x7ffe65dea290、rsp 是 0x7ffe65dea280
Demo • rbp 是 0x7ffe65dea290、rsp 是 0x7ffe65dea280 • leave 後,rbp
換成 save rbp、rsp 變 rbp + 0x8
Demo • rbp 是 0x7ffe65dea290、rsp 是 0x7ffe65dea280 • leave 後,rbp
換成 save rbp、rsp 變 rbp + 0x8 • 再 leave 一次,rsp 就會再改變
Practice • stack_pivoting
solution • 有全域變數 name 可以寫入內容 • 有 message 可以輸入並存在 buffer
overflow • 編譯參數使用了 –static 有很多 gadgets • 不能直接透過 return address 堆 ROP • 將 ROP chain 寫在 name,利用 stack pivoting ROP
問題 • 如果沒有足夠空間可以堆 ROP 呢?
問題 • 如果沒有足夠空間可以堆 ROP 呢? • 只要有其中一塊可以堆 gadgets • 直接透過不斷的
stack pivoting 製造出來
Reference • NTU Computer Security Fall 2019 • NCKUCTF (成大資安社)
• frozenkp-Stack Migration
None