Unverified Commit e74d0fd8 by Enkelmann Committed by GitHub

reimplement CWE 215 check in Rust (#121)

parent a3093dcb
......@@ -3,7 +3,7 @@ use cwe_checker_rs::utils::log::print_all_messages;
use cwe_checker_rs::utils::{get_ghidra_plugin_path, read_config_file};
use cwe_checker_rs::AnalysisResults;
use std::collections::HashSet;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::Command;
use structopt::StructOpt;
......@@ -136,10 +136,17 @@ fn run_with_ghidra(args: CmdlineArgs) {
filter_modules_for_partial_run(&mut modules, partial_module_list);
}
let mut project = get_project_from_ghidra(&Path::new(&args.binary.unwrap()));
let binary_file_path = PathBuf::from(args.binary.unwrap());
let binary: Vec<u8> = std::fs::read(&binary_file_path).unwrap_or_else(|_| {
panic!(
"Error: Could not read from file path {}",
binary_file_path.display()
)
});
let mut project = get_project_from_ghidra(&binary_file_path);
// Normalize the project and gather log messages generated from it.
let mut all_logs = project.normalize();
let mut analysis_results = AnalysisResults::new(&project);
let mut analysis_results = AnalysisResults::new(&binary, &project);
let modules_depending_on_pointer_inference = vec!["CWE243", "CWE367", "CWE476", "Memory"];
let pointer_inference_results = if modules
......
......@@ -16,6 +16,7 @@ anyhow = "1.0" # for easy error types
crossbeam-channel = "0.4"
derive_more = "0.99"
directories = "3.0"
goblin = "0.2"
[lib]
name = "cwe_checker_rs"
......
pub mod cwe_190;
pub mod cwe_215;
pub mod cwe_243;
pub mod cwe_332;
pub mod cwe_367;
......
//! This module implements a check for CWE-215: Information Exposure Through Debug Information.
//!
//! Sensitive debugging information can be leveraged to get a better understanding
//! of a binary in less time.
//!
//! See <https://cwe.mitre.org/data/definitions/215.html> for a detailed description.
//!
//! ## How the check works
//!
//! For ELF binaries we check whether they contain sections containing debug information.
//! Other binary formats are currently not supported by this check.
//!
//! ## False Positives
//!
//! None known.
//!
//! ## False Negatives
//!
//! None known.
use crate::prelude::*;
use crate::utils::log::{CweWarning, LogMessage};
use crate::CweModule;
pub static CWE_MODULE: CweModule = CweModule {
name: "CWE215",
version: "0.2",
run: check_cwe,
};
/// Run the check.
///
/// We simply check whether the ELF file still contains sections whose name starts with `.debug`.
/// Binary formats other than ELF files are currently not supported by this check.
pub fn check_cwe(
analysis_results: &AnalysisResults,
_cwe_params: &serde_json::Value,
) -> (Vec<LogMessage>, Vec<CweWarning>) {
let binary = analysis_results.binary;
match goblin::Object::parse(binary) {
Ok(goblin::Object::Elf(elf_binary)) => {
for section_header in elf_binary.section_headers {
if let Some(Ok(section_name)) = elf_binary.shdr_strtab.get(section_header.sh_name) {
if section_name.starts_with(".debug") {
let cwe_warning = CweWarning::new(
CWE_MODULE.name,
CWE_MODULE.version,
"(Information Exposure Through Debug Information) The binary contains debug symbols."
);
return (Vec::new(), vec![cwe_warning]);
}
}
}
(Vec::new(), Vec::new())
}
Ok(_) => {
let info_log = LogMessage::new_info(
"File type not supported. Currently this check only supports ELF files.",
)
.source(CWE_MODULE.name);
(vec![info_log], Vec::new())
}
Err(err) => {
let err_log = LogMessage::new_error(format!("Error while parsing binary: {}", err))
.source(CWE_MODULE.name);
(vec![err_log], Vec::new())
}
}
}
......@@ -55,6 +55,7 @@ impl std::fmt::Display for CweModule {
pub fn get_modules() -> Vec<&'static CweModule> {
vec![
&crate::checkers::cwe_190::CWE_MODULE,
&crate::checkers::cwe_215::CWE_MODULE,
&crate::checkers::cwe_243::CWE_MODULE,
&crate::checkers::cwe_332::CWE_MODULE,
&crate::checkers::cwe_367::CWE_MODULE,
......@@ -72,6 +73,8 @@ pub fn get_modules() -> Vec<&'static CweModule> {
/// that may be needed as input for other analyses and CWE checks.
#[derive(Clone, Copy)]
pub struct AnalysisResults<'a> {
/// The content of the binary file
pub binary: &'a [u8],
/// A pointer to the project struct
pub project: &'a Project,
/// The result of the pointer inference analysis if already computed.
......@@ -80,8 +83,9 @@ pub struct AnalysisResults<'a> {
impl<'a> AnalysisResults<'a> {
/// Create a new `AnalysisResults` struct with only the project itself known.
pub fn new(project: &'a Project) -> AnalysisResults<'a> {
pub fn new(binary: &'a [u8], project: &'a Project) -> AnalysisResults<'a> {
AnalysisResults {
binary,
project,
pointer_inference: None,
}
......
......@@ -200,6 +200,24 @@ mod tests {
#[test]
#[ignore]
fn cwe_215() {
let mut error_log = Vec::new();
let tests = linux_test_cases("cwe_476", "CWE215"); // We use the test binaries of another check here.
for test_case in tests {
let num_expected_occurences = 1;
if let Err(error) = test_case.run_test("[CWE215]", num_expected_occurences) {
error_log.push((test_case.get_filepath(), error));
}
}
if !error_log.is_empty() {
print_errors(error_log);
panic!();
}
}
#[test]
#[ignore]
fn cwe_243() {
let mut error_log = Vec::new();
let mut tests = linux_test_cases("cwe_243", "CWE243");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment