自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

在 Linux 上使用 Checksec 識別二進制文件的安全屬性

系統(tǒng) Linux
這篇文章能讓你了解如何使用 Checksec ,來識別一個可執(zhí)行文件的安全屬性,了解安全屬性的含義,并知道如何使用它們。

編譯源代碼會生成一個二進制文件(LCTT 譯注:即 ??.o??? 文件)。在編譯期間,你可以向 ??gcc?? 編譯器提供 標志flags,以啟用或禁用二進制文件的某些屬性,這些屬性與安全性相關。

Checksec 是一個漂亮的小工具,同時它也是一個 shell 腳本。Checksec 可以識別編譯時構建到二進制文件中的安全屬性。編譯器可能會默認啟用一些安全屬性,你也可以提供特定的標志,來啟用其他的安全屬性。

本文將介紹如何使用 Checksec ,來識別二進制文件的安全屬性,包括:

  1. Checksec 在查找有關安全屬性的信息時,使用了什么底層的命令
  2. 在將源代碼編譯成二進制文件時,如何使用GNU 編譯器套件GNU Compiler Collection(即 GCC)來啟用安全屬性

安裝 checksec

要在 Fedora 和其他基于 RPM 的 Linux 系統(tǒng)上,安裝 Checksec,請使用以下命令:

$ sudo dnf install checksec

對于基于 Debian 的 Linux 發(fā)行版,使用對應的 ??apt?? 命令,來安裝 Checksec。

$ sudo apt install checksec

shell 腳本

在安裝完 Checksec 后,能夠發(fā)現(xiàn) Checksec 是一個單文件的 shell 腳本,它位于 ??/usr/bin/checksec??,并且這個文件挺大的。Checksec 的一個優(yōu)點是你可以通過快速通讀這個 shell 腳本,從而了解 Checksec 的執(zhí)行原理、明白所有能查找有關二進制文件或可執(zhí)行文件的安全屬性的系統(tǒng)命令

$ file /usr/bin/checksec/usr/bin/checksec: Bourne-Again shell script, ASCII text executable, with very long lines$ wc -l /usr/bin/checksec2111 /usr/bin/checksec

以下的命令展示了如何對你每天都會使用的:??ls?? 命令的二進制文件運行 Checksec。Checksec 命令的格式是:??checksec --file=??,后面再跟上二進制文件的絕對路徑:

$ checksec --file=/usr/bin/lsRELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILEFull RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   No Symbols        Yes   5       17              /usr/bin/ls

當你在終端中對某個二進制文件運行 Checksec 時,你會看到安全屬性有顏色上的區(qū)分,顯示什么是好的安全屬性(綠色),什么可能不是好的安全屬性(紅色)。我在這里說 “可能” 是因為即使有些安全屬性是紅色的,也不一定意味著這個二進制文件很糟糕,它可能只是表明發(fā)行版供應商在編譯二進制文件時做了一些權衡,從而舍棄了部分安全屬性。

Checksec 輸出的第一行提供了二進制文件的各種安全屬性,例如 ??RELRO??、??STACK CANARY??、??NX?? 等(我將在后文進行詳細解釋)。第二行打印出給定二進制文件(本例中為 ??ls??)在這些安全屬性的狀態(tài)(例如,??NX enabled?? 表示為堆棧中的數(shù)據(jù)沒有執(zhí)行權限)。

示例二進制文件

在本文中,我將使用以下的 “hello world” 程序作為示例二進制文件。

#include <stdio.h>int main(){        printf("Hello World\n");        return 0;}

請注意,在編譯源文件 ??hello.c?? 的時候,我沒有給 ??gcc?? 提供任何額外的標志:

$ gcc hello.c -o hello $ file hellohello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped$ ./helloHello World

使用 Checksec 運行二進制文件 ??hello??,打印的某些安全屬性的狀態(tài),與上面的 ??ls?? 二進制文件的結果不同(在你的屏幕上,某些屬性可能顯示為紅色):

$ checksec --file=./helloRELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILEPartial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   85) Symbols       No    0       0./hello$

(LCTT 譯注:在我的 Ubuntu 22.04 虛擬機,使用 11.3.0 版本的 ??gcc??,結果與上述不太相同,利用默認參數(shù)進行編譯,會得到 RELRO、PIE、NX 保護是全開的情況。)

更改 Checksec 的輸出格式

Checksec 允許自定義各種輸出格式,你可以使用 ??--output?? 來自定義輸出格式。我將選擇的輸出格式是 JSON 格式,并將輸出結果通過管道傳輸?shù)?nbsp;??jq?? 實用程序,來得到漂亮的打印。

接下來,確保你已安裝好了 ??jq??,因為本教程會使用 ??jq?? 從 Checksec 的輸出結果中,用 ??grep?? 來快速得到某一特定的安全屬性狀態(tài),并報告該安全屬性是否啟動(啟動為 ??yes??,未啟動為 ??no??):

$ checksec --file=./hello --output=json | jq{  "hello": {    "relro": "partial",    "canary": "no",    "nx": "yes",    "pie": "no",    "rpath": "no",    "runpath": "no",    "symbols": "yes",    "fortify_source": "no",    "fortified": "0",    "fortify-able": "0"  }}

看一看所有的安全屬性

上面的二進制文件 ??hello?? 包括幾個安全屬性。我將該二進制文件與 ??ls?? 的二進制文件進行比較,以檢查啟用的安全屬性有何不同,并解釋 Checksec 是如何找到此信息。

1、符號(Symbol)

我先從簡單的講起。在編譯期間,某些 符號symbols包含在二進制文件中,這些符號主要用作于調(diào)試。開發(fā)軟件時,需要用到這些符號,來調(diào)試和修復錯誤。

這些符號通常會從供用戶普遍使用的最終二進制文件中刪除。刪除這些符號不會影響到二進制文件的執(zhí)行。刪除符號通常是為了節(jié)省空間,因為一旦符號被刪除了,二進制文件就會稍微小一些。在閉源或專有軟件中,符號通常都會被刪除,因為把這些符號放在二進制文件中,可以很容易地推斷出軟件的內(nèi)部工作原理。

根據(jù) Checksec 的結果,在二進制文件 ??hello?? 中有符號,但在 ??ls?? 的二進制文件中不會有符號。同樣地,你還可以用 ??file?? 命令,來找到符號的信息,在二進制文件 ??hello?? 的輸出結果的最后,看到 ??not stripped??,表明二進制文件 ??hello?? 有符號:

$ checksec --file=/bin/ls --output=json | jq | grep symbols    "symbols": "no",$ checksec --file=./hello --output=json | jq | grep symbols    "symbols": "yes",$ file hellohello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

Checksec 是如何找到符號的信息呢?Checksec 提供了一個方便的 ??--debug?? 選項,來顯示運行了哪些函數(shù)。因此,運行以下的命令,會顯示在 shell 腳本中運行了哪些函數(shù):

$ checksec --debug --file=./hello

在本教程中,我試圖尋找 Checksec 查找安全屬性信息時,使用了什么底層命令。由于 Checksec 是一個 shell 腳本,因此你始終可以使用 Bash 功能。以下的命令將輸出從 shell 腳本中運行的每個命令:

$ bash -x /usr/bin/checksec --file=./hello

如果你滾動瀏覽上述的輸出結果的話,你會看到 ??echo_message?? 后面有各個安全屬性的類別。以下顯示了 Checksec 檢測二進制文件是否包含符號時,運行的底層命令:

+ readelf -W --symbols ./hello+ grep -q '\\.symtab'+ echo_message '\033[31m96) Symbols\t\033[m  ' Symbols, ' symbols="yes"' '"symbols":"yes",'

上面的輸出顯示,Checksec 利用 ??readelf??,來讀取二進制文件,并提供一個特殊 ??--symbols?? 標志,來列出二進制文件中的所有符號。然后它會查找一個特殊值:??.symtab??,它提供了所能找到的條目的計數(shù)(即符號的個數(shù))。你可以在上面編譯的測試二進制文件 ??hello?? 上,嘗試以下命令,得到與 Checksec 查看二進制文件類似的符號信息:

$ readelf -W --symbols ./hello$ readelf -W --symbols ./hello | grep -i symtab

(LCTT 譯注:也可以通過直接查看 ??/usr/bin/checksec?? 下的 Checksec 源文件。)

如何刪除符號

你可以在編譯后或編譯時刪除符號。

  • 編譯后: 在編譯后,你可以使用 strip,手動地來刪除二進制文件的符號。刪除后,使用 file 命令,來檢驗是否還有符號,現(xiàn)在顯示 stripped,表明二進制文件 hello 無符號了:
$ gcc hello.c -o hello$$ file hellohello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, for GNU/Linux 3.2.0, not stripped$$ strip hello$$ file hellohello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, for GNU/Linux 3.2.0, stripped$
  • 編譯時: 你也可以在編譯時,用 -s 參數(shù)讓 gcc 編譯器幫你自動地刪除符號:
$ gcc -s hello.c -o hello$$ file hellohello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=247de82a8ad84e7d8f20751ce79ea9e0cf4bd263, for GNU/Linux 3.2.0, stripped$

重新運行 Checksec,你可以看到現(xiàn)在二進制文件 ??hello?? 的 ??symbols?? 這一屬性的值是??no??:

$ checksec --file=./hello --output=json | jq | grep symbols    "symbols": "no",$

2、Canary(堆棧溢出哨兵)

Canary 是放置在緩沖區(qū)和 棧stack 上的控制數(shù)據(jù)之間的已知值,它用于監(jiān)視緩沖區(qū)是否溢出。當應用程序執(zhí)行時,會為其分配兩種內(nèi)存,其中之一就是 。棧是一個具有兩個操作的數(shù)據(jù)結構:第一個操作 ??push???,將數(shù)據(jù)壓入堆棧;第二個操作 ??pop??,以后進先出的順序從棧中彈出數(shù)據(jù)。惡意的輸入可能會導致棧溢出,或使用特制的輸入破壞棧,并導致程序崩潰:

$ checksec --file=/bin/ls --output=json | jq | grep canary    "canary": "yes",$$ checksec --file=./hello --output=json | jq | grep canary    "canary": "no",$

Checksec 是如何確定二進制文件是否啟用了 Canary 的呢?使用上述同樣的方法,得到 Checksec 在檢測二進制文件是否啟用 Canary 時,運行的底層命令:

$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'
啟用 Canary

為了防止棧溢出等情況,編譯器提供了 ??-stack-protector-all?? 標志,它向二進制文件添加了額外的代碼,來檢查緩沖區(qū)是否溢出:

$ gcc -fstack-protector-all hello.c -o hello$ checksec --file=./hello --output=json | jq | grep canary    "canary": "yes",

Checksec 顯示 Canary 屬性現(xiàn)已啟用。你還可以通過以下方式,來驗證這一點:

$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (3)    83: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@@GLIBC_2.4$

3、位置無關可執(zhí)行文件(PIE)

位置無關可執(zhí)行文件Position-Independent Executable(PIE),顧名思義,它指的是放置在內(nèi)存中某處執(zhí)行的代碼,不管其絕對地址的位置,即代碼段、數(shù)據(jù)段地址隨機化(ASLR):

$ checksec --file=/bin/ls --output=json | jq | grep pie    "pie": "yes",$ checksec --file=./hello --output=json | jq | grep pie    "pie": "no",

通常,PIE 僅對 庫libraries啟用,并不對獨立命令行程序啟用 PIE。在下面的輸出中,??hello??? 顯示為 ??LSB executable???,而 ??libc??? 標準庫(??.so???) 文件被標記為 ??LSB shared object??:

$ file hellohello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped$ file /lib64/libc-2.32.so/lib64/libc-2.32.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4a7fb374097fb927fb93d35ef98ba89262d0c4a4, for GNU/Linux 3.2.0, not stripped

Checksec 查找是否啟用 PIE 的底層命令如下:

$ readelf -W -h ./hello | grep EXEC  Type:                              EXEC (Executable file)

如果你在共享庫上嘗試相同的命令,你將看到 ??DYN???,而不是 ??EXEC??:

$ readelf -W -h /lib64/libc-2.32.so | grep DYN  Type:                              DYN (Shared object file)
啟用 PIE

要在測試程序 ??hello.c?? 上啟用 PIE,請在編譯時,使用以下命令:

$ gcc -pie -fpie hello.c -o hello`

你可以使用 Checksec,來驗證 PIE 是否已啟用:

$ checksec --file=./hello --output=json | jq | grep pie    "pie": "yes",$

現(xiàn)在,應該會顯示為 “PIE 可執(zhí)行pie executable”,其類型從 ??EXEC??? 更改為 ??DYN??:

$ file hellohello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bb039adf2530d97e02f534a94f0f668cd540f940, for GNU/Linux 3.2.0, not stripped$ readelf -W -h ./hello | grep DYN  Type:                              DYN (Shared object file)

4、NX(堆棧禁止執(zhí)行)

NX 代表 不可執(zhí)行non-executable。它通常在 CPU 層面上啟用,因此啟用 NX 的操作系統(tǒng)可以將某些內(nèi)存區(qū)域標記為不可執(zhí)行。通常,緩沖區(qū)溢出漏洞將惡意代碼放在堆棧上,然后嘗試執(zhí)行它。但是,讓堆棧這些可寫區(qū)域變得不可執(zhí)行,可以防止這種攻擊。在使用 ??gcc?? 對源程序進行編譯時,默認啟用此安全屬性:

$ checksec --file=/bin/ls --output=json | jq | grep nx    "nx": "yes",$ checksec --file=./hello --output=json | jq | grep nx    "nx": "yes",

Checksec 使用以下底層命令,來確定是否啟用了 NX。在尾部的 ??RW??? 表示堆棧是可讀可寫的;因為沒有 ??E??,所以堆棧是不可執(zhí)行的:

$ readelf -W -l ./hello | grep GNU_STACK  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
演示如何禁用 NX

我們不建議禁用 NX,但你可以在編譯程序時,使用 ??-z execstack?? 參數(shù),來禁用 NX:

$ gcc -z execstack hello.c -o hello$ checksec --file=./hello --output=json | jq | grep nx    "nx": "no",

編譯后,堆棧會變?yōu)榭勺x可寫可執(zhí)行(??RWE??),允許在堆棧上的惡意代碼執(zhí)行:

$ readelf -W -l ./hello | grep GNU_STACK  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

5、RELRO(GOT 寫保護)

RELRO 代表 “重定位只讀Relocation Read-Only”??蓤?zhí)行鏈接格式(ELF)二進制文件使用全局偏移表(GOT)來動態(tài)地解析函數(shù)。啟用 RELRO 后,會設置二進制文件中的 GOT 表為只讀,從而防止重定位攻擊:

$ checksec --file=/bin/ls --output=json | jq | grep relro    "relro": "full",$ checksec --file=./hello --output=json | jq | grep relro    "relro": "partial",

Checksec 使用以下底層命令,來查找是否啟用 RELRO。在二進制文件 ??hello??? 僅啟用了 RELRO 屬性中的一個屬性,因此,在 Checksec 驗證時,顯示 ??partial??:

$ readelf -W -l ./hello | grep GNU_RELRO  GNU_RELRO      0x002e10 0x0000000000403e10 0x0000000000403e10 0x0001f0 0x0001f0 R   0x1$ readelf -W -d ./hello | grep BIND_NOW
啟用全 RELRO

要啟用全 RELRO,請在 ??gcc?? 編譯時,使用以下命令行參數(shù):

$ gcc -Wl,-z,relro,-z,now hello.c -o hello$ checksec --file=./hello --output=json | jq | grep relro    "relro": "full",

現(xiàn)在, RELRO 中的第二個屬性也被啟用,使程序變成全 RELRO:

$ readelf -W -l ./hello | grep GNU_RELRO  GNU_RELRO      0x002dd0 0x0000000000403dd0 0x0000000000403dd0 0x000230 0x000230 R   0x1$ readelf -W -d ./hello | grep BIND_NOW 0x0000000000000018 (BIND_NOW)       

6、Fortify

Fortify 是另一個安全屬性,但它超出了本文的范圍。Checksec 是如何在二進制文件中驗證 Fortify,以及如何在 ??gcc?? 編譯時啟用 Fortify,作為你需要解決的課后練習。

$ checksec --file=/bin/ls --output=json | jq  | grep -i forti    "fortify_source": "yes",    "fortified": "5",    "fortify-able": "17"$ checksec --file=./hello --output=json | jq  | grep -i forti    "fortify_source": "no",    "fortified": "0",    "fortify-able": "0"

其他的 Checksec 功能

關于安全性的話題是永無止境的,不可能在本文涵蓋所有關于安全性的內(nèi)容,但我還想提一下 Checksec 命令的一些其他功能,這些功能也很好用。

對多個二進制文件運行 Checksec

你不必對每個二進制文件都進行一次 Checksec。相反,你可以提供多個二進制文件所在的目錄路徑,Checksec 將一次性為你驗證所有文件:

$ checksec --dir=/usr

對進程運行 Checksec

Checksec 除了能檢查二進制文件的安全屬性,Checksec 還能對程序起作用。以下的命令用于查找你系統(tǒng)上所有正在運行的程序的安全屬性。如果你希望 Checksec 檢查所有正在運行的進程,可以使用 ??--proc-all??,或者你也可以使用進程名稱,選擇特定的進程進行檢查:

$ checksec --proc-all$ checksec --proc=bash

對內(nèi)核運行 Checksec

除了本文介紹的用 Checksec 檢查用戶態(tài)應用程序的安全屬性之外,你還可以使用它來檢查系統(tǒng)內(nèi)置的 內(nèi)核屬性kernel properties:

$ checksec --kernel

快來試一試 Checksec 吧

Checksec 是一個能了解哪些用戶空間和內(nèi)核的安全屬性被啟用的好方法。現(xiàn)在,你就可以開始使用 Checksec,來了解每個安全屬性是什么,并明白啟用每個安全屬性的原因,以及它能阻止的攻擊類型。

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2020-05-06 09:51:37

二進制Linux命令行工具

2024-02-01 09:04:12

2009-12-10 09:24:50

PHP函數(shù)fwrite

2022-10-31 08:02:42

二進制計算乘法

2009-12-16 10:49:42

Ruby操作二進制文件

2009-08-12 18:06:53

C#讀取二進制文件

2023-09-20 00:02:33

C++14二進制字面量

2009-02-27 09:37:33

Google二進制代碼

2013-04-28 15:37:35

JBoss

2023-09-18 23:50:25

二進制文件裁剪Layout

2017-04-11 10:48:53

JS二進制

2010-10-13 15:45:23

MySQL二進制日志

2020-05-22 18:00:26

Go二進制文件編程語言

2023-12-26 15:10:00

處理二進制文件

2009-11-02 11:27:42

VB.NET二進制文件

2018-10-22 14:37:16

二進制數(shù)據(jù)存儲

2023-03-20 08:24:31

工具GoReleaser

2024-10-30 09:50:51

WebGo語言

2011-05-25 14:10:38

浮點數(shù)

2021-11-10 09:15:00

CPU01 二進制Linux
點贊
收藏

51CTO技術棧公眾號