GNU/Linux >> Linux の 問題 >  >> Linux

checksecを使用してLinuxのセキュリティプロパティを特定する

ソースコードをコンパイルすると、バイナリが生成されます。コンパイル中に、バイナリの特定のプロパティを有効または無効にするフラグをコンパイラに提供できます。これらのプロパティの一部はセキュリティに関連しています。

Checksecは、他の関数の中でも、コンパイル時にバイナリに組み込まれたセキュリティプロパティを識別する気の利いた小さなツール(およびシェルスクリプト)です。コンパイラはこれらのプロパティの一部をデフォルトで有効にする場合があり、他のプロパティを有効にするために特定のフラグを指定する必要がある場合があります。

この記事では、checksecを使用して、バイナリのセキュリティプロパティを識別する方法について説明します。

  1. checksecがセキュリティプロパティに関する情報を検索するために使用する基本的なコマンド
  2. サンプルバイナリをコンパイルするときにGNUコンパイラコレクション(GCC)を使用してセキュリティプロパティを有効にする方法
チェック秒をインストール

Fedoraおよびその他のRPMベースのシステムにchecksecをインストールするには、以下を使用します:

 $ sudo dnf install checksec 

Debianベースのディストリビューションの場合、同等のaptを使用します コマンド。

シェルスクリプト

Checksecは、かなり大きなスクリプトですが、単一ファイルのシェルスクリプトです。利点は、スクリプトをすばやく読み、実行中のすべてのシステムコマンドを理解して、バイナリまたは実行可能ファイルに関する情報を見つけることができることです。

 $ file / usr / bin / checksec 
/ usr / bin / checksec:Bourne-Againシェルスクリプト、ASCIIテキスト実行可能ファイル、非常に長い行

$ wc -l / usr / bin / checksec
2111 / usr / bin / checksec

おそらく毎日実行するバイナリを備えたドライブのchecksecを実行します:ユビキタスなls 指図。コマンドの形式はchecksec --file=です。 lsの絶対パスが続きます バイナリ:

 $ checksec --file =は/ usr / binに/ lsの
RELRO STACK CANARY NX PIE RPATH RUNPATHシンボルFORTIFY要塞Fortifiableファイル
全RELROカナリアはNXはPIEはありませんRPATHないRUNPATHない記号を有効に有効になっていはい5 17 / usr / bin / ls

これを端末で実行すると、何が良いのか、何がおそらく悪いのかを示す色分けが表示されます。 「おそらく」と言うのは、何かが赤で表示されていても、必ずしも物事が恐ろしいことを意味するわけではないからです。バイナリをコンパイルするときに、ディストロベンダーがトレードオフを行ったことを意味するだけかもしれません。

最初の行は、RELROなどのバイナリで通常使用できるさまざまなセキュリティプロパティを提供します 、STACK CANARYNX 、など(以下で詳しく説明します)。 2行目は、特定のバイナリ(ls)のこれらのプロパティのステータスを示しています。 、 この場合)。たとえば、NX enabled このバイナリに対して一部のプロパティが有効になっていることを意味します。

サンプルバイナリ

このチュートリアルでは、次の「helloworld」プログラムをサンプルバイナリとして使用します。

 #include  

int main()
{
printf( "Hello World \ n");
return 0;
}

gccを提供しなかったことに注意してください コンパイル中に追加のフラグを使用する場合:

 $ gcc hello.c -o hello 

$ file hello
hello:ELF 64ビットLSB実行可能ファイル、x86-64、バージョン1(SYSV)、動的リンク、インタープリター/ lib64 / ld-linux-x86-64.so.2、BuildID [sha1] =014b8966ba43e3ae47fab5acae051e208ec9074c、GNU / Linux 3.2.0の場合、削除されません

$ ./hello
Hello World

checksecを介してバイナリを実行します。一部のプロパティは、lsの場合とは異なります 上記のコマンド(画面上では、これらは赤で表示される場合があります):

<前> $ checksec --file =。/ 部分RELROありませんカナリア/>
$ 出力形式の変更

Checksecでは、--outputで指定できるさまざまな出力形式を使用できます。 。 JSON形式を選択し、出力をjqにパイプします きれいな印刷のためのユーティリティ。

フォローするには、jqがあることを確認してください このチュートリアルではこの出力形式を使用して、出力から特定のプロパティをすばやくgrepし、yesを報告するためにインストールされました またはno それぞれに:

 $ checksec --file =./ hello --output =json | jq 
{
"./hello":{
"relro": "partial"、
"canary": "no"、
"nx": " yes "、
" pie ":" no "、
" rpath ":" no "、
" runpath ":" no "、
" symbol ":" yes " 、
"fortify_source": "no"、
"fortified": "0"、
"fortify-able": "0"
}
}
セキュリティプロパティのウォークスルー

セキュリティの詳細

  • 防御的なコーディングガイド
  • ウェビナー:システムのセキュリティと標準オペレーティングシステムへの準拠の自動化
  • Linuxコンテナセキュリティの10層
  • SELinuxの塗り絵
  • その他のセキュリティ記事

上記のバイナリには、いくつかのセキュリティプロパティが含まれています。そのバイナリをlsと比較します 上記のバイナリを使用して、何が有効になっているかを調べ、checksecがこの情報をどのように検出したかを説明します。

1。記号

まずは簡単なものから始めましょう。コンパイル中、主にデバッグのために、特定のシンボルがバイナリに含まれます。これらの記号は、ソフトウェアを開発するときに必要であり、デバッグと修正に複数のサイクルが必要です。

これらのシンボルは通常、一般的な使用のためにリリースされる前に、最終的なバイナリから削除(削除)されます。これは、バイナリの実行にはまったく影響しません。シンボルの場合と同じように実行されます。シンボルが削除されるとバイナリがいくらか軽くなるため、スペースを節約するために削除が行われることがよくあります。クローズドソースまたはプロプライエタリソフトウェアでは、シンボルをバイナリに含めるとソフトウェアの内部動作を簡単に推測できるため、シンボルが削除されることがよくあります。

checksecによると、シンボルはこのバイナリに存在しますが、lsには存在しませんでした。 バイナリ。 fileを実行して、この情報を見つけることもできます。 プログラムのコマンド-not strippedが表示されます 終わりに向かって出力で:

 $ checksec --file =/ bin / ls --output =json | jq | grepシンボル
"symbols": "no"、

$ checksec --file =./ hello --output =json | jq | grepシンボル
"symbols": "yes"、

$ file hello
hello:ELF 64ビットLSB実行可能ファイル、x86-64、バージョン1(SYSV)、動的リンク、インタープリター/lib64/ld-linux-x86-64.so.2、BuildID [sha1] =014b8966ba43e3ae47fab5acae051e208ec9074c、GNU / Linux 3.2.0の場合、削除されません

checksecはどのようにしてこの情報を見つけましたか?まあ、それは便利な--debugを提供します 実行された関数を表示するオプション。したがって、次のコマンドを実行すると、シェルスクリプト内で実行された関数が表示されます。

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

このチュートリアルでは、この情報を見つけるために使用される基本的なコマンドを探しています。シェルスクリプトなので、いつでもBashの機能を利用できます。このコマンドは、シェルスクリプト内から実行されたすべてのコマンドを出力します:

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

出力をスクロールすると、echo_messageが表示されます。 その後にセキュリティプロパティのカテゴリが続きます。バイナリにシンボルが含まれているかどうかについてchecksecが報告する内容は次のとおりです。

 + readelf -W --symbols ./hello 
+ grep -q'\ .symtab'
+ echo_message'\ 033 [31m96)シンボル\ t \ 033 [m'シンボル、'シンボル="yes"'' "symbols": "yes"、'

これを単純化するために、checksecはreadelfを利用します バイナリを読み取り、特別な--symbolsを提供するユーティリティ バイナリ内のすべてのシンボルを一覧表示するフラグ。次に、特別な値.symtabを取得します。 、検出したエントリ(シンボル)の数を提供します。上でコンパイルしたテストバイナリで次のコマンドを試すことができます。

 $ readelf -W --symbols ./hello 
$ readelf -W --symbols ./hello | grep -i symtab
シンボルを削除する方法

コンパイル後またはコンパイル中にシンボルを削除できます。

  • コンパイル後: コンパイル後、stripを使用できます シンボルを削除するためのバイナリのユーティリティ。 fileを使用して機能したことを確認します コマンド。出力はstrippedとして表示されます。 :
     $ gcc hello.c -o hello 
    $
    $ file hello
    hello:ELF 64ビットLSB実行可能ファイル、x86-64、バージョン1(SYSV) 、動的リンク、インタープリター/lib64/ld-linux-x86-64.so.2、BuildID [sha1] =322037496cf6a2029dcdcf68649a4ebc63780138、GNU / Linux 3.2.0の場合、ストリップされない
    $
    $ strip hello
    $
    $ file hello
    hello:ELF 64ビットLSB実行可能ファイル、x86-64、バージョン1(SYSV)、動的リンク、インタープリター/lib64/ld-linux-x86-64.so .2、BuildID [sha1] =322037496cf6a2029dcdcf68649a4ebc63780138、GNU / Linux 3.2.0の場合、削除
    $

コンパイル中にシンボルを削除する方法

コンパイル後に手動でシンボルを削除する代わりに、-sを指定して、コンパイラに削除を依頼できます。 引数:

 $ gcc -s hello.c -o hello 
$
$ file hello
hello:ELF 64ビットLSB実行可能ファイル、x86-64、バージョン1(SYSV)、動的リンク、インタープリター/lib64/ld-linux-x86-64.so.2、BuildID [sha1] =247de82a8ad84e7d8f20751ce79ea9e0cf4bd263、GNU / Linux 3.2.0の場合、削除
$

checksecを再実行すると、symbolsが表示されます。 noとして表示されます :

 $ checksec --file =./ hello --output =json | jq | grepシンボル
"シンボル": "no"、
$

2。カナリア

カナリアは、スタック上のバッファと制御データの間に配置される既知の値です。 バッファオーバーフローを監視します。アプリケーションを実行すると、2種類のメモリが割り当てられます。それらの1つはスタックです 、これは2つの操作を含む単純なデータ構造です:push 、データをスタックに配置し、pop 、逆の順序でスタックからデータを削除します。悪意のある入力は、特別に細工された入力でスタックをオーバーフローまたは破損させ、プログラムをクラッシュさせる可能性があります:

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

checksecは、バイナリがカナリアで有効になっているかどうかをどのように確認しますか?上記の方法を使用して、シェルスクリプト内で次のコマンドを実行することにより、それを絞り込むことができます。

 $ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie' 
カナリアを有効にする

これらのケースから保護するために、コンパイラは-stack-protector-allを提供します フラグ。このようなバッファオーバーフローをチェックするためにバイナリに追加のコードを追加します。

 $ gcc -fstack-protector-all hello.c -o hello 

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

Checksecは、プロパティが有効になったことを示します。これは次の方法でも確認できます:

 $ 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)
8:0000000000000000 _ _ _ _ _ _ _ _ $

3。 PIE

PIEは、位置に依存しない実行可能ファイルの略です。名前が示すように、絶対アドレスに関係なく、実行のためにメモリ内のどこかに配置されるコードです:

 $ checksec --file =/ bin / ls --output =json | jq | grep pie 
"pie": "yes"、

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

多くの場合、PIEはライブラリに対してのみ有効になり、スタンドアロンのコマンドラインプログラムには有効になりません。以下の出力では、hello LSB executableとして表示されます 、一方、libc 標準ライブラリ(.so )ファイルはLSB shared objectとマークされています :

 $ file hello 
hello:ELF 64ビットLSB実行可能、x86-64、バージョン1(SYSV)、動的リンク、インタープリター/lib64/ld-linux-x86-64.so.2、BuildID [ sha1] =014b8966ba43e3ae47fab5acae051e208ec9074c、GNU / Linux 3.2.0の場合、削除されません

$ファイル/lib64/libc-2.32.so
/lib64/libc-2.32.so:ELF64ビットLSB共有オブジェクト、x86-64、バージョン1(GNU / Linux)、動的リンク、インタープリター/lib64/ld-linux-x86-64.so.2、BuildID [sha1] =4a7fb374097fb927fb93d35ef98ba89262d0c4a4、GNU / Linux 3.2.0用、剥ぎ取られていない

Checksecは、次の方法でこの情報を見つけようとします:

 $ readelf -W -h ./hello | grep EXEC 
タイプ:EXEC(実行可能ファイル)

EXECの代わりに共有ライブラリで同じコマンドを試した場合 、DYNが表示されます :

 $ readelf -W -h /lib64/libc-2.32.so | grep DYN 
タイプ:DYN(共有オブジェクトファイル)
PIEを有効にする

テストプログラムでPIEを有効にするには、次の引数をコンパイラに送信します。

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

checksecを使用してPIEが有効になっていることを確認できます:

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

タイプがEXECから変更されたPIE実行可能ファイルとして表示されるはずです。 DYNへ :

 $ file hello 
hello:ELF64ビットLSBpie実行可能ファイル、x86-64、バージョン1(SYSV)、動的リンク、インタープリター/lib64/ld-linux-x86-64.so.2、BuildID [sha1] =bb039adf2530d97e02f534a94f0f668cd540f940、GNU / Linux 3.2.0の場合、削除されません

$ readelf -W -h ./hello | grep DYN
タイプ:DYN(共有オブジェクトファイル)

4。 NX

NXは「実行不可能」の略です。多くの場合、CPUレベルで有効になっているため、NXが有効になっているオペレーティングシステムは、メモリの特定の領域を実行不可としてマークできます。多くの場合、バッファオーバーフローのエクスプロイトは、コードをスタックに配置してから実行しようとします。ただし、この書き込み可能領域を実行不可にすると、このような攻撃を防ぐことができます。このプロパティは、gccを使用した通常のコンパイル中にデフォルトで有効になります :

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

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

Checksecは、以下のコマンドを使用してこの情報を判別します。 RW 終わりに向かって、スタックが読み取りおよび書き込み可能であることを意味します。 Eがないので 、実行可能ではありません:

 $ readelf -W -l ./hello | grep GNU_STACK 
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
デモ目的でNXを無効にする

推奨されていませんが、NXを無効にすることができます -z execstackを使用してプログラムをコンパイルする場合 引数:

 $ gcc -z execstack hello.c -o hello 

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

コンパイル時に、スタックは実行可能になります(RWE )、悪意のあるコードの実行を許可します:

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

5。 RELRO

RELROはRelocationRead-Onlyの略です。 Executable Linkable Format(ELF)バイナリは、グローバルオフセットテーブル(GOT)を使用して関数を動的に解決します。有効にすると、このセキュリティプロパティにより、GOTがバイナリ内で読み取り専用になり、何らかの形の再配置攻撃が防止されます。

 $ checksec --file =/ bin / ls --output =json | jq | grep relro 
"relro": "full"、

$ checksec --file =./ hello --output =json | jq | grep relro
"relro": "partial"、

Checksecは、以下のコマンドを使用してこの情報を検索します。ここでは、RELROプロパティの1つが有効になっています。したがって、checksecで検証すると、バイナリは「部分的」と表示されます。

 $ 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でコンパイルするときに、次のコマンドライン引数を使用します :

 $ gcc -Wl、-z、relro、-z、now hello.c -o hello 

$ checksec --file =./ hello --output =json | jq | grep relro
"relro": "full"、

これで、2番目のプロパティも有効になり、プログラムが完全に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は別のセキュリティプロパティですが、この記事の範囲外です。 checksecがバイナリでfortifyを検証する方法と、gccでどのように有効にするかについては学習しません。 あなたが取り組むための練習として。

 $ 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機能

セキュリティのトピックは終わりがなく、ここですべてを網羅することはできませんが、checksecのいくつかの機能について言及したいと思います。 一緒に仕事をするのを楽しくするコマンド。

複数のバイナリに対して実行

checksecに個別に各バイナリを提供する必要はありません。代わりに、複数のバイナリが存在するディレクトリパスを指定すると、checksecが一度にすべてのバイナリを検証します。

 $ checksec --dir=/usr/bin 
プロセス

バイナリに加えて、checksecは実行中のプログラムでも機能します。次のコマンドは、システムで実行されているすべてのプログラムのセキュリティプロパティを検索します。 --proc-allを使用できます 実行中のすべてのプロセスをチェックする場合、または名前を使用して特定のプロセスを選択する場合:

 $ checksec --proc-all 

$ checksec --proc =bash
カーネルプロパティ

この記事で説明されているchecksecのユーザーランドアプリケーションに加えて、システムに組み込まれているカーネルプロパティをチェックするためにも使用できます。

 $ checksec --kernel 
試してみてください

Checksecは、どのユーザーランドとカーネルのプロパティが有効になっているかを理解するための良い方法です。各セキュリティプロパティを詳細に調べ、各機能を有効にする理由と、それが防止する攻撃の種類を理解してください。


Linux
  1. Linux カーネルで getnstimeofday を使用する例

  2. mv コマンドを使用して Linux でフォルダーを移動する

  3. Linux でシグナルを使用した IPC

  1. ProcDumpを使用してLinuxをデバッグする

  2. Linuxでのripgrep(rg)コマンドの使用

  3. Linux Deploy を使用した Android 上の Kali Linux

  1. 13Linuxセキュリティチュートリアル

  2. 50 UNIX / Linux システム管理者チュートリアル

  3. Linux での dmsetup コマンドの使用例