Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added U-Boot version signature, fixed openssl signature validation #782

Merged
merged 2 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,40 @@ pub fn get_cstring(raw_data: &[u8]) -> String {
string
}

/// Returns true if the provided byte is an ASCII number
///
/// ## Example
///
/// ```
/// use binwalk::common::is_ascii_number;
///
/// assert!(is_ascii_number(0x31));
/// assert!(!is_ascii_number(0xFE));
/// ```
pub fn is_ascii_number(b: u8) -> bool {
const ZERO: u8 = 48;
const NINE: u8 = 57;

(ZERO..=NINE).contains(&b)
}

/// Returns true if the provided byte is a printable ASCII character
///
/// ## Example
///
/// ```
/// use binwalk::common::is_printable_ascii;
///
/// assert!(is_printable_ascii(0x41));
/// assert!(!is_printable_ascii(0xFE));
/// ```
pub fn is_printable_ascii(b: u8) -> bool {
const ASCII_MIN: u8 = 0x0A;
const ASCII_MAX: u8 = 0x7E;

(ASCII_MIN..=ASCII_MAX).contains(&b)
}

/// Validates data offsets to prevent out-of-bounds access and infinite loops while parsing file formats.
///
/// ## Notes
Expand Down
11 changes: 11 additions & 0 deletions src/magic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,17 @@ pub fn patterns() -> Vec<signatures::common::Signature> {
description: signatures::android_bootimg::DESCRIPTION.to_string(),
extractor: None,
},
// uboot
signatures::common::Signature {
name: "uboot".to_string(),
short: false,
magic_offset: 0,
always_display: true,
magic: signatures::uboot::uboot_magic(),
parser: signatures::uboot::uboot_parser,
description: signatures::uboot::DESCRIPTION.to_string(),
extractor: None,
},
];

binary_signatures
Expand Down
1 change: 1 addition & 0 deletions src/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ pub mod tarball;
pub mod tplink;
pub mod trx;
pub mod ubi;
pub mod uboot;
pub mod uefi;
pub mod uimage;
pub mod vxworks;
Expand Down
25 changes: 20 additions & 5 deletions src/signatures/openssl.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::common::is_printable_ascii;
use crate::signatures::common::{
SignatureError, SignatureResult, CONFIDENCE_LOW, CONFIDENCE_MEDIUM,
};
Expand All @@ -24,13 +25,10 @@ pub fn openssl_crypt_parser(
..Default::default()
};

// This "salt" value are the bytes commonly found in the openssl binary itself
let known_false_positive_salts: Vec<usize> = vec![0x2D252D32];

// Parse the header
if let Ok(openssl_header) = parse_openssl_crypt_header(&file_data[offset..]) {
// Check common false positive salt values
if !known_false_positive_salts.contains(&openssl_header.salt) {
// Sanity check the salt value
if !is_salt_invalid(openssl_header.salt) {
// If the magic starts at the beginning of a file, our confidence is a bit higher
if offset == 0 {
result.confidence = CONFIDENCE_MEDIUM;
Expand All @@ -44,3 +42,20 @@ pub fn openssl_crypt_parser(

Err(SignatureError)
}

// Returns true if the salt is entirely comprised of NULL and/or ASCII bytes
fn is_salt_invalid(salt: usize) -> bool {
const SALT_LEN: usize = 8;

let mut bad_byte_count: usize = 0;

for i in 0..SALT_LEN {
let salt_byte = ((salt >> (8 * i)) & 0xFF) as u8;

if salt_byte == 0 || is_printable_ascii(salt_byte) {
bad_byte_count += 1;
}
}

bad_byte_count == SALT_LEN
}
37 changes: 37 additions & 0 deletions src/signatures/uboot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::common::{get_cstring, is_ascii_number};
use crate::signatures::common::{SignatureError, SignatureResult, CONFIDENCE_MEDIUM};

/// Human readable description
pub const DESCRIPTION: &str = "U-Boot version string";

/// U-Boot version number magic bytes
pub fn uboot_magic() -> Vec<Vec<u8>> {
vec![b"U-Boot\x20".to_vec()]
}

/// Validates the U-Boot version number magic
pub fn uboot_parser(file_data: &[u8], offset: usize) -> Result<SignatureResult, SignatureError> {
const NUMBER_OFFSET: usize = 7;

// Successful return value
let mut result = SignatureResult {
offset,
description: DESCRIPTION.to_string(),
confidence: CONFIDENCE_MEDIUM,
..Default::default()
};

if let Some(expected_number_byte) = file_data.get(offset + NUMBER_OFFSET) {
if is_ascii_number(*expected_number_byte) {
let uboot_version_string = get_cstring(&file_data[offset + NUMBER_OFFSET..]);

if !uboot_version_string.is_empty() {
result.size = uboot_version_string.len();
result.description = format!("{}: {}", result.description, uboot_version_string);
return Ok(result);
}
}
}

Err(SignatureError)
}