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ミニプログラムがシームレスなスクロールを実現

推薦する

Dockerのデフォルトネットワークセグメントを変更する実装方法の分析

背景同社のサーバーはすべて Alibaba Cloud ECS ホストを購入しています。デフォルトの...

js で継承を実装する 5 つの方法

コンストラクタの借用この手法の基本的な考え方は単純です。サブタイプ コンストラクター内からスーパータ...

MySQL がデータの削除と挿入に非常に時間がかかる問題の解決策

会社の開発者がテスト環境で挿入ステートメントを実行すると、正常に実行されるまでに 10 秒以上かかり...

HTML 順序なしリスト 箇条書き 画像を使用した CSS の記述

少なくとも 5 冊のベストセラー書籍の順序なしリストを含む HTML ページを作成します。各書籍の前...

HTML の基礎必読 - CSS スタイルシートの包括的な理解

CSS (カスケーディング スタイル シート) は、HTML Web ページを美しくするために使用さ...

MYSQLデータベーステーブル構造の最適化方法の詳細な説明

この記事では、例を使用して、MYSQL データベース テーブル構造を最適化する方法を説明します。ご参...

Dockerでランナーコンテナを構成する方法

1. ランナーコンテナを作成する mk@mk-pc:~/Desktop$ docker run -d...

簡潔なReactコンポーネントを書くためのヒント

目次スプレッド演算子を使用してプロパティを渡すのは避けてください関数パラメータをオブジェクトにカプセ...

Win10 に Tomcat サーバーをインストールし、環境変数を構成する詳細なチュートリアル (画像とテキスト)

目次JDKをダウンロードしてインストールするTomcat 圧縮パッケージをダウンロードTomcatの...

CSS はコンテナ レベル (div...) タグを 1 つの位置 (ページの右端) に固定します。

コードは次のようになります。 。プロセス{ 境界線:1px 実線 #B7B7B8; 背景:#F8F8...

Windows で IP アドレスを指定してサーバーへのリモート アクセスを設定する方法

当社には、外部ネットワークからの干渉を受けることが多いサーバーが多数あります。侵入者はポート 338...

標準SQL更新ステートメントの3つの用途についての簡単な理解

1. 環境: MySQL-5.0.41-win32 Windows XP プロフェッショナル2. テ...

ドメイン名を介してプロジェクトにアクセスするnginx + tomcatの例

ドメイン名を使ってプロジェクトにアクセスする方法が気になったのですが、自分でドメイン名を取得するのは...

Linux のさまざまなロックメカニズムの使用方法と違いについて詳しく説明します

序文:この知識を理解する必要がある人は、すでにプロセス間通信とスレッド間通信の基本的な理解を持ってい...

自己終了XHTMLタグを書くときに注意すべきこと

XHTML の img タグはいわゆる自己終了タグであり、XML では完全に合法です。 XHTMLの...