diff --git a/README.md b/README.md index 9426ad7..50d71d3 100644 --- a/README.md +++ b/README.md @@ -130,14 +130,14 @@ look at [src/windows/config.rs](https://github.com/thewh1teagle/rookie/blob/main | Arc | 2024/08/07 | 2024/08/07 | 2024/08/07 | | Brave | 2024/10/26 | 2024/10/26 | 2024/10/26 | | Cachy | 2024/06/04 | N/A | N/A | -| Chromium | 2024/10/26 | 2024/10/26 | 2023/10/01 | +| Chromium | 2024/10/26 | 2024/10/26 | 2024/03/16 | | Chrome | 2024/10/26 | 2024/10/26 | 2024/03/16 | -| Edge | 2023/10/01 | - | 2023/10/01 | +| Edge | 2023/10/01 | 2024/08/07 | 2024/03/16 | | Firefox | 2024/10/26 | 2023/11/25 | 2024/03/16 | -| IE | N/A | N/A | 23/10/01 | -| LibreWolf | 2023/10/01 | 2023/11/25 | 23/10/01 | -| Opera | 2023/10/01 | - | 23/10/01 | -| Opera GX | N/A | - | 23/10/01 | +| IE | N/A | N/A | 2024/03/16 | +| LibreWolf | 2023/10/01 | 2023/11/25 | 2023/10/01 | +| Opera | 2023/10/01 | - | 2023/10/01 | +| Opera GX | N/A | - | 2023/10/01 | | Safari | N/A | 2023/11/25 | N/A | | Vivaldi | 2023/10/01 | 2023/11/25 | 2023/10/01 | diff --git a/rookie-rs/src/browser/chromium.rs b/rookie-rs/src/browser/chromium.rs index dd594da..7f0a66e 100644 --- a/rookie-rs/src/browser/chromium.rs +++ b/rookie-rs/src/browser/chromium.rs @@ -48,8 +48,7 @@ pub fn chromium_based( if !privilege::user::privileged() { bail!("Chrome cookies from version v130 can be decrypted only when running as admin due to appbound encryption!") } - let key = crate::windows::appbound::get_keys(appbound_key)?; - vec![key] + crate::windows::appbound::get_keys(appbound_key)? } else { get_keys(legacy_key)? }; @@ -161,21 +160,30 @@ fn decrypt_encrypted_value( let ciphertext = &encrypted_value[12..]; // Create a new AES block cipher. - if let Some(key) = keys.into_iter().next() { + for key in keys { let key = Key::::from_slice(key.as_slice()); let cipher = Aes256Gcm::new(key); let nonce = GenericArray::from_slice(nonce); // 96-bits; unique per message - let plaintext = cipher - .decrypt(nonce, ciphertext.as_ref()) - .map_err(eyre::Error::msg) - .context("Can't decrypt using key")?; - let plaintext = if key_type == b"v20" { - String::from_utf8(plaintext[32..].to_vec()).context("Can't decode encrypted value") - } else { - String::from_utf8(plaintext).context("Can't decode encrypted value") - }?; - return Ok(plaintext); + match cipher.decrypt(nonce, ciphertext.as_ref()) { + Ok(plaintext) => { + // Successfully decrypted, try to convert to string + let plaintext = if key_type == b"v20" { + String::from_utf8(plaintext[32..].to_vec()).context("Can't decode encrypted value") + } else { + String::from_utf8(plaintext).context("Can't decode encrypted value") + }; + + match plaintext { + Ok(text) => return Ok(text), + Err(e) => log::warn!("Failed to decode plaintext: {}", e), + } + } + Err(e) => { + log::warn!("Failed to decrypt with a key: {}", e); + continue; + } + } } bail!("decrypt_encrypted_value failed") } diff --git a/rookie-rs/src/windows/appbound.rs b/rookie-rs/src/windows/appbound.rs index b1af4dc..eaff62c 100644 --- a/rookie-rs/src/windows/appbound.rs +++ b/rookie-rs/src/windows/appbound.rs @@ -6,7 +6,7 @@ wget.exe https://github.com/thewh1teagle/rookie/releases/download/appbound-binar cargo build --release --features appbound */ use base64::{prelude::BASE64_STANDARD, Engine}; -use eyre::{bail, Context, Result}; +use eyre::{bail, eyre, Context, Result}; use std::fs; use std::process::{Command, Stdio}; @@ -50,7 +50,9 @@ fn decrypt(key_b64: &str, as_system: bool) -> Result { Ok(result.trim().to_string()) } -pub fn get_keys(key64: &str) -> Result> { +pub fn get_keys(key64: &str) -> Result>> { + let mut keys: Vec> = Vec::new(); + let key_u8 = BASE64_STANDARD.decode(key64)?; if !key_u8.starts_with(b"APPB") { bail!("key not starts with APPB") @@ -60,20 +62,26 @@ pub fn get_keys(key64: &str) -> Result> { let system_decrypted = decrypt(&key64, true)?; let user_decrypted = decrypt(system_decrypted.trim(), false)?; let key = BASE64_STANDARD.decode(user_decrypted)?; - let decrypted_key = &key[key.len() - 61..]; - if decrypted_key[0] != 1 { - bail!("key[0] != 1") - } + // Most chrome browsers can use the system->user decrypted key directly (last 32 bytes) + keys.push(key[key.len() - 32..].to_vec()); + + // Chrome also decrypt the decrypted key with hardcoded AES key from elevation_service.exe + let decrypted_key = &key[key.len() - 61..]; let aes_key = BASE64_STANDARD.decode("sxxuJBrIRnKNqcH6xJNmUc/7lE0UOrgWJ2vMbaAoR4c=")?; let iv = &decrypted_key[1..1 + 12]; let mut ciphertext = decrypted_key[1 + 12..1 + 12 + 32].to_vec(); let tag = &decrypted_key[1 + 12 + 32..]; ciphertext.extend(tag); - let aes_key = Key::::from_slice(&aes_key); let cipher = Aes256Gcm::new(aes_key); let nonce = GenericArray::from_slice(iv); // 96-bits; unique per message - let plain = cipher.decrypt(nonce, ciphertext.as_slice()).unwrap(); - Ok(plain) + if let Ok(plain) = cipher + .decrypt(nonce, ciphertext.as_slice()) + .map_err(|e| eyre!("{:?}", e)) + { + keys.push(plain) + } + + Ok(keys) }