[IT-Security-2] 記憶體相關之漏洞 Buffer Overflows and other Memory Corruptions
Notes from RWTH Aachen University course
“IT security 2” Wintersemester 2019/20
professor: Meyer, Ulrike Michaela
Buffer Overflow
- 定義
- A condition at an interface under which more input can be placed into a buffer than the capacity allocated for it, overwriting other information. Attackers exploit such a condition to crash a system or to insert specially crafted code that allows them to gain control of the system.
- C語言
- 預設programmer要負責data integrity
- compiler不做integrity檢查
- 可能造成超過memory space的capacity
buffer會overwriting接下來的資料- 多數情況會crash program
- ping of death
- 基本buffer overflow
- Variable corruption
- 利用過長的input data複寫其他data
- Corruption of program control addresses
- 以更改程式執行順序
- 攻擊者必須:
- identify overflow vulnerability
- buffer要存什麼資料
- 要怎麼corrupt memory allocation
- Variable corruption
Executable Program Segments
Dynamic | Stack segment |
Heap segment | |
Static | Bss segment |
Data segment | |
Text segment |
Text segment
- code,儲存machine language instructions
- nonlinear執行
- 當程式執行時,Extended Instruction Pointer (EIP) 設為text segment的第一個instruction
- 讀取指向的instruction
- Adds the byte length of the instruction to EIP
增加instruction的byte長度給EIP - 執行instruction
- 回到步驟1
- 不允許write (不允許修改code)
Data segment
- 初始化過的global和static變數
- writable
- fixed size
Bss segment
- 非初始化過的counter
- writable
- fixed size
Heap segment
- programmer 可以直接控制的memory片段
- 被allocator和deallocator algorithm控制
- reserve region of memory
- release reservation
Stack segment
在 function calls 暫時儲存的空間
stack frame儲存
- 輸入變數 (passed variables)
- 2 pointers:
- Saved frame pointer (SFP):
恢復Extended stack pointer,指向stack的尾端 - return address (RET):
恢復EIP,指向下個instruction
- Saved frame pointer (SFP):
- 區域變數 (local variable)
在每個function call時產生
Stack Example
void test_function(int a, int b, int c, int d) { int flag; char buffer[10]; flag = 31337; buffer[0] = 'A'; } int main(){ test_function(1,2,3,4); }Stack d c b a RET SFP flag buffer
Memory exploits
- Buffer 是指memory中的data storage area (stack or heap)
- 若 executable code 被當作 data 提供,使用者可能被騙執行
- pointer assignment
- format strings
- memory allocation/ de-allocation
- function pointers
- calls to library routines via offset tables
- 若buffer塞了過多東西
- 原:void func(char *str){ char buf[126]; strcpy(buf, str); }
- Overflow:
複寫鄰近的stack區塊複寫的區域會被認為是 return address
- 攻擊者利用此 return address 執行自己的input
eg.execve("/bin/sh")
- 則攻擊者可以得到 shell
若victim program是setuid root
則可得到 root shell
- 原:
Different ways of executing attack code
Attack
- 使return address改成指向attack code
- return-to-libc: 用現有的instructions
eg.system()
,exec()
- stack理論上只能存data但攻擊者存了executable code
- buffer的RET必有correct address of attack code
- 否則程式會crash
- 攻擊者要正確猜到在buffer的哪個位置
Shell Code
- buffer overflow攻擊的最重要的部分
- transfer of execution to code
- 因shell code用來執行user command-line interpreter
- Unix:
execve("/bin/sh")
- Windows:
system("command.exe")
- 通常針對不同的OS攻擊,因為指令不一樣
- buffer overflow需要
- 避免library calls(
execve()
) - position independent, 只有相對位址
- 不能有NULL,否則會被視為string的結尾
- 避免library calls(
Format string in C
- 沒有check input size
strcpy
strcat
gets
scanf
printf
- Range checking:
strncpy
只有最多n
個字被複製strncat
首n
個*src
才能被複製到*dest
中- 可能的overflow:
strcpy(record, user); strcat(record,":"); strcat(record, cpw);
- “fix”:
strncpy(record, user, MAX_STRING_LEN-1); strcat(record,":"); strncat(record, cpw, MAX_STRING_LEN-1);
record = record||":"||cpw
問題: 只有MAX_STRING_LEN-1
長度的record被allocated
Attack
- 修改function pointer指向attack code
- 任何memory可以被此儲存值進pointer的statement修改
Off-by-one Overflow
for (i=0; i<=512; i++)
會copy 513個字元不能change RET,但可能change SFP to前一個stack frame
Attack
- Overflow Frame Pointer 以取代 stack frame
- 修改原本的 frame pointer 成 attacker-controlled memory
- 可以用 off-by-one overflow 達成
- 但attacker必須猜到fake frame的address
Heap Overflow
- 可能修改 function pointer 指向重要的資料
- illegitimate privilege elevation: 若 program 有 root 權限,則攻擊者可以存取權限較高的檔案
- Heap:
Buf[256] | vtable | … | ptr |
---|
- 若
Buf
overflow,則會蓋住vtable
ptr
指向的vtable
的位址會變成overflow的data (eg. shell code)
- Heap Spraying
- 用 Javascript 和 shellcode spray heap
- 並在spray area任意地方指向vtable pointer
- 指向任意在heap中的 function pointer 會執行shellcode
Dynamic Memory Management in C
malloc(size_t n)
- 分配
n
bytes 並回傳一個指標 - memory不是乾淨的
- 分配
free(void *p)
- 釋放
p
指標指向的memory space
- 釋放
- 錯誤:
- Initialization errors
- Failing to check return values
- writing to already freed memory
- freeing the same memory more than once
- improperly paired memory management functions (eg.
malloc
/delete
) - Failure to distinguish scalars and arrays
- improper use of allocation functions
all result in exploitable vulnerabilities
Variable Arguments in C
printf
可以有可變的輸入數量printf("hello, world");
printf("length of '%s' = %d", str, str.length());
- 在執行時多了變數
va_start
,va_arg
,va_end
- Format Strings
- 正確的:
printf("foo = %d", foo);
- Sloppy use:
char buf[123]="hello world; printf(buf);
(正確用法:printf("%s", buf);
)- 若buffer裡面有
%
,則原本的stack pointer會以為是argument - attacker可以用來移動stack pointer
- 若buffer裡面有
%n
: 印出的字元數量- 若
char buf[16] = "overflow this!%n"; printf(buf);
- stack pointer指向的位置會被譯為number of characters將要被寫入的位址
如
printf("overflow this!%n", &myVar);
%n
為將要被寫入的位址 RET
會指向attack code
,printf(buffer)
會寫入attackString
的number of characters 到RET
中C 有一簡單的方式print出多個 symbols:
%Mx
會print出剛好M
bytes
若attackString
有足夠多的%Mx
,長度等於attack code的address的most significant byte,則此byte會被寫入&RET
中
再執行3次&RET+1
,&RET+2
,&RET+3
會得到所有attack code的address
把RET
複寫為attack code的address
- 正確的:
Preventing Buffer Overflows
- 分為兩類
- Compile time:
- 選擇不允許buffer overflow的high level programming language
- 有些library仍vulnerable
- 無法直接取得hardware resources
- safe coding
- safe libraries
- additional code to detect(eg. stackGuard)
- 選擇不允許buffer overflow的high level programming language
- Compile time:
- StackGuard
- 在stack frame加入一個 Canary ,在function return前檢查 Integrity
若buf Canary SFP RET buf
overflow 的話會改變 Canary- 兩種 canary:
- Random number
- termination symbol:
\0
,EOF
就不會被strcpy
就不會繼續copy
- 需要code recompilation
- 每個function都要檢查會降低performance
- 放在
buf
和pointer
旁邊更降低performance - 可以被攻擊
- 攻擊StackGuard
- 用
strcpy
複寫pointer,指向RET strcpy
可以複寫而且避開 Canary
- 用
- LibSafe
- 動態載入的library
- 攔截calls eg.
strcpy
- 檢查現在的stack frame有沒有足夠的空間
|frame-pointer – dest| > strlen(src)
- PointGuard
- attack: overflow a function pointer以指向attack code
- 在memory中 Encrypt all pointers
- 執行時產生一 random key
- XOR each pointer
- 攻擊者不能預測
- 即使此key被攻擊者複寫,XOR 後此key會被 dereference to a random address
根據被攻擊過的key decrypt過後,會指向一random address
因為修改的key不會是attack code address本身 - Run-time:
- attack: 利用 Code Injectoin
- data的部分被植入executable code
- 目標:使 stack 和其他 data area Non-executable
- 變成OS中的standard
- 但攻擊者用更精巧的方式攻擊
- attack: 利用 Code Injectoin
- Write not Execute 無法避免:
- 只要 Saved EIP 指向已存在的code
此保障就無法阻止control transfer - return-to-libc 的攻擊基礎
- 複寫 Saved EIP 指向某 library routine
- 編排 stack 看起來像 routine 的 argument
- 只要 Saved EIP 指向已存在的code
- ASLR Address Space Randomization
- attacker原本要預測targeted buffer的location
預測 return address - 目標:隨機擺放stack location使得預測困難
- 隨機擺放standard library routines
- 用
malloc
跟把standard library routines放在heap
留言
張貼留言