Week1--漏洞學習
來源於天問之路知識星球的每日安全推送。
ASAN檢測不到的bugs
文章連結: https://nandynarwhals.org/bugs-asan-doesnt-detect/
這篇文章是關於三個能夠繞過ASAN檢測的bugs,之前我沒有接觸過ASAN,藉此瞭解一下。
在gcc/g++下使用ASAN只需要在編譯的時候加上-fsanitize=address,在此選項下編譯簡單的存在double free的C檔案,執行時可以看到檢測到double free:
//TODO
在源文章程式碼的基礎上稍加修改在Linux Ubuntu16.04的環境下可以得到預期結果的原始碼如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> struct sample { char buf[8]; uint32_t val; }; void choice1() { puts("1. Overflowing a buffer within a struct."); struct sample sample_struct; printf("sample_struct.val = 0x%x\n", sample_struct.val); strncpy(sample_struct.buf, "ccccccccdddd", 12); printf("sample_struct.val = 0x%x\n", sample_struct.val); } /* void choice2() { puts("2. Arbitrary write with integer overflows skipping over shadow mem."); char canary[10] = "IAMCANARY"; char buf[10]; printf("Canary = \"%s\"\n", canary); int position = 2147483616; position = position * 2; printf("position = %d\n", position); for (int i = 0; i < 9; i++) { buf[position + i] = 'X'; printf("buf[%d] = 'X'\n", position + i); } printf("Canary = \"%s\"\n", canary); } */ void choice2() { puts("2. Skipping over shadow memory."); char canary[10] = "IAMCANARY"; char buf[10]; printf("Canary = \"%s\"\n", canary); int position = -64; printf("position = %d\n", position); for (int i = 0; i < 9; i++) { buf[position + i] = 'X'; printf("buf[%d] = 'X'\n", position + i); } printf("Canary = \"%s\"\n", canary); } void f1(int ** p) { int dangle = 0x41414141; *p = &dangle; } void f2() { int override1 = 0x42424242; long long int a=1; long long int b=2; long long int c=3; long long int d=4; long long int e=5; long long int f=6; long long int g=7; long long int h=8; long long int i=9; int j=10; } void choice3() { puts("3. Use of stack variable after returning from a function."); int * p = 0; printf("p = %p\n", p); printf("*p = undefined\n"); f1(&p); printf("p = %p\n", p); printf("*p = 0x%x\n", *p); f2(); printf("p = %p\n", p); printf("*p = 0x%x\n", *p); } int main(int argc, char ** argv) { choice1(); choice2(); choice3(); return 0; }
結果如下:
//TODO
其中choice1對應第一種漏洞:結構體中的緩衝區溢位。首先打印出了棧上未初始化的垃圾資料,其次利用結構體上的變數連續儲存,第一個變數溢位,覆蓋後一個本不該被賦值的變數,此緩衝區溢位不會被ASAN檢測到。
choice2對應第二種漏洞:跳過shadow memory。(由於我在查了一些資料後,對ASAN中的shadow memory仍然不是非常理解,這一部分先翻譯原文章的內容。)此漏洞利用在二進位制檔案上啟用了ASAN來執行相同的緩衝區上溢/下溢,通過計算一些偏移量來跳過保護緩衝區的shadow位元組。
choice3對應第三種漏洞:從函式返回後使用棧變數。在函式呼叫返回後,棧空間被銷燬,下一次再次呼叫其他函式時不應該影響上一次呼叫的結果。但是由於在主函式中連續兩次呼叫函式,會開拓同一段棧空間,因此可能會出現stack-use-after-return的bugs。choice3展示了該bug的一種情況,可以看到ASAN不會檢測到使用指向已銷燬棧幀的指標的情況。
跟我一起寫Makefile
文章連結: https://seisman.github.io/how-to-write-makefile/index.html
Makefile可以實現“自動化編譯”,使用make命令就可以實現整個工程完全自動編譯。
規則
Makefile的規則包含兩個部分:依賴關係、生成目標的方法
target ... : prerequisites ...
#或者 target : prerequisites ; command
command
...
target: 目標檔案/可執行檔案/label
prerequisites:生成該target所依賴的檔案或target
command:必須以Tab鍵開頭,說明該target所要執行的命令(任意的shell命令)
==> target依賴於prerequisites中的檔案,其生成規則定義在command中。
prerequisites中如果有一個以上的檔案比target檔案要新,就會執行command定義的命令。
一般來說,make命令會以UNIX的標準Shell,/bin/sh
執行命令
書寫規則
Makefile中只應該有一個最終目標,第一條規則中的第一個目標會成為最終的目標,也就是make命令所完成的目標。
如果某一行過長,可以使用反斜槓\
作為換行符。
make支援三個萬用字元:*
,?
,~
Makefile包含的五個部分
-
顯示規則
說明了如何生成一個或多個目標檔案,包括要生成的檔案、檔案的依賴檔案和生成的命令
-
隱晦規則
GNU的make可以自動推導檔案以及檔案依賴關係後面的命令,make看到一個.o檔案,就會自動的把.c檔案加在依賴關係中,並且推匯出
cc -c xxx.c
命令 -
變數的定義
makefile的變數也就是一個字串:定義字串
xxx=...
,則可以通過$(xxx)
來使用這個變數 -
檔案指示
通過
inlcude <filename>
可以在一個Makefile中引用另一個Makefile檔案;make也會引用環境變數MAKEFILES值所代表的所有Makefile,但引入Makefile的“目標”不起作用。 -
註釋
Makefile的檔名
預設情況下:make命令會在當前目錄下按順序尋找檔名為"GNUmakefile","makefile","Makefile",其中"GNUmakefile"只能由GNU的make識別。
GNU make的工作方式
- 讀入所有的Makefile
- 讀入被include的其它Makefile
- 初始化檔案中的變數
- 推導隱晦規則,並分析所有規則
- 為所有的目標檔案建立依賴關係鏈
- 根據依賴關係,決定哪些目標要重新生成
- 執行生成命令
當變量出現在依賴關係的規則中,只有當這條依賴被決定要使用了,那麼變數才會在其內部展開。
//UNDONE