Linuxカーネルのアクセス制御セキュリティを強化する方法

Linuxカーネルのアクセス制御セキュリティを強化する方法

背景

以前、当社のプロジェクト チームは、Windows、Linux、macOS の 3 つの主要なオペレーティング システム プラットフォームに関連するオペレーティング システム セキュリティの分野で、お客様のいくつかの問題の解決を支援していました。どのようなオペレーティングシステムであっても、本質的にはソフトウェアです。ソフトウェアは、最初に設計された時点では、人々のニーズを 100% 満たすことはできません。オペレーティングシステムでも同じです。人々のニーズを可能な限り満たすためには、人々がオペレーティングシステムをカスタマイズするための何らかのメカニズムを提供する必要があります。もちろん、公式のメカニズムに加えて、いくつかのブラックマジックもあります。これらのブラックマジックの使用は推奨されていませんが、特定のビジネスシナリオに直面したときに参考として使用できる場合があります。

Linux における一般的な傍受とフィルタリング

この記事では、Linux プラットフォームでよく見られるインターセプションに焦点を当てます。

  • ユーザー モードの動的ライブラリのインターセプション。
  • カーネルモードのシステムコールのインターセプト。
  • スタック可能なファイル システムのインターセプション。
  • インラインフックインターセプション。
  • LSM (Linux セキュリティ モジュール)

動的ライブラリのハイジャック

Linux での動的ライブラリのハイジャックは、主に LD_PRELOAD 環境変数に基づいています。この環境変数の主な機能は、動的ライブラリの読み込み順序を変更し、ユーザーが異なる動的ライブラリ内の同じ関数を選択的に読み込むことができるようにすることです。ただし、不適切な使用は深刻なセキュリティ問題を引き起こします。メイン プログラムやダイナミック リンク ライブラリに他の動的関数をロードするために使用することができ、これにより、他の人のプログラムに悪意のあるコードを挿入する機会が生まれます。

次のようなユーザー名とパスワードの検証機能があるとします。

#include <stdio.h>
#include <文字列.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char passwd[] = "パスワード";
(引数<2)の場合{
printf("無効なargcです!\n");
戻る;
}
(!strcmp(passwd、argv[1]))の場合{
printf("パスワードが正しいです!\n");
戻る;
}
printf("無効なパスワードです!\n");
}

比較が常に正しいことを確認するために、別の hookStrcmp プログラムを作成しましょう。

#include <stdio.h>
int strcmp(const char *s1, const char *s2)
{
/* 常に 0 を返し、2 つの文字列が等しいことを示します */
0を返します。
}

次のコマンドを順番に実行すると、フック プログラムが最初に実行されます。

gcc -Wall -fPIC -shared -o hookStrcmp.so hookStrcmp.c
LD_PRELOAD="./hookStrcmp.so" をエクスポートします

その結果、自分で書いた strcmp 関数が最初に呼び出されることがわかります。これは最も単純なハイジャックですが、geteuid/getuid/getgid のようなものをハイジャックして 0 を返すようにすると、ルート権限を公開するのと同じことになります。したがって、安全上の理由から、LD_PRELOAD 環境変数は通常無効になっています。

Linux システムコールのハイジャック

最近、4.4.0 カーネルには 513 を超えるシステム コール (その多くは一度も使用されたことがない) があることが発見されました。システム コール ハイジャックの目的は、システム内の元のシステム コールを変更し、元のシステム コールを独自のプログラムに置き換えることです。 Linux カーネル内のすべてのシステム コールは、sys_call_table と呼ばれるカーネル配列に配置され、配列の値はシステム コール サービス プログラムのエントリ アドレスを表します。システムコールのプロセス全体は次のとおりです。


ユーザー モードでシステム コールが開始されると、80 ソフト割り込みを介して syscall ハンドラーに入り、次にグローバル システム コール テーブル sys_ call _table に入り、特定のシステム コールを検索します。この配列内のアドレスを独自のプログラム アドレスに変更すると、システム コール ハイジャックを実現できます。ただし、セキュリティ上の理由から、カーネルはこの操作にいくつかの制限を設けています。

  • sys_ call _table のシンボルはエクスポートされず、直接取得することはできません。
  • sys_ call _table が配置されているメモリ ページは読み取り専用であり、直接変更することはできません。

上記の 2 つの問題に対する解決策は次のとおりです (複数の方法があります)。

  • sys call テーブルのアドレスを取得します: grep sys_call_table /boot/System.map-uname -r
  • ページ テーブルの読み取り専用属性は、CR0 レジスタの WP ビットによって制御されます。このビットをクリアすると、読み取り専用ページ テーブルを変更できます。
/* ページを書き込み可能にする */
int make_rw(符号なしロングアドレス)
{
符号なし整数レベル;
pte_t *pte = lookup_address(address, &level);//仮想アドレスが配置されているページ テーブル アドレスを検索します pte->pte |= _PAGE_RW;//ページ テーブルの読み取りおよび書き込み属性を設定します return 0;
}
/* ページを書き込み禁止にする */
int make_ro(符号なしロングアドレス)
{
符号なし整数レベル;
pte_t *pte = lookup_address(アドレス、レベル);
pte->pte &= ~_PAGE_RW; //読み取り専用属性を設定する return 0;
}

システムコールの置き換えを開始する

この記事では、ls コマンドに対応するシステム コールを実装します。システム コール番号は _NR _getdents です。

静的 int syscall_init_module(void)
{
orig_getdents = sys_call_table[__NR_getdents];
make_rw((unsigned long)sys_call_table); //ページ属性を変更するsys_call_table[__NR_getdents] = (unsigned long *)hacked_getdents; //新しいシステムコールアドレスを設定するmake_ro((unsigned long)sys_call_table);
0を返します。
}

復元

静的 void syscall_cleanup_module(void)
{
printk(KERN_ALERT "モジュールのシステムコールがアンロードされました。\n");
make_rw((符号なしlong)sys_call_table);
sys_call_table[__NR_getdents] = (符号なしlong *)orig_getdents;
make_ro((符号なしlong)sys_call_table);
}

Makefile を使用してコンパイルし、insmod を使用してカーネル モジュールを挿入してから ls を実行すると、システム コールが開始されます。フック コード内の特定のファイルを削除できます。ls ではこれらのファイルが表示されませんが、これらのファイルは引き続き存在します。

スタックファイルシステム

Linux は vfs 仮想ファイルシステムを使用して特定のディスクファイルシステムを統合および抽象化し、上から下までスタックのような IO スタックを形成します。カーネル ソース コードを分析すると、読み取り操作を例にとると、上から下に実行されるプロセスは次のようになります。


カーネルは、C 言語の形式、つまり関数ポインタの形式で、多くのオブジェクト指向プログラミングを使用します。たとえば、read は vfs によってユーザーに提供されるインターフェイスであり、その下にある特定の呼び出しは ext2 の読み取り操作です。 VFS が提供するさまざまなインターフェースを実装すれば、スタックファイルシステムを実現できます。いくつかのスタックされたファイルシステムは Linux カーネルに統合されています。たとえば、Ubuntu をインストールするときに、ホームディレクトリを暗号化するように求められます。これは実際にはスタックされた暗号化ファイルシステム (eCryptfs) です。原理は次のとおりです。


スタック ファイル システムが実装されているため、すべての読み取りおよび書き込み操作がファイル システムに入るため、すべてのデータを取得して、インターセプションとフィルタリングを行うことができます。

以下は私が実装した最も単純なスタック ファイル システムです。これは、ファイルを開いて読み書きする最も簡単な方法を実装しています。小さいですが完全です。

https://github.com/wangzhangjun/wzjfs

インラインフック

カーネル内の関数がこの関数内ですべての関数を実装することは不可能であり、下位レベルの関数を呼び出す必要があることはわかっています。この下位レベル関数が、必要なフィルタリングされた情報コンテンツを取得できる場合は、上位レベル関数内の下位レベル関数のオフセットを新しい関数のオフセットに置き換えることができます。このようにして、上位レベル関数が下位レベル関数を呼び出すと、新しい関数にジャンプし、新しい関数でフィルタリングとコンテンツのハイジャックを実行します。したがって、原則として、インライン フックは任意の場所にフックできます。


インライン フックには 2 つの重要な問題があります。

  • フックポイントを見つける方法。
  • フック関数エントリを挿入する方法。

最初の質問について:

カーネルのソース コードに関する経験が必要です。たとえば、読み取り操作の場合、ソース コードは次のようになります。


ここで、read システム コールが開始されると、sys read に入り、sys read 内で vfs read 関数が呼び出されます。vfs read のパラメーターにはフィルタリングに必要な情報が含まれているため、vfs_read をフック ポイントとして使用できます。

2番目の質問について:

フックする方法は?ここに 2 つの方法があります:

最初の方法は、バイナリ置換を直接実行し、呼び出し命令のオペランドをフック関数のアドレスに置き換えることです。


2 番目の方法: Linux カーネルによって提供される kprobes メカニズム。

原理としては、フックポイントに int 3 (x86) のマシンコードを挿入し、CPU がここで実行すると sig trap シグナルがトリガーされ、次にユーザー定義のフック関数を sig trap のコールバック関数に挿入して、フック関数をトリガーするという目的を達成します。これが実はデバッガーの原理です。

エルエスエム

LSM は Linux Secrity Module の略で、Linux セキュリティ モジュールを意味します。これは、高効率、シンプルさ、使いやすさを特徴とする一般的な Linux セキュリティ フレームワークです。仕組みは次のとおりです:

エルエスエム

カーネルでは次の作業が行われます。

  • 特定のカーネル データ構造にセキュリティ ドメインを追加します。
  • カーネル ソース コードのさまざまな重要なポイントにセキュリティ フック関数の呼び出しを挿入します。
  • 共通のセキュリティ システム コールを追加します。
  • カーネル モジュールをセキュリティ モジュールとして登録したり、登録解除したりできるようにする関数が提供されます。
  • 機能ロジックのほとんどは、スケーラビリティのためにオプションのセキュリティ モジュールに移行されます。

適用可能なシナリオ

上記のフックメソッドにはさまざまな適用シナリオがあります。

  • ダイナミック ライブラリのハイジャックは完了していません。ハイジャックされた情報は、私たちのニーズを満たさない可能性があります。また、あなたより前に誰かがハイジャックした可能性もあります。LD_PRELOAD が無効になると、無効になります。
  • システムコールハイジャックでは、struct ファイル構造を取得できない、ファイルの絶対パスを取得できないなど、ハイジャックされた情報が私たちのニーズを満たさない可能性があります。
  • スタックされたファイル システムはマウントに依存しており、システムの再起動が必要になる場合があります。
  • インライン フックは柔軟性が高く、自由にフックできます。再起動せずにすぐに有効になります。ただし、異なるカーネル バージョン間の互換性が低く、一部の関数が変更されるとフックが無効になります。
  • LSM の場​​合、初期のカーネルでは、1 つの LSM カーネル モジュールのみをロードできました。たとえば、SELinux がロードされると、他の LSM モジュールをロードできませんでした。この問題は、最新のカーネル バージョンでは発生しません。

要約する

スペースの制限により、この記事では Linux 上の傍受技術についてのみ紹介します。Windows および macOS 上の傍受技術については、後ほど説明する機会があります。実際、同様の監査フックは、カーネルだけでなく、あらゆるシステムで厳格に要求されています。ますます多くの VM やランタイム、さらには多くの Web コンポーネントやフロントエンド アプリケーションが、より柔軟なフック メソッドを提供していることがわかります。これは、透明性とリアルタイム パフォーマンスという 2 つの主要なセキュリティ トレンドの下で最も一般的なソリューションです。

上記はこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に一定の参考学習価値を持つことを願っています。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM を応援していただきありがとうございます。

以下もご興味があるかもしれません:
  • Linuxカーネルの一般的なリンクリスト学習のまとめ
  • Linux のカーネルリンクリストの例の詳細な説明
  • Linuxカーネルのリンクリスト実装プロセス
  • Linux カーネル デバイス ドライバー proc ファイル システム ノート
  • Linux カーネル デバイス ドライバー 高度な文字デバイス ドライバーのメモ
  • Linux カーネル デバイス ドライバー Linux カーネル モジュールの読み込みメカニズム メモの概要
  • Linux カーネル デバイス ドライバー アドレス マッピングに関する注意事項
  • Linux カーネル デバイス ドライバー Linux カーネル 基本メモの概要
  • Linuxカーネル空間とユーザー空間の実装と分析
  • Linuxカーネルプロセススケジューリング関数schedule()のトリガーと実行タイミングの詳細な説明
  • Linux カーネル デバイス ドライバー カーネル リンク リストの使用上の注意

<<:  InnoDB エンジンのパフォーマンスを最適化するための my.cnf パラメータ構成

>>:  WeChatミニプログラムがシームレスなスクロールを実現

推薦する

XshellがvirtualBox仮想マシンに接続できない問題の解決策

まず、VirtualBox仮想マシンのネットワーク設定モードについて説明します。NAT+ホストオンリ...

HTML で 2 列レイアウトを実装する方法の例 (左側は固定幅、右側は適応幅)

HTMLは2列レイアウトを実装し、左側は固定幅、右側は適応幅です。実装1: <スタイル>...

デザイン理論: コンテンツプレゼンテーションのための 10 のヒント

<br /> テキスト、記号、リンクの3つの側面に焦点を当て、主に中国語で、個人的な執筆...

div を下から上にスライドさせる CSS3 の例

1. まず、CSS3 のターゲット セレクターを使用し、a タグを使用して id セレクターを指定し...

MySQL sql_modeの適切な設定に関する詳細な説明

MySQL sql_modeの適切な設定sql_mode は見落とされやすい変数です。デフォルト値は...

CSSを使用して特別なロゴやグラフィックを実装する

1. はじめに画像は多くのスペースを占め、画像の数が増えるほど管理が難しくなるため、シンプルなラベル...

MySQL スライディング集計/年初来集計の原理と使用例の分析

この記事では、例を使用して、MySQL スライディング集計/年初来集計の原理と使用方法を説明します。...

JS で配列をループする 4 つの方法のまとめ

この記事では、配列を走査する 4 つの方法を比較してまとめます。 for ループ: for (let...

MySQL関数の簡単な紹介

目次1. 数学関数2. 文字列関数3. 日付関数4. 暗号化機能主な MySQL 関数は次のように紹...

動的テーブルを実装するための要素サンプルコード

目次【コード背景】 【コード実装】 #1# -> コード再利用の基本は、再利用可能なコンポーネ...

Windows で mysql-8.0.18-winx64 をインストールするチュートリアル (画像とテキスト付き)

1. インストールパッケージをダウンロードするインストール パッケージは次の場所にあります:参考:...

jQuery はピッカーをシミュレートしてスライド選択効果を実現します

この記事では、スライド選択効果を実現するピッカーをシミュレートするjQueryの具体的なコードを参考...

Linuxはnode.jsを完全に削除し、yumコマンドで再インストールします。

最初のステップ組み込みのパッケージ管理機能で一度削除する yum 削除 nodejs npm -y ...

Win10 での MySQL 8.0.16 のインストールと設定のチュートリアル

1. MySQL 8.0.16を解凍する次の図に示すように、解凍後にdadaフォルダとmy.ini構...

Centos7でのSambaサーバー構成(実戦)

サンバの概要Samba は、Linux および UNIX システム上で SMB プロトコルを実装する...