Day13-How to change libc & ret2libc

前言 昨天介紹了 ROP,當程式使用靜態鏈結時,我們可以利用更多 gadgets 組合出 ROP chain。那麼,當程式為動態鏈結時,還有其他方法能夠取得 shell 嗎?其實有一種方法與 libc.so 有關,這種技術被稱作 ret2libc。 How to change libc 首先,由於每個人的環境和遠端環境可能不同,因此操作系統與 libc 版本也不盡相同。我們會希望在本地測試的程式與遠端題目盡量一致,所以我們通常會更換 libc 和動態鏈結器。以往題目不常附帶 libc,這時可能需要自己從 libc database 等網站找資料。然而,有些題目(像筆者的 lab)會提供包含題目完整環境的 Dockerfile。我們可以按照以下步驟將題目環境架設起來: 執行 docker-compose up -d 執行 docker ps 並記下容器的 ID 使用 docker exec -it [ID] /bin/bash 進入容器 使用 ldd 確認 libc 路徑與檔名 使用 docker cp [ID]:[檔案路徑] . 將檔案從容器中複製到本地 使用 ls -al 會發現 ld-linux-x86-64.so.2 其實是連結到另一個檔案,因此需要再多複製一次 接下來,我們需要使用 patchelf 來修改 ELF 檔案。下載 patchelf 後,執行以下命令進行 patch: ...

2024-09-27 · 4 min · 794 words · YJK

Day12-Basic ROP

Lab 網址 前言 昨天的 shellcode 是在記憶體區段有執行與寫入權限的情況下才可以執行,那如果程式啟用了 NX 保護,且沒有任何變數的記憶體區段有執行權限呢?這就要提到今天的內容:ROP (Return Oriented Programming)。 static or dynamic linking 觀察以下程式碼,並使用底下的編譯參數分別編譯: 1#include<stdio.h> 2int main(){ 3 printf("Hello World!\n"); 4 return 0; 5} 1gcc test.c -static -o static 2gcc test.c -o dynamic 透過各種資訊查看兩者差異,這裡使用 ls、file 和 ASM 的方式比較。 ls -al static dynamic 可以發現 static 檔案的大小明顯大上許多。 file static dynamic 可以看到一個是 static linking,另一個是 dynamic linking。 ...

2024-09-26 · 3 min · 545 words · YJK

Day11-Shellcode

前言 從今天開始,內容會變得更加困難。之前的題目可能有留一個後門函式,讓你可以直接開啟 shell,或是使用 system 函式來方便後續的操作。然而,現實中基本不會有這種情況,所以我們需要學習更多漏洞利用的方法,才能更符合實際的需求。 Shellcode 根據之前提到的編譯過程,經過簡化後,最終會變成下圖所示的形式: 簡單來說,最後真正執行的部分是機器碼,而這正是本章節要教授的內容:Shellcode。之所以稱為 Shellcode,是因為我們透過編寫 Assembly 程式碼,將參數寫入指定的位置,並最終呼叫 syscall,來達成我們的目標,例如開啟 shell 或讀取特定檔案。 Syscall syscall 即為 System Call,是用來與 Kernel 進行溝通的呼叫。在 CTF 中,常見的有以下兩種: execve("/bin/sh", NULL, NULL) open、read、write 這些可以分別用來啟動 shell 或進行任意的檔案讀寫。這個網站可以幫助查詢呼叫各種 syscall 時應該將各個暫存器設置為什麼值,這與前面提到的 Calling Convention 是相關的。 如何編寫 Shellcode? 編寫 Shellcode 有幾種方法,以下是幾個選項: 自己寫 Assembly,並透過 pwntools 進行轉換。 從 shellcode database 中找到需要的 Shellcode。 使用 pwntools 中的 shellcraft,記得指定 context.arch。 Lab 查看以下程式原始碼: 1#include<stdio.h> 2#include <unistd.h> 3#include <sys/mman.h> 4char shellcode[0x100]; 5int main(){ 6 setvbuf(stdout, 0, _IONBF, 0); 7 setvbuf(stdin, 0, _IONBF, 0); 8 setvbuf(stderr, 0, _IONBF, 0); 9 unsigned long addr = (unsigned long)&shellcode & ~0xfff; 10 mprotect((void *)addr, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE); 11 printf("Give me shellcode: "); 12 read(0, shellcode, 0x100); 13 printf("Overflow me: "); 14 char buffer[0x10]; 15 gets(buffer); 16 printf("Bye!\n"); 17 return 0; 18} 使用以下指令進行編譯: ...

2024-09-25 · 2 min · 257 words · YJK

Day10-GOT Hijacking

前言 前一天我們介紹了 GOT 和 Lazy Binding 的機制,今天要介紹的是如何利用這些機制進行攻擊,也就是 GOT Hijacking。 簡介 由於 Lazy Binding 的機制,GOT 是可寫的。因此,如果能夠覆蓋 GOT 的值,那麼下次呼叫該函數時,就可以控制即將執行的函數指針。這種情況通常出現在陣列未驗證輸入範圍、記憶體越界(即所謂的 out of bounds,oob)或是透過格式化字串(format string)將特定值寫入 GOT 的情況。 Lab 1#include<stdio.h> 2#include<stdlib.h> 3 4int backdoor(const char *arg){ 5 system("/bin/sh"); 6} 7 8long long value[4]; 9 10int main(){ 11 setvbuf(stdin, 0, 2, 0); 12 setvbuf(stdout, 0, 2, 0); 13 setvbuf(stderr, 0, 2, 0); 14 long long index; 15 for(int i = 0; i < 4; i++){ 16 puts("Enter a index to store a value: "); 17 scanf("%lld", &index); 18 puts("Enter a value: "); 19 scanf("%lld", &value[index]); 20 } 21 if(value[0] != 123){ 22 puts("CHECK FAILED\n"); 23 exit(0); 24 } 25 if(value[1] != 456){ 26 puts("CHECK FAILED\n"); 27 exit(0); 28 } 29 if(value[2] != 789){ 30 puts("CHECK FAILED\n"); 31 exit(0); 32 } 33 if(value[3] != 101112){ 34 puts("CHECK FAILED\n"); 35 exit(0); 36 } 37 puts("CHECK PASSED\n"); 38 return 0; 39} 使用以下指令進行編譯(注意,預設編譯會是 Partial RELRO): ...

2024-09-24 · 2 min · 243 words · YJK

Day9-Lazy binding & GOT

簡介 如果大家經常使用 file 指令來查看檔案資訊,應該會經常看到像下面這樣的一大串訊息: 你會注意到其中有一個資訊是 dynamically linked,這表示這是一個動態鏈結的程式。動態鏈結意味著程式在執行時,會從外部函式庫載入一些函式,例如常見的 printf、scanf 等。 Lazy Binding Lazy binding 是動態鏈結程式的一種機制。當程式包含一個或多個函式庫時,不一定會使用到所有的函式。換句話說,有些函式庫中的函式可能永遠不會被執行。 Lazy binding 的機制是在程式首次呼叫某個函式時,系統才會查找該函式的位置,並將其填入 GOT 表(Global Offset Table)。後續的呼叫則會直接從 GOT 表中取得函式的位址。那什麼是 GOT 表呢? GOT 前面提到,函式庫中的函式位址是在載入時才決定的,因此在編譯階段無法得知這些函式的具體位址。GOT 表儲存了這些函式的指標,而程式在一開始執行時,並不會直接存取 GOT 表,而是先透過 PLT 表(Procedure Linkage Table)中的 offset。 例如,在下方的反編譯程式碼中,我們看到在 main 函式中呼叫了 printf@plt,而 printf@plt 最終會跳轉到 printf@GLIBC_2.2.5,也就是實際在 libc 中的 printf 函式。 攻擊? 大家可能會認為,這樣通過外部函式呼叫應該不會有什麼問題。但仔細想一想,事情或許並非如此。如果 PLT 表或 GOT 表可以被修改或重寫,那這樣的機制就不再安全了。 例如,將 printf 函式的指標改寫成 system 或者後門函式,甚至控制傳入的參數,這樣的情境可能會導致嚴重的安全漏洞。而這部分的內容將會在明天探討,也就是 GOT Hijacking 的攻擊技術。

2024-09-23 · 1 min · 60 words · YJK

Day8-format string bug

What is a Format String? 在 C 語言中,printf 和 scanf 是兩個常用的函式,它們透過格式化字串來處理參數。例如: scanf("%s", s); printf("Hello, %s\n", s); 這兩個例子會讀取格式化字串,並將 %s 解析後替換為傳入的參數。 Format String Vulnerability 如果在撰寫程式時未遵循安全方式,例如使用 printf(buf) 直接傳入變數而非格式化字串,這樣的漏洞可能會導致我們可以洩漏變數或 stack 的殘值。因此,有機會取得如 PIE base、libc base 和 canary 的值,甚至可能修改任意變數或記憶體中的值。如果能成功修改記憶體的值,便能改變程式的執行流程,例如往後會提到的 GOT Hijacking 攻擊。 Format String 格式 格式 %[parameter][flags][field width][.precision][length]type Parameter 可忽略 n$ 表示顯示第 n 個參數 printf("%3$d %2$d %1$d\n", 1, 2, 3); 輸出結果為 3 2 1 Type d/i、u:整數 x/X:十六進位 o:八進位 c、s:字元、字串 p:指標 n:可寫入變數 寫入資料 printf("Hello%n\n", &a); 此時 a=5,因為 Hello 字串佔了 5 個字元 Lab 本章節沒有提供 Lab,但接下來的內容會將此主題應用於實際的 Lab 中,例如 leak 可以繞過各種保護機制的資訊或更改任意記憶體的值。大家可以期待之後的實作內容。 ...

2024-09-22 · 1 min · 91 words · YJK

Day7-ret2code (ret2func)

Lab 網址 前言 經過了前一天的 lab,相信大家對於 buffer overflow 的原理已經有了更多的理解。既然我們能覆蓋判斷式中的值,那麼是否也能覆蓋 return address,讓程式跳到其他位置呢?這正是我們今天要介紹的攻擊技術:ret2code,又稱為 ret2func 或 ret2win。 介紹 回顧之前的 stack 內容,當使用 gets 讀取 buf 字串時,可以持續覆蓋記憶體,甚至可能覆蓋到 rbp 和 return address 例如,如果我們想跳到名為 shell 或 win 的函數,可以嘗試將 stack 覆蓋成如圖所示的狀態。當程式執行到 return address 時,它就會跳轉到我們覆蓋的位置。 雖然在現實情況下,程式中不太可能直接有開啟 shell 的 function,但在一些初學者的 CTF 題目中,這類控制程式執行流程(control flow)的題目仍然存在。在進入實作之前,我們要了解這種攻擊的前提條件是:需要關閉 PIE 保護,因為我們必須知道確切要跳轉的 function 位置。 Lab 查看以下程式原始碼: 1#include<stdio.h> 2 3void shell(){ 4 system("/bin/sh"); 5} 6 7int main(){ 8 setvbuf(stdout, 0, 2, 0); 9 setvbuf(stdin, 0, 2, 0); 10 setvbuf(stderr, 0, 2, 0); 11 char b[10]; 12 puts("Send me a message: "); 13 gets(b); 14 return 0; 15} 使用以下指令進行編譯: ...

2024-09-21 · 2 min · 386 words · YJK

Day6-Basic buffer overflow

Lab 網址 前言 經歷了前面的許多基礎知識與工具介紹,終於來到了第一個漏洞與第一個 lab。而這個漏洞可以說是最簡單也最基本的,就是 Buffer Overflow。 介紹 首先,先來看一個簡單例子。假如一個程式宣告了一些變數及字串,記憶體中的狀態可能會是下圖的樣子: 如果對 buf 字串輸入正常大小的資料,例如這邊宣告的空間是 0x10(16 bytes),輸入 0x10 個 ‘A’,記憶體狀態可能會像下圖這樣: 然而,當使用一些不安全的函式來輸入數據時,例如 gets 函式,可能會產生問題。因為 gets 不會檢查輸入的長度,因此可能會覆蓋到 buf 後面的變數,甚至是 rbp 或 return address。以下例子顯示了覆蓋到後面變數 num3 和 num4 的情況: 如果對填入的值進行精確的編排,則可能成為如下所示的情況: 這就是最基本的 Buffer Overflow 例子。 Lab 查看以下程式原始碼 1#include<stdio.h> 2int main(){ 3 setvbuf(stdout, 0, 2, 0); 4 setvbuf(stdin, 0, 2, 0); 5 setvbuf(stderr, 0, 2, 0); 6 int a = 10; 7 printf("Please input your name: "); 8 char b[10]; 9 gets(b); 10 if(a == 0xdeadbeef){ 11 system("/bin/sh"); 12 } 13 printf("Hello, %s\n", b); 14 return 0; 15} 使用以下指令進行編譯 ...

2024-09-20 · 1 min · 213 words · YJK

Day5-How to use GDB

簡介 GDB 是 GNU Debugger 的縮寫,它是一個功能強大的 command line debug 工具,支援多種程式語言如 C、C++、Fortran 等等。當我們在進行開發時,如果程式在執行過程中發生 segmentation fault 或其他錯誤,GDB 可以幫助我們追蹤程式 crash 的原因。我們可以透過設置中斷點、檢查變數內容等,來針對特定問題進行 debug 改造? 原生的 GDB 有時候可能顯得過於簡單,缺少一些便利的視覺化工具或記憶體分析功能。因此,許多使用者會安裝外掛來補強 GDB 的功能,像是 pwndbg 或 peda 等外掛,可以讓我們更容易地看到 stack、register 等資訊,從而提高 debug 效率 使用 執行程式並設定中斷點: 在 GDB 中,我們可以使用 run 或 r 來執行程式,通常會先設定中斷點(break)在程式的某一個位置,例如 main 函式,這樣程式會在到達該點時停止執行,方便我們進行檢查。 ex: b main 在 main 函式處設置中斷點。 踩到中斷點後要繼續執行程式: 當程式停止於中斷點時,使用 continue 或 c 來繼續執行程式。 觀察 register: 當程式在中斷點停止後,我們可以使用 info 指令查看目前的 register 狀態、函式列表等資訊。例如,使用 info registers 來查看目前的 register 內容。 使用 x 指令可以檢查具體的記憶體位址,通過格式化選項來調整輸出,例如 x/2gx $rax 顯示從寄存器 rax 開始的兩個 giant word。 反組譯執行的程式: ...

2024-09-19 · 2 min · 226 words · YJK

Day4-pwntools & useful tools

前言 這篇文章整理了筆者在練習 CTF 題目時常用的工具,有些工具在後續也會頻繁使用。另外,如果你有興趣一起跟著文章進行練習,可以使用文中提供的 Docker 環境,裡面已經包含了後續教學中會使用到的工具,此 repo 包含後面的題目及環境 環境 Dockerfile F M R R R R R R R R R R R R R R R R U R R R R R R R R R R R R R R U # E E C R A U U U U U U U U U U U U U U U U S U U U U U U U U U U U U U U S X N M O I N N N N N N N N N N N N N N N N E N N N N N N N N N N N N N N E r P T D M N R R u O R T a y a a a a a a a p g g m e s e g c g c r e e e e e e e e e n S Y [ u A p e p p p p p p p i e e k c e c r i d i p m c c c c c c c c c r E P " b I t s t t t t t t t p m m d h d h o t t h h h h h h h h h o t O / u N - - - - - - - - 3 i o o o ~ ~ - o o o o o o o o o o h 2 I u n E g | g g g g g g g i i r - t c / c / r t e 2 N s t R e e e e e e e e i n n ' i ' l p l P f " " " " " " " " " T r u t u t t t t t t t n s s P % o w o w s s s d p i a e e s / : Y n s t t v e ' s n n n n ~ o o e y m n n n e [ s 2 J u m i i i i i i i t a a a r s u e d e g u u u f t p g d d r " b 2 K p i n n n n n n n a l l r m / d b d . r r r i h o e " " v / i . d n s s s s s s s l l l / i n o h g h b g c c c n o r l i u n 0 a i t t t t t t t l r t u t t / d e e e e n t h c s / 4 t m a a a a a a a s o u E l A t & t . b " e e r s e i l l l l l l l p e n n m l L p & p g i ~ ~ ~ h a a / s z l l l l l l l w c e / p o L s s d n / / / o n p ~ ~ b h e n c _ s t k = : : b i p P P o g . / i d - - - - - - - t o g s y _ ( / i t w w w k e i . . n " y y y y y y y o m a h P s A s / n n n n - ~ l n g g / , o p d d a e L g e g i d g g r / h i d d t t o g g l c r l - g s c L i t i t b d d u . e t b b i " i p c c i u u s t e s u ) t u t g b b n g a _ i i n - n e c c b r b o t w r h p h ~ / / / " d p a n n i D i n - c l y c o o e N u . u / g p a b " n i i " " s g m 6 - a l r / O b s b d w n i g t t , ] i s d u - g d p s d n P . h . b n g n e p h b l d i e s s u A c c i g e i l " r - t b t v t l S o o n d l ~ t h - o s m i g o y l S m m i b h / ~ e - u e a l z w n e o W / / t . e . / a " t r k i d s g e s k D p s . p a g . p ] e v e b p h e ' / : w c p y p d g ( 2 e k t f ' A n w y " / b d ) r y g g i L d u " g i b " i a + - l / L b a d n i p s s + d e e ' g p b i n u u m - e b / t / t i t i t d m v y e c p x ~ n t i o n u t t / w / ~ i ~ l a l e c p n P . t / s v s t s / a / d w . g . . - i m i s m e b n g d p g p m l k s . t g g d b y d i t i e h d c d b i " b n g c b y / / / ~ b i n i g r p s s c s / . n i n e d t s o u p g i t i n p u o h m d w i t t e m n d m o n t ~ t g p e _ o e d / - a - c n r b ~ . t w p e o - s g / g o k y n n a P d o t g f u w b l r h i i t n i s s o n g h g n y n e d i n n 3 b t e c r t p o c t y p a m t p t u h e x o r n d 3 i - f p f i u p t i p l y s t h f o i n l 3 e - v i r t u a l e n v docker-compose.yml ...

2024-09-18 · 7 min · 1455 words · YJK