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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
freebsd-dirent-info-leak-bugs — CVE-2020-25578 および CVE-2020-25579: 2020年に私が発見したFreeBSDの情報漏洩バグです。 | Kitploit
ツール/GitHubGitHub/farazsth98/freebsd-dirent-info-leak-bugs
メモリフォレンジック脆弱性分析エクスプロイト情報収集バイナリ解析
GitHubfarazsth98/freebsd-dirent-info-leak-bugs

freebsd-dirent-info-leak-bugs

CVE-2020-25578 および CVE-2020-25579: 2020年に私が発見したFreeBSDの情報漏洩バグです。

リポジトリを見る

人気

すべて見る →

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

すべてのツールを探索

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

すべてのツールを見る →
共有
7225年前未レビュー

どのようにバグを見つけたか?

  1. ランダムにFreeBSDのファイルシステムを監査しようと決める
  2. 調査して、使用されているデフォルトのファイルシステムがFFSとUFSの組み合わせであることを発見
  3. ufs_create の監査に時間を費やし、バグを0件発見
  4. ここ にアクセスし、UFSファイルシステム関数のコミット履歴を調べる
  5. スタックに割り当てられた struct dirent オブジェクトのパディングバイトを介して情報が漏洩するこのコミット を見つける
  6. パッチを分析し、msdosfs_readdir へのパッチが不完全であることを発見。バグの1つのインスタンスにはパッチを当てたが、2つ目には当てていなかった。
  7. PoCを作成し、パディングから3バイトを漏洩できることを確認。その後、亜種を探し始める。
  8. mqueuefs、autofs、smbfs、tmpfs において、完全な8バイトのポインタを漏洩できる亜種を発見。確認のためのPoCを作成。

元のバグ

上記のように、私が見つけた元のバグは、関連するコミットのパッチを分析中に msdosfs_readdir にありました。

FreeBSDで readdir を呼び出す基本的な流れは以下の通りです:

root@kitploit:~
#include <dirent.h>

int main(void) {
    struct dirent *dp;
    DIR *dirp;

    dirp = opendir("./somedir");
    dp = readdir(dirp);
}

somedir が存在するファイルシステムに応じて、FreeBSDカーネルの多くの *_readdir 関数のいずれかが呼び出される可能性があります。

上記のパッチでは、struct dirent オブジェクトをユーザー空間に返す前に呼び出されることを意図した dirent_terminate 関数が追加されています(多くの場合 uiomove 関数を使用して行われます)。この関数は、パディングバイトと構造体の d_name フィールドの残りのバイトをゼロにします。struct dirent の定義はこちら。

パッチを見ると、1562行目で dirbuf 変数を引数として dirent_terminate が呼び出されていることがわかります。続いて、uiomove が呼び出され、dirbuf の内容をユーザー空間にコピーします。しかし、これらのコード行はこのif文のブロック内にあることに注意してください。このif文の上のコメントは、この分岐はMSDOSファイルシステムのルートで readdir が呼び出された場合にのみ取られることを説明しています。したがって、ファイルシステムのルートより先の任意のサブディレクトリで readdir を呼び出すことで、このif文を簡単にスキップできます。

さらに下の方で、1691行目に uiomove への別の呼び出しがあります。しかし、コードを注意深く読むと、このインスタンスでは dirent_terminate が呼び出されていないことがわかります。つまり、パディングバイトは初期化されないままになります。残念ながら、d_name フィールドはこの関数の開始時にゼロにされていたため(ここ)、より大きな漏洩を得ることはできません。

PoC

まず、USBドライブを持っていなかったので、MSDOSファイルシステムをマウントする方法を考え出す必要がありました。以下が動作します:

root@kitploit:~
$ dd if=/dev/zero of=test.img bs=512 count=256000
$ sudo mdconfig -a -t vnode -f test.img
$ sudo newfs_msdos -s 131072000 /dev/md1 # My mdconfig returned md1
$ mkdir ./temp
$ sudo mount -t msdosfs /dev/md1 ./temp
$ mkdir ./temp/test_dir

PoCは original_poc.c にあります。clang でコンパイルして上記のコマンドと同じディレクトリから実行するだけで、漏洩したバイトが表示されます。

亜種

このバグの亜種を探し始めました。uiomove\(&.*, をgrepしただけで、約15~20件の結果が返ってきて、すべて手動で確認しました。残念ながら、これらの亜種はデフォルトのFreeBSDには存在しません(ファイルシステムは手動で有効化/カーネルにコンパイルする必要があります)。亜種が存在する関数は以下の通りです:

  1. mqfs_readdir
  2. tmpfs_dir_getdotdent
  3. tmpfs_dir_getdotdotdent
  4. smbfs_readvdir
  5. autofs_readdir_one

これらの関数すべてでバグはまったく同じなので、mqfs_readdir のみを取り上げます。

  1. まず、スタックに struct dirent entry が割り当てられます
  2. 次に、dirent_terminate が呼び出され、構造体のパディングと d_name フィールドをゼロにします
  3. 最後に、vfs_read_dirent が呼び出されます。この関数は uiomove を呼び出して構造体をユーザー空間にコピーします

ここまではすべて問題なさそうですよね? 必ずしもそうとは限りません。構造体のすべてのフィールドが初期化されていることを確認する必要があります。コードをよく見ると、d_off フィールドが初期化されていないままになっていることがわかります。このフィールドの型は off_t で、実質的には int64_t です。構造体がユーザー空間にコピーされると、このフィールドに初期化されていないデータが含まれます。

PoC

この同じPoCはすべての亜種で動作します。異なるファイルシステム上で実行するだけです。mqueuefs の場合は、以下の手順を実行します(最初に mqueuefs を有効化/カーネルにコンパイルする必要があります):

root@kitploit:~
$ mkdir ./temp
$ sudo mount -t mqueuefs null ./temp

PoC自体は variants_poc.c にあります。clang でコンパイルして上記のコマンドと同じディレクトリから実行するだけです。カーネルポインタが表示されます(おそらく1つのスタックポインタと1つのコードセクション/ヒープポインタですが、確認していません)。

ツールをダウンロード