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

推薦する

独自のサーバーを素早く構築する方法の詳細なチュートリアル(Java 環境)

1. サーバーの購入1. 私はAlibaba Cloudのサーバーを選択しました。学生向けで月額9...

Linux deb パッケージの解凍、変更、その他の操作方法のコード例

さまざまな理由により、debパッケージ内のさまざまなファイルの内容を直接変更する必要がある場合があり...

vue router-view のネストされた表示実装

目次1. ルーティング構成2. Vueページのネスト3. ネストされた関係1. ルーティング構成 定...

JavaScript 配列 sort() メソッドの基本的な使い方と落とし穴

序文日常のコード開発では、配列のソートに関連する操作が多数あります。JavaScript では、so...

HTML ページジャンプコード

次のコードを index.html などのデフォルトのホームページ ファイルとして保存し、ルート デ...

Linuxディレクトリ構造の詳細な紹介

Linuxを学び始めるときは、まずLinuxの標準ディレクトリ構造を理解する必要があります。 / r...

Hbase 入門

1. HBaseの概要1.1 HBaseとはHBase は、高い信頼性、高いパフォーマンス、列ストレ...

nginx のフロントエンドとバックエンドに同じドメイン名を設定する方法

この記事では、主にnginxのフロントエンドとバックエンドに同じドメイン名を設定する方法を紹介し、皆...

セマンティックウェブページ XHTML セマンティックマークアップ

構造とプレゼンテーションを分離するもう 1 つの重要な側面は、セマンティック マークアップを使用して...

MySQL の組み込み関数 find_in_set を使用した効率的なあいまい検索の詳細な説明

一般的に使用される方法は次の 4 つです。 1.locate()メソッドを使用する一般的な使用法: ...

CSS でホバー ドロップダウン メニューを実装する方法

いつものように、今日は非常に実用的な CSS 効果についてお話します。マウスがボタンに移動すると、ド...

いくつかの CSS3 タグの短縮形 (推奨)

border-radius: CSS3 丸い角構文: border-radius: 25px;楕円...

CentOS 8 に Docker をインストールする詳細なチュートリアル

1. 以前のバージョン yum 削除 docker docker-client docker-cli...

Kali Linux インストール VMware ツールのインストール プロセスと VM インストール vmtools ボタン グレー

Xiaobai は vmtools のインストールを記録します。 1. 意義と機能: VMWARE ...

JavaScript データ構造 双方向リンクリスト

単方向リンク リストは、先頭から末尾、または末尾から先頭への方向のみを走査できます。そのため、単方向...