1. 程式人生 > 實用技巧 >Week1--漏洞學習

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的工作方式

  1. 讀入所有的Makefile
  2. 讀入被include的其它Makefile
  3. 初始化檔案中的變數
  4. 推導隱晦規則,並分析所有規則
  5. 為所有的目標檔案建立依賴關係鏈
  6. 根據依賴關係,決定哪些目標要重新生成
  7. 執行生成命令

當變量出現在依賴關係的規則中,只有當這條依賴被決定要使用了,那麼變數才會在其內部展開。

//UNDONE