Skip to content

Commit

Permalink
Merge pull request ReFirmLabs#782 from ReFirmLabs/uboot_version
Browse files Browse the repository at this point in the history
Added U-Boot version signature, fixed openssl signature validation
  • Loading branch information
devttys0 authored Nov 29, 2024
2 parents 9bc9ccf + 7fe81a3 commit f4716ef
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 5 deletions.
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)
}

0 comments on commit f4716ef

Please sign in to comment.