
2026/01/18 18:36
**Linux向けの無料でオープンソースのルートキット**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Singularityは、マテウス・アルヴェスによってセキュリティ研究のために作られたオープンソースのLinuxルートキットであり、悪意ある侵害を目的としたものではありません。
このルートキットは Ftrace を介してカーネルにステルス的にフックし、システムコールへの直接パッチ適用やCPUトラップ処理検出を回避します。ルートキットはカーネルトレイントフラグをリセットし、自身をモジュール一覧から削除し、追加のモジュールロードをブロックします。また通常の方法ではアンロードできません。
プロセス隠蔽: Singularityは32エントリのPID配列を維持します。PIDは未使用のシグナル(デフォルトで59)または環境変数を介して追加されます。一度プロセスが一覧に登録されると、シグナル、
sysinfo()、およびさまざまなシステムコールへのフックによって、そのプロセスはリスト表示やツールから隠蔽されます。
ファイル隠蔽: フックが
getdents() を介してディレクトリエントリを除去し、stat() を調整してリンクカウントを一貫させ、openat()/readlink() をブロックし、/proc ファイルをフィルタリングします。デフォルトの隠蔽名は「singularity」です。
ネットワーク隠蔽: TCPポート8081(デフォルト)でのトラフィックは、IPv4およびIPv6の両方に対して
netstat とパケットキャプチャから隠蔽されます。
このルートキットはx86/x86_64をサポートし、32ビットと64ビットのシステムコール規約の両方にフックを挿入することで、混合モード環境で疑念が生じないようにします。Ubuntu、CentOS Stream、Debian、およびFedora上のLinux 6.xでテスト済みですが、将来のカーネルアップデートにより内部Ftraceの詳細が変更される可能性があります。
Alvesはログトランケーション、ソースコード破棄、および起動時自動ロード用のスクリプトを提供し、インストール証拠をクリーンにします。最も顕著な指標は
ftrace_enabled の強制です:/proc/sys/kernel/ftrace_enabled に「0」を書き込んでもそれが「1」のままである場合、Singularityの存在を示します。
Alvesは責任ある研究を推奨しています。明示的な許可を得た上でのみテストし、犯罪活動に使用してはいけません。生産システムではFtrace状態とモジュール整合性を監視することが不可欠です。将来のカーネルパッチは新しい検出ポイントを露呈させたり、フック機構を破壊したりする可能性があります。
本文
LWN.netへようこそ
以下のサブスクリプション専用コンテンツは、LWN の購読者によってご提供いただいたものです。数千人の購読者が Linux とフリーソフトウェアコミュニティから最高のニュースを得るために LWN に依存しています。この記事がお役に立ったら、ぜひ LWN を購読してみてください。LWN.net へのご訪問ありがとうございます!
Linux を標的とするルートキットは数多く存在しますが、いずれも Linux ソフトウェアの典型的なオープンソース精神を完全に取り入れているわけではありません。幸いにもマテウス・アルヴェス氏は、Linux システム向けに Singularity というオープンソースルートキットを開発し、この不足を補おうとしています。コンピュータが過剰に安全だと感じるユーザーは、Singularity カーネルモジュールをインストールしてリモートコード実行を許可し、セキュリティ機能を無効化し、通常の管理ツールからファイルやプロセスを隠すことができます。多くの機能を備えているにもかかわらず、Singularity が実際に野外で使用されているという報告はなく、むしろ新しい検出・回避技術を調査するためのテストベッドとしてセキュリティ研究者に提供されています。
アルヴェス氏は Singularity の研究目的を強調しており、その主な目的は「現在可能なこと」を示すことでセキュリティ研究を推進することだと述べています。彼はソフトウェアを使用する人々に対し、「犯罪者ではなく研究者であれ」と呼びかけ、明示的な許可があるシステムのみにテストを行うよう求めています。ただし、もし悪意のある目的で Singularity を利用したいと考える場合でも、コードは MIT ライセンス下で自由に入手できるため、その使用自体が著作権侵害ではなく犯罪となります。
カーネルへのフック取得
システム上で root 権限を得てカーネルモジュールをインストールする方法は Singularity の範囲外です。Singularity は「すでに侵害された状態でどのようにして検知されずに存在し続けるか」に焦点を当てています。そのため、システムが全く変更されていないという錯覚を作り出すために多大な手間を掛けます。具体的には、カーネルの既存 Ftrace 機構を利用して、多数のシステムコールを処理する関数へフックし、その応答を書き換えて存在感を隠します。
Ftrace を使用すると以下のような利点があります。最も重要なのは、CPU のトラップハンドリングベクタを変更せずに済むため、過去にいくつかのルートキットが検出された手法を回避できることです。また、カーネル関数自体を直接パッチする必要もなく、Ftrace 用のフックがすでに存在しているため、機械語レベルで不審な変更を行わずに済みます。もちろん Ftrace は実行時に無効化できますが、Singularity はそれを自動的に有効化し、無効化を試みるとブロックします。
Singularity は「自身の存在」「攻撃者制御プロセス」「そのプロセスとのネットワーク通信」「使用ファイル」の四種類を隠すことに注力しています。自身の存在を隠す方法は比較的簡単で、モジュールがロードされるとカーネルの汚染マーカー(taint)をリセットし、アクティブなモジュールリストから自分自身を除外します。その結果、Singularity は通常のアンロードインタフェースに現れず、アンロードできなくなるほか、後続モジュールのロードも試みるものの失敗するようになります。したがって、アルヴェス氏は Singularity の実験を仮想マシンで行うことを推奨しています。
プロセス隠蔽
プロセスを隠す機構はより複雑です。Singularity はまず「隠すべき」プロセスを特定し、32 個のエントリからなる配列で追跡します。これは、より洗練されたデータ構造が追加メモリアロケーションや遅延を生じさせるため、検出されやすくなる可能性があるからです。
プロセスをリストに追加する方法は二つあります。1 つ目は未使用シグナル(デフォルトで番号 59)を送信し、
kill() システムコールをフックしてそのシグナルを抑制し、対象プロセスを内部リストへ登録するとともに、全体空間で root 権限を付与します。これによりコンテナ内からも攻撃者制御プロセスを追加でき、新しいルート権限でコンテナから脱出できます。2 つ目は環境変数を設定し新規プロセスを起動することで、execve() システムコールを同様にフックします。
一度リストに入ったプロセスでは、シグナル 0(存在確認)や
getpgid(), sched_getaffinity() などの呼び出しもインターセプトされます。また、sysinfo() によって報告される総プロセス数も減算され、一貫性を保ちます。さらに /proc 内のファイルは Singularity のファイル隠蔽コードにより隠されます。この部分がルートキット全体で最も難しい箇所といえるでしょう。
ファイル隠蔽
プログラムが
getdents() を呼び出すと、カーネルはディレクトリエントリをバッファに格納します。Singularity はこのバッファをユーザメモリからコピーし、隠したいエントリを除去して再度ユーザメモリへ戻し、システムコールの戻り値も調整します。カーネルがディレクトリエントリを書き込む前にフックできる場所がないため、この手順はやや複雑です。別スレッドでエントリ読み取りを競合させ、削除されたものを検出する方法も考えられます。
ただしディレクトリエントリ数だけを減算するとシステムの一貫性が損なわれる恐れがあります。Linux ファイルシステムは各ディレクトリに対して参照カウント(子ディレクトリ内の ".." も含む)を持つため、ディレクトリを隠す際には
stat() をフックし親へのリンク数を調整する必要があります。openat() 等で直接隠したディレクトリにアクセスしようとすると失敗します。
シンボリックリンクの解決 (
readlink()) は特別な課題です。実際にはリンク先を開かずに名前を解決するため、別途処理が必要です。また、プロセスの procfs ファイルやユーザー指定パターン(デフォルトでは「singularity」)にマッチするディレクトリも隠します。構築時にこの名前を変更しないと検出が容易になるため、ドキュメントで推奨されています。
高度なファイル隠蔽機構にもかかわらず、Singularity は別コンピュータからのハードディスクフォレンジック調査には対処できません。実行中カーネルにインストールされていない限り何も隠せないためです。そのためドキュメントでは RAM 内の一時ファイルシステムに可能な限り多くの隠しファイルを置き、再起動後に表示されないようにすることを推奨しています。
また、完全に消えると逆に疑念が生じるような痕跡(例:システムログや
kallsyms、enabled_functions など Ftrace プローブの有無を示す procfs ファイル)はファイルシステムレベルで隠さず、代わりに read() 呼び出しをフィルタリングして証拠となる情報を隠します。何が証拠になるかは完全には解決されておらず、現在は既知文字列のマッチングに頼っています。この点もユーザーがビルド時にカスタマイズする必要があります。
ネットワーク活動の隠蔽
攻撃者プロセスとファイルを隠した後でも、コマンド&コントロールサーバへ情報を送ることは通常望まれます。Singularity はデフォルトで TCP ポート 8081(IPv4/IPv6 両方)に対する接続を隠し、そのポートへのパケットキャプチャからも除外します。
netstat 等のツールからは同じファイル隠蔽コードを使って隠されますが、パケット捕捉(ネットワークタップなど)にはカーネルの受信処理にフックする必要があります。
未侵害コンピュータでネットワークタップを走らせている場合、Singularity の隠蔽ポートへの通信は完全に可視化されるため、この点も制御できません。
互換性の重要性
Singularity は x86 と x86_64 にのみ対応し、64 ビットと 32 ビットのシステムコールインタフェースを両方サポートします。これは、64 ビットカーネル上で動作する 32 ビットアプリケーションが異なる結果を受け取ると疑わしくなるためです。この問題を回避するために、Singularity は前述の Ftrace フックを 32 ビットと 64 ビットそれぞれで二重に挿入します。汎用ラッパ関数が 32 ビット呼び出し規約から 64 ビットへ変換して実際のフック実装へ転送します。
Singularity は Ubuntu、CentOS Stream、Debian、Fedora のいくつかのバージョンを含む多様な 6.x カーネルでテスト済みです。ツールは主に Ftrace インタフェースを利用しているため、多くのカーネルでサポートされるべきですが、内部詳細と結合しているためアップデートによって壊れる可能性も常に存在します。
また、インストール時に残った痕跡をクリーンアップするユーティリティスクリプトが付属しています。ログローテーションのような振る舞いを模倣しつつ、分析を妨げるために無音でログを切り詰めるスクリプトや、ローカルでコンパイルされたモジュールを安全に破壊するスクリプト、起動時に自動ロードされるよう設定するスクリプトなどがあります。
総じて Singularity は驚くほど隠密です。何かがおかしいと気付けない人は問題があることを特定しづらいでしょう。ルートキットの最大の特徴は Ftrace を無効化できなくする点で、
/proc/sys/kernel/ftrace_enabled に「0」を書き込んでも内容が「1」のままであれば何かがおかしいと明確に示されます。
この制限を解消したい方はプロジェクトへプルリクエストを送ることを歓迎します。アルヴェス氏はバグ修正、新たな回避手法の提案、検出方法の報告を受け入れています。コード自体がシンプルでモジュール化されているため、自分用にカスタマイズしやすいです。ルートキットで可能なことを実証することで、新たでより優れた検出・防御手段の開発につながるかもしれません。