diff --git a/check_project.sh b/check_project.sh index f776ff444..f62aff9e8 100755 --- a/check_project.sh +++ b/check_project.sh @@ -117,7 +117,8 @@ import_emba_main() { dockerchecker() { - echo -e "\\n""$ORANGE""$BOLD""EMBA docker-files check""$NC""\\n""$BOLD""=================================================================""$NC" + echo -e "\\n""$ORANGE""$BOLD""EMBA docker-files check""$NC" + echo -e "$BOLD""=================================================================""$NC" mapfile -t DOCKER_COMPS < <(find . -maxdepth 1 -iname "docker-compose*.yml") for DOCKER_COMP in "${DOCKER_COMPS[@]}"; do echo -e "\\n""$GREEN""Run docker check on $DOCKER_COMP:""$NC""\\n" @@ -132,7 +133,8 @@ dockerchecker() { } check() { - echo -e "\\n""$ORANGE""$BOLD""Embedded Linux Analyzer Shellcheck""$NC""\\n""$BOLD""=================================================================""$NC" + echo -e "\\n""$ORANGE""$BOLD""Embedded Linux Analyzer Shellcheck""$NC" + echo -e "$BOLD""=================================================================""$NC" echo -e "\\n""$GREEN""Load all files for check:""$NC""\\n" @@ -280,8 +282,9 @@ check dockerchecker summary -if [[ "${#MODULES_TO_CHECK_ARR_TAB[@]}" -gt 0 ]] || [[ "${#MODULES_TO_CHECK_ARR[@]}" -gt 0 ]] || [[ "${#MODULES_TO_CHECK_ARR[@]}" -gt 0 ]] || \ - [[ "${#MODULES_TO_CHECK_ARR_SEMGREP[@]}" -gt 0 ]] || [[ "${#MODULES_TO_CHECK_ARR_DOCKER[@]}" -gt 0 ]] || [[ "${#MODULES_TO_CHECK_ARR_PERM[@]}" -gt 0 ]] || \ +if [[ "${#MODULES_TO_CHECK_ARR_TAB[@]}" -gt 0 ]] || [[ "${#MODULES_TO_CHECK_ARR[@]}" -gt 0 ]] || \ + [[ "${#MODULES_TO_CHECK_ARR[@]}" -gt 0 ]] || [[ "${#MODULES_TO_CHECK_ARR_SEMGREP[@]}" -gt 0 ]] || \ + [[ "${#MODULES_TO_CHECK_ARR_DOCKER[@]}" -gt 0 ]] || [[ "${#MODULES_TO_CHECK_ARR_PERM[@]}" -gt 0 ]] || \ [[ "${#MODULES_TO_CHECK_ARR_COMMENT[@]}" -gt 0 ]]; then exit 1 fi diff --git a/config/bin_version_strings.cfg b/config/bin_version_strings.cfg index f72e892d0..56bc29d15 100644 --- a/config/bin_version_strings.cfg +++ b/config/bin_version_strings.cfg @@ -548,7 +548,7 @@ quagga;;gpl;"^(ldpd|linkd)\ version\ 0\.9[\.0-9]+$";"sed -r 's/(ldpd|linkd)\ ver quagga;;gpl;"^Hello,\ this\ is\ Quagga\ \(version\ [0-9](\.[0-9]+)+?\)\.$";"sed -r 's/Hello,\ this\ is\ Quagga\ \(version\ ([0-9](\.[0-9]+)+?)\)\.$/quagga:\1/'"; #quik;;unknown;"QUIK\ version\ [0-9]\.[0-9]+";"NA"; qdiscman;;unknown;"^qdiscman\ [0-9](\.[0-9]+)+?\ release$";"sed -r 's/qdiscman\ ([0-9](\.[0-9]+)+?)$/qdiscman:\1/'"; -radlogin;;unknown;"radlogin\.c,v\ [0-9]\.[0-9]+\ [0-9]+";"sed -r 's/radlogin\.c,v\ ([0-9](\.[0-9]+)+?)$/radlogin:\1/'"; +radlogin;;unknown;"radlogin\.c,v\ [0-9]\.[0-9]+\ [0-9]+";"sed -r 's/radlogin\.c,v\ ([0-9](\.[0-9]+)+?).*/radlogin:\1/'"; radvd;strict;radvd-lic;"Version:\ [0-9]\.[0-9]+$";"sed -r 's/Version:\ ([0-9](\.[0-9]+)+?)$/radvd:\1/'"; radvd;strict;radvd-lic;"Version:\ [0-9]\.[0-9]+\.[0-9]+$";"sed -r 's/Version:\ ([0-9](\.[0-9]+)+?)$/radvd:\1/'"; radvdump;strict;radvd-lic;"Version:\ [0-9]\.[0-9]+$";"sed -r 's/Version:\ ([0-9](\.[0-9]+)+?)$/radvd:\1/'"; diff --git a/config/report_templates/F20_vul_aggregator-post.sh b/config/report_templates/F20_vul_aggregator-post.sh index 412c5e490..17f547a18 100755 --- a/config/report_templates/F20_vul_aggregator-post.sh +++ b/config/report_templates/F20_vul_aggregator-post.sh @@ -12,6 +12,10 @@ print_output "$(indent "${ORANGE}S$NC - PoC code found on Snyk vulnerability dat write_link "https://security.snyk.io/vuln" print_output "$(indent "${ORANGE}X$NC - Vulnerability is known as exploited")" write_link "https://www.cisa.gov/known-exploited-vulnerabilities-catalog" +if [[ -f "$LOG_DIR"/s26_kernel_vuln_verifier.txt ]]; then + print_output "$(indent "${ORANGE}V$NC - Kernel vulnerability was verified from module s26")" + write_link "s26" +fi print_ln print_ln print_output "[*] Source notes:" diff --git a/config/report_templates/S26_kernel_vuln_verifier-post.sh b/config/report_templates/S26_kernel_vuln_verifier-post.sh new file mode 100755 index 000000000..b40b78e7f --- /dev/null +++ b/config/report_templates/S26_kernel_vuln_verifier-post.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +print_output "[*] Exploitability notes:" +print_output "$(indent "${ORANGE}EDB$NC - Exploit code found in the Exploit database")" +write_link "https://exploit-db.com" +print_output "$(indent "${ORANGE}MSF$NC - Exploit code found in the Metasploit framework")" +write_link "https://github.com/rapid7/metasploit-framework" +print_output "$(indent "${ORANGE}GH$NC - PoC code found on Github (via trickest)")" +write_link "https://github.com/trickest/cve" +print_output "$(indent "${ORANGE}PS$NC - PoC code found on Packetstormsecurity")" +write_link "https://packetstormsecurity.com/files/tags/exploit/" +print_output "$(indent "${ORANGE}SNYK$NC - PoC code found on Snyk vulnerability database")" +write_link "https://security.snyk.io/vuln" +print_output "$(indent "${ORANGE}EXP$NC - Vulnerability is known as exploited")" +write_link "https://www.cisa.gov/known-exploited-vulnerabilities-catalog" diff --git a/docker-compose.yml b/docker-compose.yml index fb16cd666..80e93b3f7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,12 +40,12 @@ services: - ${FIRMWARE}/:/firmware:ro - ${LOG}/:/logs - ${EMBA}/:/emba:ro + - ${EMBA}/external/linux_kernel_sources/:/external/linux_kernel_sources:ro - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro - /dev:/dev - /lib/modules:/lib/modules:ro - /boot:/boot:ro - # - /home/m1k3/github-repos/EMBA-emulation-binaries:/external/EMBA_Live_bins/:ro environment: - USER devices: diff --git a/emba.sh b/emba.sh index dbe67b894..406983e3d 100755 --- a/emba.sh +++ b/emba.sh @@ -415,7 +415,8 @@ main() welcome # Print EMBA welcome message if [[ $# -eq 0 ]]; then - print_output "\\n""$ORANGE""In order to be able to use EMBA, you have to specify at least a firmware (-f).\\nIf you don't set a log directory (-l), then ./logs will be used.""$NC" "no_log" + print_output "\\n""$ORANGE""In order to be able to use EMBA, you have to specify at least a firmware (-f)." "no_log" + print_output "If you don't set a log directory (-l), then ./logs will be used.""$NC" "no_log" print_help exit 1 fi @@ -656,6 +657,14 @@ main() create_log_dir fi + # kernel downloader runs on the host and waits for an identified kernel version. Afterwards + # it tries to download the kernel sources for further analysis + if [[ $IN_DOCKER -eq 0 ]]; then + kernel_downloader & + K_DOWN_PID="$!" + print_output "[*] Started kernel downloader thread with PID $K_DOWN_PID" "no_log" + fi + if [[ $IN_DOCKER -eq 0 ]]; then echo "$LOG_DIR" > "$TMP_DIR"/orig_logdir fi @@ -854,58 +863,56 @@ main() print_output "[*] EMBA sets up the docker environment.\\n" "no_log" - if [[ "$UPDATE" -eq 1 ]]; then - EMBA="$INVOCATION_PATH" FIRMWARE="$FIRMWARE_PATH" LOG="$LOG_DIR" docker pull embeddedanalyzer/emba + if ! docker images | grep -qE "emba[[:space:]]*latest"; then + if ! docker images | grep -qE "emba[[:space:]]*latest"; then + print_output "[*] Available docker images:" "no_log" + docker images | grep -E "emba[[:space:]]*latest" || true + print_output "[-] EMBA docker not ready!" "no_log" + exit 1 + fi fi - if ! docker images | grep -qE "emba[[:space:]]*latest"; then - print_output "[*] Available docker images:" "no_log" - docker images | grep -E "emba[[:space:]]*latest" || true - print_output "[-] EMBA docker not ready!" "no_log" - exit 1 - else - print_output "[*] EMBA initializes docker container.\\n" "no_log" + print_output "[*] EMBA initializes docker container.\\n" "no_log" - if [[ "$ONLY_DEP" -eq 0 ]]; then - # store some details that we do not have in the docker container: - echo "$FIRMWARE_PATH" >> "$TMP_DIR"/fw_name.log - echo "$LOG_DIR" >> "$TMP_DIR"/emba_log_dir.log - echo "$EMBA_COMMAND" >> "$TMP_DIR"/emba_command.log - fi + if [[ "$ONLY_DEP" -eq 0 ]]; then + # store some details that we do not have in the docker container: + echo "$FIRMWARE_PATH" >> "$TMP_DIR"/fw_name.log + echo "$LOG_DIR" >> "$TMP_DIR"/emba_log_dir.log + echo "$EMBA_COMMAND" >> "$TMP_DIR"/emba_command.log + fi - write_notification "EMBA starting docker container" + write_notification "EMBA starting docker container" - if [[ "$STRICT_MODE" -eq 1 ]]; then - set +e - fi - disable_strict_mode "$STRICT_MODE" 0 - EMBA="$INVOCATION_PATH" FIRMWARE="$FIRMWARE_PATH" LOG="$LOG_DIR" docker-compose run --rm emba -c './emba.sh -l /logs -f /firmware -i "$@"' _ "${ARGUMENTS[@]}" - D_RETURN=$? - enable_strict_mode "$STRICT_MODE" 0 - - if [[ $D_RETURN -eq 0 ]] ; then - if [[ $ONLY_DEP -eq 0 ]] ; then - print_output "[*] EMBA finished analysis in docker container.\\n" "no_log" - write_notification "EMBA finished analysis in default mode" - print_output "[*] Firmware tested: $ORANGE$FIRMWARE_PATH$NC" "no_log" - print_output "[*] Log directory: $ORANGE$LOG_DIR$NC" "no_log" - if [[ -f "$HTML_PATH"/index.html ]]; then - print_output "[*] Open the web-report with$ORANGE firefox $(abs_path "$HTML_PATH/index.html")$NC\\n" "main" - fi - cleaner 0 - else - # we do not need the log dir from dependency checker - if [[ -d "$LOG_DIR" ]]; then - rm -r "$LOG_DIR" - fi + if [[ "$STRICT_MODE" -eq 1 ]]; then + set +e + fi + disable_strict_mode "$STRICT_MODE" 0 + EMBA="$INVOCATION_PATH" FIRMWARE="$FIRMWARE_PATH" LOG="$LOG_DIR" docker-compose run --rm emba -c './emba.sh -l /logs -f /firmware -i "$@"' _ "${ARGUMENTS[@]}" + D_RETURN=$? + enable_strict_mode "$STRICT_MODE" 0 + + if [[ $D_RETURN -eq 0 ]] ; then + if [[ $ONLY_DEP -eq 0 ]] ; then + print_output "[*] EMBA finished analysis in docker container.\\n" "no_log" + write_notification "EMBA finished analysis in default mode" + print_output "[*] Firmware tested: $ORANGE$FIRMWARE_PATH$NC" "no_log" + print_output "[*] Log directory: $ORANGE$LOG_DIR$NC" "no_log" + if [[ -f "$HTML_PATH"/index.html ]]; then + print_output "[*] Open the web-report with$ORANGE firefox $(abs_path "$HTML_PATH/index.html")$NC\\n" "main" fi - exit 0 - else - print_output "[-] EMBA failed in docker mode!" "no_log" cleaner 0 - write_notification "EMBA failed analysis in default mode" - exit 1 + else + # we do not need the log dir from dependency checker + if [[ -d "$LOG_DIR" ]]; then + rm -r "$LOG_DIR" + fi fi + exit 0 + else + print_output "[-] EMBA failed in docker mode!" "no_log" + cleaner 0 + write_notification "EMBA failed analysis in default mode" + exit 1 fi fi diff --git a/helpers/helpers_emba_dependency_check.sh b/helpers/helpers_emba_dependency_check.sh index 0bfcd8cd0..50851f7aa 100755 --- a/helpers/helpers_emba_dependency_check.sh +++ b/helpers/helpers_emba_dependency_check.sh @@ -339,7 +339,10 @@ dependency_check() # Check system tools ####################################################################################### if [[ $USE_DOCKER -eq 0 ]] ; then - SYSTEM_TOOLS=("awk" "basename" "bash" "cat" "chmod" "chown" "cp" "cut" "date" "dirname" "dpkg-deb" "echo" "eval" "find" "grep" "head" "kill" "ln" "ls" "md5sum" "mkdir" "mknod" "modinfo" "mv" "netstat" "openssl" "printf" "pwd" "readelf" "realpath" "rm" "rmdir" "sed" "seq" "sleep" "sort" "strings" "tee" "touch" "tr" "uniq" "unzip" "wc") + SYSTEM_TOOLS=("awk" "basename" "bash" "cat" "chmod" "chown" "cp" "cut" "date" "dirname" \ + "dpkg-deb" "echo" "eval" "find" "grep" "head" "kill" "ln" "ls" "md5sum" "mkdir" "mknod" \ + "modinfo" "mv" "netstat" "openssl" "printf" "pwd" "readelf" "realpath" "rm" "rmdir" "sed" \ + "seq" "sleep" "sort" "strings" "tee" "touch" "tr" "uniq" "unzip" "wc") for TOOL in "${SYSTEM_TOOLS[@]}" ; do check_dep_tool "$TOOL" @@ -434,6 +437,9 @@ dependency_check() # Freetz-NG check_dep_file "Freetz-NG fwmod" "$EXT_DIR""/freetz-ng/fwmod" + # AVM fitimg extraction script + check_dep_file "fitimg script" "$EXT_DIR""/fitimg-0.8/fitimg" + # EnGenius decryptor - https://gist.github.com/ryancdotorg/914f3ad05bfe0c359b79716f067eaa99 check_dep_file "EnGenius decryptor" "$EXT_DIR""/engenius-decrypt.py" diff --git a/helpers/helpers_emba_helpers.sh b/helpers/helpers_emba_helpers.sh index 1b1c32b70..ae19ec1ee 100755 --- a/helpers/helpers_emba_helpers.sh +++ b/helpers/helpers_emba_helpers.sh @@ -136,6 +136,13 @@ cleaner() { restore_permissions fi + if [[ "$IN_DOCKER" -eq 0 ]] && [[ -v K_DOWN_PID ]]; then + if ps -p "$K_DOWN_PID" > /dev/null; then + # kernel downloader is running in a thread on the host and needs to be stopped now + print_output "[*] Stopping kernel downloader thread with PID $K_DOWN_PID" "no_log" + kill "$K_DOWN_PID" || true + fi + fi if [[ "$IN_DOCKER" -eq 0 ]] && pgrep -f "find ./external/trickest" &> /dev/null 2>&1; then pkill -f "find ./external/trickest" 2>/dev/null || true fi diff --git a/helpers/helpers_emba_html_generator.sh b/helpers/helpers_emba_html_generator.sh index 164384b8c..c36cd3734 100755 --- a/helpers/helpers_emba_html_generator.sh +++ b/helpers/helpers_emba_html_generator.sh @@ -293,19 +293,22 @@ add_link_tags() { # CVE links if ( grep -a -q -E '(CVE)' "$LINK_FILE" ) ; then - readarray -t CVE_IDS < <( grep -a -n -E -o 'CVE-[0-9]{4}-[0-9]{4,7}' "$LINK_FILE" | uniq || true) - for CVE_ID in "${CVE_IDS[@]}" ; do - CVE_ID_LINE="$(echo "$CVE_ID" | cut -d ":" -f 1)" - CVE_ID_STRING="$(echo "$CVE_ID" | cut -d ":" -f 2-)" - if [[ -n "$CVE_ID_STRING" ]] ; then - HTML_LINK="$(echo "$CVE_LINK" | sed -e "s@LINK@$CVE_ID_STRING@g")""$CVE_ID_STRING""$LINK_END" - if [[ "$LINK_FILE" == *"f20_vul_aggregator"* ]]; then - LINK_COMMAND_ARR+=( "$CVE_ID_LINE"'s@'"[[:blank:]]$CVE_ID_STRING"'@'"\t$HTML_LINK""@" ) - else - LINK_COMMAND_ARR+=( "$CVE_ID_LINE"'s@'"$CVE_ID_STRING"'@'"$HTML_LINK"'@' ) + # in l35 html report we do not link CVE - we have Metasploit links in there + if ! [[ "$LINK_FILE" == *"l35_"* ]]; then + readarray -t CVE_IDS < <( grep -a -n -E -o 'CVE-[0-9]{4}-[0-9]{4,7}' "$LINK_FILE" | uniq || true) + for CVE_ID in "${CVE_IDS[@]}" ; do + CVE_ID_LINE="$(echo "$CVE_ID" | cut -d ":" -f 1)" + CVE_ID_STRING="$(echo "$CVE_ID" | cut -d ":" -f 2-)" + if [[ -n "$CVE_ID_STRING" ]] ; then + HTML_LINK="$(echo "$CVE_LINK" | sed -e "s@LINK@$CVE_ID_STRING@g")""$CVE_ID_STRING""$LINK_END" + if [[ "$LINK_FILE" == *"f20_vul_aggregator"* ]]; then + LINK_COMMAND_ARR+=( "$CVE_ID_LINE"'s@'"[[:blank:]]$CVE_ID_STRING"'@'"\t$HTML_LINK""@" ) + else + LINK_COMMAND_ARR+=( "$CVE_ID_LINE"'s@'"$CVE_ID_STRING"'@'"$HTML_LINK"'@' ) + fi fi - fi - done + done + fi fi # CWE links diff --git a/helpers/helpers_emba_internet_access.sh b/helpers/helpers_emba_internet_access.sh new file mode 100755 index 000000000..5dc9f3f45 --- /dev/null +++ b/helpers/helpers_emba_internet_access.sh @@ -0,0 +1,135 @@ +#!/bin/bash -p + +# EMBA - EMBEDDED LINUX ANALYZER +# +# Copyright 2020-2023 Siemens Energy AG +# +# EMBA comes with ABSOLUTELY NO WARRANTY. This is free software, and you are +# welcome to redistribute it under the terms of the GNU General Public License. +# See LICENSE file for usage of this software. +# +# EMBA is licensed under GPLv3 +# +# Author(s): Michael Messner + +# Description: Multiple useful helpers used to access online resources + + +# kernel downloader waits for s24 results. If we were able to identify a kernel version, +# a kernel config or at least kernel symbols we can use these details to verify the +# vulnerabilities which we identified based on the kernel version +kernel_downloader() { + LOG_FILE_KERNEL="$CSV_DIR"/s24_kernel_bin_identifier.csv + KERNEL_ARCH_PATH="$EXT_DIR"/linux_kernel_sources/ + + if ! [[ -d "$KERNEL_ARCH_PATH" ]]; then + mkdir "$KERNEL_ARCH_PATH" + fi + + # we wait until the s24 module is finished and hopefully shows us a kernel version + while ! [[ -f "$LOG_DIR"/"$MAIN_LOG_FILE" ]]; do + sleep 1 + done + if [[ -f "$LOG_DIR"/"$MAIN_LOG_FILE" ]]; then + while [[ $(grep -c S24_kernel_bin_identifier "$LOG_DIR"/"$MAIN_LOG_FILE") -lt 2 ]]; do + sleep 1 + done + fi + + # now we should have a csv log with a kernel version: + if ! [[ -f "$LOG_FILE_KERNEL" ]]; then + local OUTPUTTER="[-] No Kernel version identified ..." + print_output "$OUTPUTTER" "no_log" + write_log "$OUTPUTTER" "$LOG_DIR/kernel_downloader.log" + return + fi + local K_VERSIONS=() + local K_VERSION="" + + mapfile -t K_VERSIONS < <(cut -d\; -f2 "$LOG_FILE_KERNEL" | tail -n +2 | sort -u | grep -E "[0-9]+(\.[0-9]+)+?" || true) + + for K_VERSION in "${K_VERSIONS[@]}"; do + local OUTPUTTER="[*] Checking download of kernel version $ORANGE$K_VERSION$NC" + print_output "$OUTPUTTER" "no_log" + write_log "$OUTPUTTER" "$LOG_DIR/kernel_downloader.log" + local K_VER_DOWNLOAD="" + local K_VER_1st="" + local K_VER_2nd="" + # local K_VER_3rd="" + + K_VER_1st=$(echo "$K_VERSION" | cut -d. -f1) + K_VER_2nd=$(echo "$K_VERSION" | cut -d. -f2) + # K_VER_3rd=$(echo "$K_VERSION" | cut -d. -f3) + + # prepare the path in the URL: + if [[ "$K_VER_1st" -lt 3 ]]; then + K_VER_DOWNLOAD="$K_VER_1st"".""$K_VER_2nd" + elif [[ "$K_VER_1st" -eq 3 && "$K_VER_2nd" -eq 0 ]]; then + K_VER_DOWNLOAD="$K_VER_1st"".""$K_VER_2nd" + else + K_VER_DOWNLOAD="$K_VER_1st"".x" + fi + + # prepare the download filename: + if [[ "$K_VERSION" == *".0" ]]; then + # for download we need to modify versions like 3.1.0 to 3.1 + K_VERSION=${K_VERSION%.0} + fi + + # we check if the sources archive is already available and is a valid tgz file: + if ! [[ -f "$KERNEL_ARCH_PATH"/linux-"$K_VERSION".tar.gz ]] || ! gunzip -t "$KERNEL_ARCH_PATH/linux-$K_VERSION.tar.gz" > /dev/null; then + local OUTPUTTER="[*] Kernel download for version $ORANGE$K_VERSION$NC" + print_output "$OUTPUTTER" "no_log" + write_log "$OUTPUTTER" "$LOG_DIR/kernel_downloader.log" + + if ! [[ -d "$TMP_DIR" ]]; then + mkdir "$TMP_DIR" + fi + + disable_strict_mode "$STRICT_MODE" 0 + wget --output-file="$TMP_DIR"/wget.log https://mirrors.edge.kernel.org/pub/linux/kernel/v"$K_VER_DOWNLOAD"/linux-"$K_VERSION".tar.gz -O "$KERNEL_ARCH_PATH"/linux-"$K_VERSION".tar.gz 2>&1 + D_RETURN="$?" + enable_strict_mode "$STRICT_MODE" 0 + + if [[ -f "$TMP_DIR"/wget.log ]]; then + print_ln + tee -a "$LOG_DIR/kernel_downloader.log" < "$TMP_DIR"/wget.log + rm "$TMP_DIR"/wget.log + fi + # if we have a non zero return something failed and we need to communicate this to the container modules (s26) which + # checks for the file "$TMP_DIR"/linux_download_failed. If this file is available it stops waiting for the kernel + # sources + if [[ $D_RETURN -ne 0 ]] ; then + local OUTPUTTER="[-] Kernel download for version $ORANGE$K_VERSION$NC failed" + print_output "$OUTPUTTER" "no_log" + write_log "$OUTPUTTER" "$LOG_DIR/kernel_downloader.log" + + echo "failed" > "$TMP_DIR"/linux_download_failed + if [[ -f "$KERNEL_ARCH_PATH"/linux-"$K_VERSION".tar.gz ]]; then + rm "$KERNEL_ARCH_PATH"/linux-"$K_VERSION".tar.gz + fi + fi + else + local OUTPUTTER="[*] Kernel sources of version $ORANGE$K_VERSION$NC already available" + print_output "$OUTPUTTER" "no_log" + write_log "$OUTPUTTER" "$LOG_DIR/kernel_downloader.log" + fi + + if ! [[ -f "$KERNEL_ARCH_PATH"/linux-"$K_VERSION".tar.gz ]]; then + local OUTPUTTER="[-] Kernel sources not available ..." + print_output "$OUTPUTTER" "no_log" + write_log "$OUTPUTTER" "$LOG_DIR/kernel_downloader.log" + continue + fi + if ! file "$KERNEL_ARCH_PATH"/linux-"$K_VERSION".tar.gz | grep -q "gzip compressed data"; then + local OUTPUTTER="[-] Kernel sources not available ..." + print_output "$OUTPUTTER" "no_log" + write_log "$OUTPUTTER" "$LOG_DIR/kernel_downloader.log" + continue + fi + local OUTPUTTER="[*] Kernel source for version $ORANGE$K_VERSION$NC stored in $ORANGE$KERNEL_ARCH_PATH$NC" + print_output "$OUTPUTTER" "no_log" + write_log "$OUTPUTTER" "$LOG_DIR/kernel_downloader.log" + done +} + diff --git a/helpers/helpers_emba_prepare.sh b/helpers/helpers_emba_prepare.sh index fc2a1b76e..a08242ffe 100755 --- a/helpers/helpers_emba_prepare.sh +++ b/helpers/helpers_emba_prepare.sh @@ -31,7 +31,8 @@ log_folder() local POSSIBLE_RESTART=0 # used for testing the checksums of the firmware with stored checksum echo -e "\\n[${RED}!${NC}] ${ORANGE}Warning${NC}\\n" - echo -e " There are files in the specified directory: ""$LOG_DIR""\\n You can now delete the content here or start the tool again and specify a different directory." + echo -e " There are files in the specified directory: ""$LOG_DIR" + echo -e " You can now delete the content here or start the tool again and specify a different directory." if [[ -f "$LOG_DIR"/"$MAIN_LOG_FILE" ]]; then if grep -q "Test ended" "$LOG_DIR"/"$MAIN_LOG_FILE"; then diff --git a/installer.sh b/installer.sh index 4c8c7cbc7..44ee310bf 100755 --- a/installer.sh +++ b/installer.sh @@ -65,7 +65,8 @@ export NC="\033[0m" # no color ## Attribute definition export BOLD="\033[1m" -echo -e "\\n""$ORANGE""$BOLD""EMBA - Embedded Linux Analyzer Installer""$NC""\\n""$BOLD""=================================================================""$NC" +echo -e "\\n""$ORANGE""$BOLD""EMBA - Embedded Linux Analyzer Installer""$NC" +echo -e "$BOLD""=================================================================""$NC" # import all the installation modules mapfile -t INSTALLERS < <(find "$INSTALLER_DIR" -iname "*.sh" 2> /dev/null) diff --git a/installer/IF20_cve_search.sh b/installer/IF20_cve_search.sh index b57a1a5cf..71285fa2a 100755 --- a/installer/IF20_cve_search.sh +++ b/installer/IF20_cve_search.sh @@ -72,11 +72,11 @@ IF20_cve_search() { pip3 install dicttoxml==1.7.4 pip3 install redis==4.2.2 pip3 install ijson==3.1.4 - pip3 install jsonpickle==2.1.0 + pip3 install jsonpickle==3.0.1 pip3 install requirements-parser==0.5.0 pip3 install ansicolors==1.1.8 pip3 install nltk==3.7 - pip3 install nested-lookup==0.2.23 + pip3 install nested-lookup==0.2.25 pip3 install dnspython==2.2.1 pip3 install Werkzeug pip3 install python-dateutil diff --git a/installer/IP12_avm_freetz_ng_extract.sh b/installer/IP12_avm_freetz_ng_extract.sh index fdb1005ee..dabb0dc3e 100755 --- a/installer/IP12_avm_freetz_ng_extract.sh +++ b/installer/IP12_avm_freetz_ng_extract.sh @@ -57,6 +57,9 @@ IP12_avm_freetz_ng_extract() { print_tool_info "libsqlite3-dev" 1 print_tool_info "gcc-multilib" 1 print_tool_info "python-is-python3" 1 + print_file_info "fitimg" "fit image extractor" "https://boxmatrix.info/hosted/hippie2000/fitimg-0.8.tar.gz" "external/fitimg-0.8.tar.gz" + print_tool_info "libstring-crc32-perl" 1 + print_tool_info "liblzma-dev" 1 if [[ "$LIST_DEP" -eq 1 ]] || [[ $DOCKER_SETUP -eq 1 ]] ; then ANSWER=("n") @@ -119,6 +122,18 @@ IP12_avm_freetz_ng_extract() { else echo -e "${ORANGE}Found freetz directory ... Not touching it$NC" fi + + # fitimg installation + cd "$HOME_PATH" || ( echo "Could not install EMBA component fitimg" && exit 1 ) + download_file "fitimg" "https://boxmatrix.info/hosted/hippie2000/fitimg-0.8.tar.gz" "external/fitimg-0.8.tar.gz" + if [[ -f "external/fitimg-0.8.tar.gz" ]]; then + echo -e "${ORANGE}[*] Installing fitimg$NC" + tar -zxv -f "external/fitimg-0.8.tar.gz" -C external + rm "external/fitimg-0.8.tar.gz" + else + echo "Warning: fitimg download failed" + exit 1 + fi ;; esac fi diff --git a/installer/helpers.sh b/installer/helpers.sh index 2b483227c..d0f7f001d 100755 --- a/installer/helpers.sh +++ b/installer/helpers.sh @@ -176,7 +176,7 @@ print_file_info() echo -e "Description: ""${2:-}" fi # echo "$(wget "${3}" --spider --server-response -O -)" - CONTENT_LENGTH=$(wget "${3:-}" --no-check-certificate --spider --server-response --output-file=./.wget.log 2>&1 | sed -ne '/.ontent-.ength/{s/.*: //;p}' | sed '$!d') + CONTENT_LENGTH=$(wget "${3:-}" --no-check-certificate --spider --server-response --output-file=./.wget.log 2>&1 | sed -ne '/.ontent-.ength/{s/.*: //;p}' | sed '$!d' || true) if [[ -n "$CONTENT_LENGTH" ]]; then FILE_SIZE=$(("$CONTENT_LENGTH")) else @@ -225,6 +225,9 @@ download_file() echo -e "\\n""$ORANGE""$BOLD""Downloading ""${1:-}""$NC" if ! [[ -f "${3:-}" ]] ; then wget --no-check-certificate --output-file=./.wget.log "${2:-}" -O "${3:-}" + if [[ -f "./.wget.log" ]]; then + cat ./.wget.log + fi else echo -e "$GREEN""${1}"" is already downloaded - no further action performed.""$NC" fi diff --git a/modules/F20_vul_aggregator.sh b/modules/F20_vul_aggregator.sh index 85003013e..bf97c2886 100755 --- a/modules/F20_vul_aggregator.sh +++ b/modules/F20_vul_aggregator.sh @@ -12,7 +12,8 @@ # # Author(s): Michael Messner -# Description: Aggregates all found version numbers together from S06, S08, S09, S25, S115/S116 and L15. +# Description: Aggregates all found version numbers together from S06, S08, S09, S25, S26, +# S115/S116 and L15. # The versions are used for identification of known vulnerabilities cve-search, # finally it creates a list of exploits that are matching for the CVEs. @@ -42,33 +43,44 @@ F20_vul_aggregator() { MSF_SEARCH=0 TRICKEST_SEARCH=0 CVE_SEARCHSPLOIT=0 + local FOUND_CVE=0 + local S26_LOGS_ARR=() CVE_AGGREGATOR_LOG="f20_vul_aggregator.txt" - if [[ -f "$CVE_WHITELIST" ]] && [[ $(grep -c -E "CVE-[0-9]+-[0-9]+" "$CVE_WHITELIST") -gt 0 ]]; then - print_output "[!] WARNING: CVE whitelisting activated" - fi - if [[ -f "$CVE_BLACKLIST" ]] && [[ $(grep -c -E "CVE-[0-9]+-[0-9]+" "$CVE_BLACKLIST") -gt 0 ]]; then - print_output "[!] WARNING: CVE blacklisting activated" - fi local S02_LOG="$CSV_DIR"/s02_uefi_fwhunt.csv local S06_LOG="$CSV_DIR"/s06_distribution_identification.csv local S08_LOG="$CSV_DIR"/s08_package_mgmt_extractor.csv local S09_LOG="$CSV_DIR"/s09_firmware_base_version_check.csv local S25_LOG="$CSV_DIR"/s25_kernel_check.csv + local S26_LOG_DIR="$LOG_DIR""/s26_kernel_vuln_verifier/" local S116_LOG="$CSV_DIR"/s116_qemu_version_detection.csv local L15_LOG="$CSV_DIR"/l15_emulated_checks_nmap.csv local L25_LOG="$CSV_DIR"/l25_web_checks.csv local L35_LOG="$CSV_DIR"/l35_metasploit_check.csv + if [[ -d "$S26_LOG_DIR" ]]; then + mapfile -t S26_LOGS_ARR < <(find "$S26_LOG_DIR" -name "cve_results_kernel_*.csv") + fi + local CVE_MINIMAL_LOG="$LOG_PATH_MODULE"/CVE_minimal.txt local EXPLOIT_OVERVIEW_LOG="$LOG_PATH_MODULE"/exploits-overview.txt + export KERNEL_CVE_VERIFIED=() + export KERNEL_CVE_VERIFIED_VERSION=() + if ! [[ -f "$KNOWN_EXP_CSV" ]]; then KNOWN_EXP_CSV="$EXT_DIR"/known_exploited_vulnerabilities.csv fi + if [[ -f "$CVE_WHITELIST" ]] && [[ $(grep -c -E "CVE-[0-9]+-[0-9]+" "$CVE_WHITELIST") -gt 0 ]]; then + print_output "[!] WARNING: CVE whitelisting activated" + fi + if [[ -f "$CVE_BLACKLIST" ]] && [[ $(grep -c -E "CVE-[0-9]+-[0-9]+" "$CVE_BLACKLIST") -gt 0 ]]; then + print_output "[!] WARNING: CVE blacklisting activated" + fi + if [[ -f $PATH_CVE_SEARCH ]]; then print_output "[*] Aggregate vulnerability details" @@ -85,6 +97,10 @@ F20_vul_aggregator() { fi fi + if [[ -v S26_LOGS_ARR ]]; then + get_kernel_verified "${S26_LOGS_ARR[@]}" + fi + get_uefi_details "$S02_LOG" get_firmware_details "$S06_LOG" get_package_details "$S08_LOG" @@ -130,10 +146,14 @@ F20_vul_aggregator() { SNYK_SEARCH=1 fi - write_csv_log "BINARY" "VERSION" "CVE identifier" "CVSS rating" "exploit db exploit available" "metasploit module" "trickest PoC" "Routersploit" "Snyk PoC" "Packetstormsecurity PoC" "local exploit" "remote exploit" "DoS exploit" "known exploited vuln" + write_csv_log "BINARY" "VERSION" "CVE identifier" "CVSS rating" "exploit db exploit available" "metasploit module" "trickest PoC" "Routersploit" "Snyk PoC" "Packetstormsecurity PoC" "local exploit" "remote exploit" "DoS exploit" "known exploited vuln" "kernel vulnerability verified" - generate_cve_details_versions "${VERSIONS_AGGREGATED[@]}" - generate_cve_details_cves "${CVES_AGGREGATED[@]}" + if [[ "${#VERSIONS_AGGREGATED[@]}" -gt 0 ]]; then + generate_cve_details_versions "${VERSIONS_AGGREGATED[@]}" + fi + if [[ "${#CVES_AGGREGATED[@]}" -gt 0 ]]; then + generate_cve_details_cves "${CVES_AGGREGATED[@]}" + fi generate_special_log "$CVE_MINIMAL_LOG" "$EXPLOIT_OVERVIEW_LOG" else @@ -162,7 +182,10 @@ aggregate_versions() { export VERSIONS_AGGREGATED=() VERSIONS_KERNEL=() - if [[ ${#VERSIONS_STAT_CHECK[@]} -gt 0 || ${#VERSIONS_EMULATOR[@]} -gt 0 || ${#KERNEL_CVE_EXPLOITS[@]} -gt 0 || ${#VERSIONS_SYS_EMULATOR[@]} || ${#VERSIONS_S06_FW_DETAILS[@]} -gt 0 || ${#VERSIONS_SYS_EMULATOR_WEB[@]} -gt 0 || "${#CVE_S02_DETAILS[@]}" -gt 0 || "${#CVE_L35_DETAILS[@]}" -gt 0 ]]; then + if [[ ${#VERSIONS_STAT_CHECK[@]} -gt 0 || ${#VERSIONS_EMULATOR[@]} -gt 0 || ${#KERNEL_CVE_EXPLOITS[@]} -gt 0 || ${#VERSIONS_SYS_EMULATOR[@]} -gt 0 || \ + ${#VERSIONS_S06_FW_DETAILS[@]} -gt 0 || ${#VERSIONS_SYS_EMULATOR_WEB[@]} -gt 0 || "${#CVE_S02_DETAILS[@]}" -gt 0 || "${#CVE_L35_DETAILS[@]}" -gt 0 || \ + ${#KERNEL_CVE_VERIFIED[@]} -gt 0 ]]; then + print_output "[*] Software inventory initial overview:" write_anchor "softwareinventoryinitialoverview" for VERSION in "${VERSIONS_S06_FW_DETAILS[@]}"; do @@ -214,6 +237,19 @@ aggregate_versions() { # print_output "[+] Added modfied Kernel Version details (${ORANGE}kernel$GREEN): ""$ORANGE$VERSION$NC" done + # details from module s26 + for VERSION in "${KERNEL_CVE_VERIFIED_VERSION[@]}"; do + if [ -z "$VERSION" ]; then + continue + fi + VERSION="$(echo "$VERSION" | cut -d\; -f1 | sed 's/^/kernel:/')" + print_output "[+] Found Version details (${ORANGE}kernel - with verified vulnerability details$GREEN): ""$ORANGE$VERSION$NC" + # we ensure that we search for the correct kernel version by adding a : at the end of the search string + VERSION=${VERSION/%/:} + VERSIONS_KERNEL+=( "$VERSION" ) + # print_output "[+] Added modfied Kernel Version details (${ORANGE}kernel$GREEN): ""$ORANGE$VERSION$NC" + done + for CVE_ENTRY in "${CVE_S02_DETAILS[@]}"; do if [ -z "$CVE_ENTRY" ]; then continue @@ -236,8 +272,6 @@ aggregate_versions() { print_output "[+] Found CVE details (${ORANGE}verified Metasploit exploits$GREEN): ""$ORANGE$CVE_ENTRY$NC" done - - print_ln VERSIONS_AGGREGATED=("${VERSIONS_EMULATOR[@]}" "${VERSIONS_KERNEL[@]}" "${VERSIONS_STAT_CHECK[@]}" "${VERSIONS_SYS_EMULATOR[@]}" "${VERSIONS_S06_FW_DETAILS[@]}" "${VERSIONS_S08_PACKAGE_DETAILS[@]}" "${VERSIONS_SYS_EMULATOR_WEB[@]}") @@ -313,7 +347,7 @@ generate_special_log() { local CVE_MINIMAL_LOG="${1:-}" local EXPLOIT_OVERVIEW_LOG="${2:-}" - if [[ $(grep -c "Found.*CVEs\ and" "$LOG_FILE" || true) -gt 0 ]]; then + if [[ $(grep -c "Found.*CVEs\ .*and" "$LOG_FILE" || true) -gt 0 ]]; then sub_module_title "Minimal report of exploits and CVE's." write_anchor "minimalreportofexploitsandcves" @@ -378,7 +412,6 @@ generate_special_log() { print_ln fi - for EXPLOIT_ in "${EXPLOITS_AVAIL[@]}"; do # remove color codes: EXPLOIT_=$(echo "$EXPLOIT_" | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g") @@ -418,7 +451,7 @@ generate_special_log() { } generate_cve_details_cves() { - sub_module_title "Collect CVE and exploit details." + sub_module_title "Collect CVE and exploit details from CVEs." write_anchor "collectcveandexploitdetails_cves" local CVES_AGGREGATED=("$@") @@ -431,7 +464,7 @@ generate_cve_details_cves() { WAIT_PIDS_F19+=( "$!" ) max_pids_protection "$MAX_MODS" "${WAIT_PIDS_F19[@]}" else - cve_db_lookup_version "$CVE_ENTRY" + cve_db_lookup_cve "$CVE_ENTRY" fi done @@ -441,7 +474,7 @@ generate_cve_details_cves() { } generate_cve_details_versions() { - sub_module_title "Collect CVE and exploit details." + sub_module_title "Collect CVE and exploit details from versions." write_anchor "collectcveandexploitdetails" CVE_COUNTER=0 @@ -555,6 +588,8 @@ cve_extractor() { local DOS=0 local CVEs_OUTPUT=() local CVE_OUTPUT="" + local S26_LOG_DIR="$LOG_DIR""/s26_kernel_vuln_verifier" + local KERNEL_VERIFIED_VULN=0 if ! [[ "$VERSION_orig" == "CVE-"* ]]; then if [[ "$(echo "$VERSION_orig" | sed 's/:$//' | grep -o ":" | wc -l || true)" -eq 1 ]]; then @@ -660,6 +695,7 @@ cve_extractor() { if [[ -f "$LOG_PATH_MODULE"/"$AGG_LOG_FILE" ]]; then for CVE_OUTPUT in "${CVEs_OUTPUT[@]}"; do local CVEv2_TMP=0 + local KERNEL_VERIFIED="no" CVE_VALUE=$(echo "$CVE_OUTPUT" | cut -d: -f1) # if we find a blacklist file we check if the current CVE value is in the blacklist @@ -711,6 +747,25 @@ cve_extractor() { EDB=1 fi done + + if [[ -f "$S26_LOG_DIR"/cve_results_kernel_"$VERSION".csv ]]; then + # check if the current CVE is a verified kernel CVE from s26 module + if grep -q ";$CVE_VALUE;.*;.*;1;1" "$S26_LOG_DIR"/cve_results_kernel_"$VERSION".csv; then + print_output "[+] ${ORANGE}INFO:$GREEN Vulnerability $ORANGE$CVE_VALUE$GREEN is a verified kernel vulnerability (${ORANGE}kernel symbols and kernel configuration${GREEN})!" + ((KERNEL_VERIFIED_VULN+=1)) + KERNEL_VERIFIED="yes" + fi + if grep -q ";$CVE_VALUE;.*;.*;1;0" "$S26_LOG_DIR"/cve_results_kernel_"$VERSION".csv; then + print_output "[+] ${ORANGE}INFO:$GREEN Vulnerability $ORANGE$CVE_VALUE$GREEN is a verified kernel vulnerability (${ORANGE}kernel symbols${GREEN})!" + ((KERNEL_VERIFIED_VULN+=1)) + KERNEL_VERIFIED="yes" + fi + if grep -q ";$CVE_VALUE;.*;.*;0;1" "$S26_LOG_DIR"/cve_results_kernel_"$VERSION".csv; then + print_output "[+] ${ORANGE}INFO:$GREEN Vulnerability $ORANGE$CVE_VALUE$GREEN is a verified kernel vulnerability (${ORANGE}kernel configuration${GREEN})!" + ((KERNEL_VERIFIED_VULN+=1)) + KERNEL_VERIFIED="yes" + fi + fi fi if [[ "$CVE_SEARCHSPLOIT" -eq 1 || "$MSF_SEARCH" -eq 1 || "$TRICKEST_SEARCH" -eq 1 || "$SNYK_SEARCH" -eq 1 || "$PS_SEARCH" -eq 1 ]] ; then @@ -954,37 +1009,40 @@ cve_extractor() { CVEv2_TMP=1 fi + # if this CVE is a kernel verified CVE we add a V to the CVE + if [[ "$KERNEL_VERIFIED" == "yes" ]]; then CVE_VALUE="$CVE_VALUE"" (V)"; fi + # we do not deal with output formatting the usual way -> we use printf if (( $(echo "$CVSS_VALUE > 6.9" | bc -l) )); then # put a note in the output if we have switched to CVSSv2 if [[ "$CVEv2_TMP" -eq 1 ]]; then CVSS_VALUE="$CVSS_VALUE"" (v2)"; fi if [[ "$EXPLOIT" == *MSF* || "$EXPLOIT" == *EDB\ ID* || "$EXPLOIT" == *linux-exploit-suggester* || "$EXPLOIT" == *Routersploit* || \ "$EXPLOIT" == *Github* || "$EXPLOIT" == *PSS* || "$EXPLOIT" == *Snyk* || "$KNOWN_EXPLOITED" -eq 1 ]]; then - printf "${MAGENTA}\t%-20.20s: %-12.12s: %-17.17s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" + printf "${MAGENTA}\t%-20.20s: %-12.12s: %-18.18s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" else - printf "${RED}\t%-20.20s: %-12.12s: %-17.17s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" + printf "${RED}\t%-20.20s: %-12.12s: %-18.18s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" fi ((HIGH_CVE_COUNTER+=1)) elif (( $(echo "$CVSS_VALUE > 3.9" | bc -l) )); then if [[ "$CVEv2_TMP" -eq 1 ]]; then CVSS_VALUE="$CVSS_VALUE"" (v2)"; fi if [[ "$EXPLOIT" == *MSF* || "$EXPLOIT" == *EDB\ ID* || "$EXPLOIT" == *linux-exploit-suggester* || "$EXPLOIT" == *Routersploit* || \ "$EXPLOIT" == *Github* || "$EXPLOIT" == *PSS* || "$EXPLOIT" == *Snyk* || "$KNOWN_EXPLOITED" -eq 1 ]]; then - printf "${MAGENTA}\t%-20.20s: %-12.12s: %-17.17s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" + printf "${MAGENTA}\t%-20.20s: %-12.12s: %-18.18s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" else - printf "${ORANGE}\t%-20.20s: %-12.12s: %-17.17s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" + printf "${ORANGE}\t%-20.20s: %-12.12s: %-18.18s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" fi ((MEDIUM_CVE_COUNTER+=1)) else if [[ "$CVEv2_TMP" -eq 1 ]]; then CVSS_VALUE="$CVSS_VALUE"" (v2)"; fi if [[ "$EXPLOIT" == *MSF* || "$EXPLOIT" == *EDB\ ID* || "$EXPLOIT" == *linux-exploit-suggester* || "$EXPLOIT" == *Routersploit* || \ "$EXPLOIT" == *Github* || "$EXPLOIT" == *PSS* || "$EXPLOIT" == *Snyk* || "$KNOWN_EXPLOITED" -eq 1 ]]; then - printf "${MAGENTA}\t%-20.20s: %-12.12s: %-17.17s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" + printf "${MAGENTA}\t%-20.20s: %-12.12s: %-18.18s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" else - printf "${GREEN}\t%-20.20s: %-12.12s: %-17.17s: %-9.9s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" + printf "${GREEN}\t%-20.20s: %-12.12s: %-18.18s: %-10.10s: %-15.15s: %s${NC}\n" "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "$VSOURCE" "$EXPLOIT" >> "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" fi ((LOW_CVE_COUNTER+=1)) fi - write_csv_log "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "${#EXPLOIT_AVAIL[@]}" "${#EXPLOIT_AVAIL_MSF[@]}" "${#EXPLOIT_AVAIL_TRICKEST[@]}" "${#EXPLOIT_AVAIL_ROUTERSPLOIT[@]}/${#EXPLOIT_AVAIL_ROUTERSPLOIT1[@]}" "${EXPLOIT_AVAIL_SNYK[@]}" "${EXPLOIT_AVAIL_PACKETSTORM[@]}" "$LOCAL" "$REMOTE" "$DOS" "${#KNOWN_EXPLOITED_VULNS[@]}" + write_csv_log "$BINARY" "$VERSION" "$CVE_VALUE" "$CVSS_VALUE" "${#EXPLOIT_AVAIL[@]}" "${#EXPLOIT_AVAIL_MSF[@]}" "${#EXPLOIT_AVAIL_TRICKEST[@]}" "${#EXPLOIT_AVAIL_ROUTERSPLOIT[@]}/${#EXPLOIT_AVAIL_ROUTERSPLOIT1[@]}" "${EXPLOIT_AVAIL_SNYK[@]}" "${EXPLOIT_AVAIL_PACKETSTORM[@]}" "$LOCAL" "$REMOTE" "$DOS" "${#KNOWN_EXPLOITED_VULNS[@]}" "$KERNEL_VERIFIED" done fi @@ -1007,12 +1065,20 @@ cve_extractor() { if [[ "$EXPLOIT_COUNTER_VERSION" -gt 0 ]]; then print_ln grep -v "Statistics" "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" | tee -a "$LOG_FILE" || true - print_output "[+] Found $RED$BOLD$CVE_COUNTER_VERSION$NC$GREEN CVEs and $RED$BOLD$EXPLOIT_COUNTER_VERSION$NC$GREEN exploits (including POC's) in $ORANGE$BINARY$GREEN with version $ORANGE$VERSION$GREEN (source ${ORANGE}$VSOURCE$GREEN).${NC}" + if [[ "$KERNEL_VERIFIED_VULN" -gt 0 ]]; then + print_output "[+] Found $RED$BOLD$CVE_COUNTER_VERSION$GREEN CVEs ($RED$KERNEL_VERIFIED_VULN verified$GREEN) and $RED$BOLD$EXPLOIT_COUNTER_VERSION$GREEN exploits (including POC's) in $ORANGE$BINARY$GREEN with version $ORANGE$VERSION$GREEN (source ${ORANGE}$VSOURCE$GREEN).${NC}" + else + print_output "[+] Found $RED$BOLD$CVE_COUNTER_VERSION$GREEN CVEs and $RED$BOLD$EXPLOIT_COUNTER_VERSION$GREEN exploits (including POC's) in $ORANGE$BINARY$GREEN with version $ORANGE$VERSION$GREEN (source ${ORANGE}$VSOURCE$GREEN).${NC}" + fi print_ln elif [[ "$CVE_COUNTER_VERSION" -gt 0 ]]; then print_ln grep -v "Statistics" "$LOG_PATH_MODULE"/cve_sum/"$AGG_LOG_FILE" | tee -a "$LOG_FILE" - print_output "[+] Found $ORANGE$BOLD$CVE_COUNTER_VERSION$NC$GREEN CVEs and $ORANGE$BOLD$EXPLOIT_COUNTER_VERSION$NC$GREEN exploits (including POC's) in $ORANGE$BINARY$GREEN with version $ORANGE$VERSION$GREEN (source ${ORANGE}$VSOURCE$GREEN).${NC}" + if [[ "$KERNEL_VERIFIED_VULN" -gt 0 ]]; then + print_output "[+] Found $ORANGE$BOLD$CVE_COUNTER_VERSION$GREEN CVEs ($ORANGE$KERNEL_VERIFIED_VULN verified$GREEN) and $ORANGE$BOLD$EXPLOIT_COUNTER_VERSION$GREEN exploits (including POC's) in $ORANGE$BINARY$GREEN with version $ORANGE$VERSION$GREEN (source ${ORANGE}$VSOURCE$GREEN).${NC}" + else + print_output "[+] Found $ORANGE$BOLD$CVE_COUNTER_VERSION$GREEN CVEs and $ORANGE$BOLD$EXPLOIT_COUNTER_VERSION$GREEN exploits (including POC's) in $ORANGE$BINARY$GREEN with version $ORANGE$VERSION$GREEN (source ${ORANGE}$VSOURCE$GREEN).${NC}" + fi print_ln else print_ln @@ -1020,7 +1086,11 @@ cve_extractor() { print_ln fi + # normally we only print the number of CVEs. If we have verified CVEs in the Linux Kernel we also add this detail CVEs="$CVE_COUNTER_VERSION" + if [[ "$KERNEL_VERIFIED_VULN" -gt 0 ]] && [[ "$BINARY" == *"kernel"* ]]; then + CVEs="$CVEs"" ($KERNEL_VERIFIED_VULN)" + fi EXPLOITS="$EXPLOIT_COUNTER_VERSION" if [[ "$CVE_COUNTER_VERSION" -gt 0 || "$EXPLOIT_COUNTER_VERSION" -gt 0 ]]; then @@ -1028,25 +1098,26 @@ cve_extractor() { echo "BINARY;VERSION;Number of CVEs;Number of EXPLOITS" >> "$LOG_PATH_MODULE"/F20_summary.csv fi if [[ "$EXPLOIT_COUNTER_VERSION" -gt 0 || "$KNOWN_EXPLOITED" -eq 1 ]]; then - printf "[${MAGENTA}+${NC}]${MAGENTA} Found version details: \t%-20.20s: %-15.15s: CVEs: %-5.5s: Exploits: %-5.5s: Source: %-15.15s${NC}\n" "$BINARY" "$VERSION" "$CVEs" "$EXPLOITS" "$VSOURCE" >> "$LOG_PATH_MODULE"/F20_summary.txt + printf "[${MAGENTA}+${NC}]${MAGENTA} Found version details: \t%-20.20s: %-15.15s: CVEs: %-10.10s: Exploits: %-5.5s: Source: %-15.15s${NC}\n" "$BINARY" "$VERSION" "$CVEs" "$EXPLOITS" "$VSOURCE" >> "$LOG_PATH_MODULE"/F20_summary.txt echo "$BINARY;$VERSION;$CVEs;$EXPLOITS" >> "$LOG_PATH_MODULE"/F20_summary.csv else - printf "[${ORANGE}+${NC}]${ORANGE} Found version details: \t%-20.20s: %-15.15s: CVEs: %-5.5s: Exploits: %-5.5s: Source: %-15.15s${NC}\n" "$BINARY" "$VERSION" "$CVEs" "$EXPLOITS" "$VSOURCE" >> "$LOG_PATH_MODULE"/F20_summary.txt + printf "[${ORANGE}+${NC}]${ORANGE} Found version details: \t%-20.20s: %-15.15s: CVEs: %-10.10s: Exploits: %-5.5s: Source: %-15.15s${NC}\n" "$BINARY" "$VERSION" "$CVEs" "$EXPLOITS" "$VSOURCE" >> "$LOG_PATH_MODULE"/F20_summary.txt echo "$BINARY;$VERSION;$CVEs;$EXPLOITS" >> "$LOG_PATH_MODULE"/F20_summary.csv fi elif [[ "$CVEs" -eq 0 && "$EXPLOITS" -eq 0 ]]; then - printf "[${GREEN}+${NC}]${GREEN} Found version details: \t%-20.20s: %-15.15s: CVEs: %-5.5s: Exploits: %-5.5s: Source: %-15.15s${NC}\n" "$BINARY" "$VERSION" "$CVEs" "$EXPLOITS" "$VSOURCE" >> "$LOG_PATH_MODULE"/F20_summary.txt + printf "[${GREEN}+${NC}]${GREEN} Found version details: \t%-20.20s: %-15.15s: CVEs: %-10.10s: Exploits: %-5.5s: Source: %-15.15s${NC}\n" "$BINARY" "$VERSION" "$CVEs" "$EXPLOITS" "$VSOURCE" >> "$LOG_PATH_MODULE"/F20_summary.txt echo "$BINARY;$VERSION;$CVEs;$EXPLOITS" >> "$LOG_PATH_MODULE"/F20_summary.csv else # this should never happen ... - printf "[+] Found version details: \t%-20.20s: %-15.15s: CVEs: %-5.5s: Exploits: %-5.5s: Source: %-15.15s\n" "$BINARY" "$VERSION" "$CVEs" "$EXPLOITS" "$VSOURCE" >> "$LOG_PATH_MODULE"/F20_summary.txt + printf "[+] Found version details: \t%-20.20s: %-15.15s: CVEs: %-5.5s: Exploits: %-10.10s: Source: %-15.15s\n" "$BINARY" "$VERSION" "$CVEs" "$EXPLOITS" "$VSOURCE" >> "$LOG_PATH_MODULE"/F20_summary.txt echo "$BINARY;$VERSION;$CVEs;$EXPLOITS" >> "$LOG_PATH_MODULE"/F20_summary.csv fi } get_firmware_base_version_check() { local S09_LOG="${1:-}" - VERSIONS_STAT_CHECK=() + export VERSIONS_STAT_CHECK=() + if [[ -f "$S09_LOG" ]]; then print_output "[*] Collect version details of module $(basename "$S09_LOG")." # if we have already kernel information: @@ -1060,7 +1131,8 @@ get_firmware_base_version_check() { get_kernel_check() { local S25_LOG="${1:-}" - KERNEL_CVE_EXPLOITS=() + export KERNEL_CVE_EXPLOITS=() + if [[ -f "$S25_LOG" ]]; then print_output "[*] Collect version details of module $(basename "$S25_LOG")." readarray -t KERNEL_CVE_EXPLOITS < <(cut -d\; -f1-3 "$S25_LOG" | grep -v "CVE identifier" | sort -u || true) @@ -1068,9 +1140,25 @@ get_kernel_check() { fi } +get_kernel_verified() { + local S26_LOGS_ARR=("$@") + local KERNEL_CVE_VERIFIEDX=() + local S26_LOG_DIR="$LOG_DIR""/s26_kernel_vuln_verifier/" + + for S26_LOG in "${S26_LOGS_ARR[@]}"; do + if [[ -f "$S26_LOG" ]]; then + print_output "[*] Collect verified kernel details of module $(basename "$S26_LOG")." + readarray -t KERNEL_CVE_VERIFIEDX < <(tail -n +2 "$S26_LOG" | sort -u || true) + fi + KERNEL_CVE_VERIFIED+=("${KERNEL_CVE_VERIFIEDX[@]}") + done + mapfile -t KERNEL_CVE_VERIFIED_VERSION < <(find "$S26_LOG_DIR" -name "cve_results_kernel_*.csv" -exec cut -d\; -f1 {} \; | grep -v "Kernel version" | sort -u) +} + get_usermode_emulator() { local S116_LOG="${1:-}" - VERSIONS_EMULATOR=() + export VERSIONS_EMULATOR=() + if [[ -f "$S116_LOG" ]]; then print_output "[*] Collect version details of module $(basename "$S116_LOG")." readarray -t VERSIONS_EMULATOR < <(cut -d\; -f4 "$S116_LOG" | grep -v "csv_rule" | sort -u || true) @@ -1079,7 +1167,8 @@ get_usermode_emulator() { get_systemmode_emulator() { local L15_LOG="${1:-}" - VERSIONS_SYS_EMULATOR=() + export VERSIONS_SYS_EMULATOR=() + if [[ -f "$L15_LOG" ]]; then print_output "[*] Collect version details of module $(basename "$L15_LOG")." readarray -t VERSIONS_SYS_EMULATOR < <(cut -d\; -f4 "$L15_LOG" | grep -v "csv_rule" | sort -u || true) @@ -1088,7 +1177,8 @@ get_systemmode_emulator() { get_systemmode_webchecks() { local L25_LOG="${1:-}" - VERSIONS_SYS_EMULATOR_WEB=() + export VERSIONS_SYS_EMULATOR_WEB=() + if [[ -f "$L25_LOG" ]]; then print_output "[*] Collect version details of module $(basename "$L25_LOG")." readarray -t VERSIONS_SYS_EMULATOR_WEB < <(cut -d\; -f4 "$L25_LOG" | grep -v "csv_rule" | sort -u || true) @@ -1097,7 +1187,8 @@ get_systemmode_webchecks() { get_msf_verified() { local L35_LOG="${1:-}" - CVE_L35_DETAILS=() + export CVE_L35_DETAILS=() + if [[ -f "$L35_LOG" ]]; then print_output "[*] Collect CVE details of module $(basename "$L35_LOG")." readarray -t CVE_L35_DETAILS < <(cut -d\; -f3 "$L35_LOG" | grep -v "^CVE$" | grep -v "NA" | sort -u || true) @@ -1106,7 +1197,8 @@ get_msf_verified() { get_uefi_details() { local S02_LOG="${1:-}" - CVE_S02_DETAILS=() + export CVE_S02_DETAILS=() + if [[ -f "$S02_LOG" ]]; then print_output "[*] Collect CVE details of module $(basename "$S02_LOG")." readarray -t CVE_S02_DETAILS < <(cut -d\; -f3 "$S02_LOG" | grep -v "CVE identifier" | sort -u || true) @@ -1115,7 +1207,8 @@ get_uefi_details() { get_firmware_details() { local S06_LOG="${1:-}" - VERSIONS_S06_FW_DETAILS=() + export VERSIONS_S06_FW_DETAILS=() + if [[ -f "$S06_LOG" ]]; then print_output "[*] Collect version details of module $(basename "$S06_LOG")." readarray -t VERSIONS_S06_FW_DETAILS < <(cut -d\; -f4 "$S06_LOG" | grep -v "csv_rule" | sort -u || true) @@ -1124,7 +1217,8 @@ get_firmware_details() { get_package_details() { local S08_LOG="${1:-}" - VERSIONS_S08_PACKAGE_DETAILS=() + export VERSIONS_S08_PACKAGE_DETAILS=() + if [[ -f "$S08_LOG" ]]; then print_output "[*] Collect version details of module $(basename "$S08_LOG")." readarray -t VERSIONS_S08_PACKAGE_DETAILS < <(cut -d\; -f3,5 "$S08_LOG" | grep -v "package\;stripped version" | sort -u | tr ';' ':'|| true) diff --git a/modules/F50_base_aggregator.sh b/modules/F50_base_aggregator.sh index 82d19256b..9c35ff588 100755 --- a/modules/F50_base_aggregator.sh +++ b/modules/F50_base_aggregator.sh @@ -36,6 +36,7 @@ F50_base_aggregator() { S22_LOG="s22_php_check.txt" S24_LOG="s24_kernel_bin_identifier.txt" S25_LOG="s25_kernel_check.txt" + S26_LOG="s26_kernel_vuln_verifier.txt" S30_LOG="s30_version_vulnerability_check.txt" S40_LOG="s40_weak_perm_check.txt" S45_LOG="s45_pass_file_check.txt" @@ -251,6 +252,19 @@ output_details() { DATA=1 fi + if [[ "${K_CVE_VERIFIED_SYMBOLS:-0}" -gt 0 ]] || [[ "${K_CVE_VERIFIED_COMPILED:-0}" -gt 0 ]]; then + if [[ "${K_CVE_VERIFIED_SYMBOLS:-0}" -gt 0 ]]; then + print_output "[+] Verified $ORANGE${K_CVE_VERIFIED_SYMBOLS:-0}$GREEN kernel vulnerabilities (${ORANGE}kernel symbols$GREEN)." + write_link "s26" + fi + if [[ "${K_CVE_VERIFIED_COMPILED:-0}" -gt 0 ]]; then + print_output "[+] Verified $ORANGE${K_CVE_VERIFIED_COMPILED:-0}$GREEN kernel vulnerabilities (${ORANGE}kernel compilation$GREEN)." + write_link "s26" + fi + DATA=1 + write_csv_log "kernel_verified" "${K_CVE_VERIFIED_SYMBOLS:-0}" "${K_CVE_VERIFIED_COMPILED:-0}" + fi + if [[ $DATA -eq 1 ]]; then print_bar fi @@ -602,7 +616,7 @@ output_cve_exploits() { local BINARY_="" if [[ "${S30_VUL_COUNTER:-0}" -gt 0 || "${CVE_COUNTER:-0}" -gt 0 || "${EXPLOIT_COUNTER:-0}" -gt 0 || -v VERSIONS_AGGREGATED[@] ]]; then - if [[ "${CVE_COUNTER:-0}" -gt 0 || "${EXPLOIT_COUNTER:-0}" -gt 0 || -v VERSIONS_AGGREGATED[@] ]]; then + if [[ "${CVE_COUNTER:-0}" -gt 0 || "${EXPLOIT_COUNTER:-0}" -gt 0 || -v VERSIONS_AGGREGATED[@] ]] && [[ -f "$LOG_DIR/f20_vul_aggregator/F20_summary.txt" ]]; then print_output "[*] Identified the following software inventory, vulnerabilities and exploits:" write_link "f20#collectcveandexploitdetails" @@ -630,9 +644,9 @@ output_cve_exploits() { echo -e "\n" >> "$LOG_FILE" print_output "[+] Identified ""$ORANGE""$CVE_COUNTER""$GREEN"" CVE entries." write_link "f20#collectcveandexploitdetails" - print_output "$(indent "$(green "Identified $RED$BOLD$HIGH_CVE_COUNTER$NC$GREEN High rated CVE entries / Exploits: $ORANGE${EXPLOIT_HIGH_COUNT:0}$NC")")" - print_output "$(indent "$(green "Identified $ORANGE$BOLD$MEDIUM_CVE_COUNTER$NC$GREEN Medium rated CVE entries / Exploits: $ORANGE${EXPLOIT_MEDIUM_COUNT:0}$NC")")" - print_output "$(indent "$(green "Identified $GREEN$BOLD$LOW_CVE_COUNTER$NC$GREEN Low rated CVE entries /Exploits: $ORANGE${EXPLOIT_LOW_COUNT:0}$NC")")" + print_output "$(indent "$(green "Identified $RED$BOLD$HIGH_CVE_COUNTER$NC$GREEN High rated CVE entries / Exploits: $ORANGE${EXPLOIT_HIGH_COUNT:-0}$NC")")" + print_output "$(indent "$(green "Identified $ORANGE$BOLD$MEDIUM_CVE_COUNTER$NC$GREEN Medium rated CVE entries / Exploits: $ORANGE${EXPLOIT_MEDIUM_COUNT:-0}$NC")")" + print_output "$(indent "$(green "Identified $GREEN$BOLD$LOW_CVE_COUNTER$NC$GREEN Low rated CVE entries /Exploits: $ORANGE${EXPLOIT_LOW_COUNT:-0}$NC")")" write_csv_log "cve_high" "$HIGH_CVE_COUNTER" "NA" write_csv_log "cve_medium" "$MEDIUM_CVE_COUNTER" "NA" write_csv_log "cve_low" "$LOW_CVE_COUNTER" "NA" @@ -734,6 +748,8 @@ get_data() { export CVE_SEARCH=1 export FWHUNTER_CNT=0 export MSF_VERIFIED=0 + export K_CVE_VERIFIED_SYMBOLS=0 + export K_CVE_VERIFIED_COMPILED=0 if [[ -f "$LOG_DIR"/"$P02_LOG" ]]; then ENTROPY=$(grep -a "Entropy" "$LOG_DIR"/"$P02_LOG" | cut -d\; -f2 | cut -d= -f2 | sed 's/^\ //' || true) @@ -796,6 +812,10 @@ get_data() { MOD_DATA_COUNTER=$(grep -a "\[\*\]\ Statistics1:" "$LOG_DIR"/"$S25_LOG" | cut -d: -f2 || true) KMOD_BAD=$(grep -a "\[\*\]\ Statistics1:" "$LOG_DIR"/"$S25_LOG" | cut -d: -f3 || true) fi + if [[ -f "$LOG_DIR"/"$S26_LOG" ]]; then + K_CVE_VERIFIED_SYMBOLS=$(grep -a "\[\*\]\ Statistics:" "$LOG_DIR"/"$S26_LOG" | cut -d: -f4 || true) + K_CVE_VERIFIED_COMPILED=$(grep -a "\[\*\]\ Statistics:" "$LOG_DIR"/"$S26_LOG" | cut -d: -f5 || true) + fi if [[ -f "$LOG_DIR"/"$S30_LOG" ]]; then S30_VUL_COUNTER=$(grep -a "\[\*\]\ Statistics:" "$LOG_DIR"/"$S30_LOG" | cut -d: -f2 || true) fi diff --git a/modules/L10_system_emulation.sh b/modules/L10_system_emulation.sh index 91a5f9a6f..07d6c5d12 100755 --- a/modules/L10_system_emulation.sh +++ b/modules/L10_system_emulation.sh @@ -230,7 +230,7 @@ create_emulation_filesystem() { # kernelInit is getting the output of the init command line we get from s24 if grep -q "init=" "$CSV_DIR"/s24_kernel_bin_identifier.csv; then print_output "[*] Found init entry for kernel - see $ORANGE$LOG_DIR/s24_kernel_bin_identifier.txt$NC:" - grep "init=/" "$CSV_DIR"/s24_kernel_bin_identifier.csv | cut -d\; -f3 | sed -e 's/.*init=/init=/' | awk '{print $1}'| sort -u | tee -a "${MNT_POINT}"/kernelInit + grep "init=/" "$CSV_DIR"/s24_kernel_bin_identifier.csv | cut -d\; -f5 | sed -e 's/.*init=/init=/' | awk '{print $1}'| sort -u | tee -a "${MNT_POINT}"/kernelInit tee -a "$LOG_FILE" < "${MNT_POINT}"/kernelInit fi else @@ -250,7 +250,7 @@ create_emulation_filesystem() { cp "$MODULE_SUB_PATH/inferService.sh" "${MNT_POINT}" || true FIRMAE_BOOT=${FIRMAE_BOOT} FIRMAE_ETC=${FIRMAE_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /bash-static /inferService.sh | tee -a "$LOG_FILE" - if [ -e "${MNT_POINT}/kernelInit" ]; then + if [[ -e "${MNT_POINT}/kernelInit" ]]; then print_output "[*] Backup ${MNT_POINT}/kernelInit:" tee -a "$LOG_FILE" < "${MNT_POINT}/kernelInit" rm "${MNT_POINT}/kernelInit" @@ -470,7 +470,7 @@ main_emulation() { ############################################################################################### # if we were running into issues with the network identification we poke with rdinit vs init: - # lets check if we have found a startup procedure (preInit script) from FirmAE/EMBA - if not we try it with the other init + # lets check if we have found a startup procedure (preInit script) from EMBA - if not we try it with the other init F_STARTUP=$(grep -a -c "EMBA preInit script starting" "$LOG_PATH_MODULE"/qemu.initial.serial.log || true) F_STARTUP=$(( "$F_STARTUP" + "$(grep -a -c "Network configuration - ACTION" "$LOG_PATH_MODULE"/qemu.initial.serial.log || true)" )) else @@ -480,8 +480,7 @@ main_emulation() { # print_output "[*] Found $ORANGE$F_STARTUP$NC EMBA startup entries." print_ln - - if [[ "${#PANICS[@]}" -gt 0 ]] || [[ "$F_STARTUP" -eq 0 ]]; then + if [[ "${#PANICS[@]}" -gt 0 ]] || [[ "$F_STARTUP" -eq 0 ]] || [[ "$DETECTED_IP" -eq 0 ]]; then # if we are running into a kernel panic during the network detection we are going to check if the # panic is caused from an init failure. If so, we are trying the other init kernel command (init vs rdinit) if [[ "${PANICS[*]}" == *"Kernel panic - not syncing: Attempted to kill init!"* || "${PANICS[*]}" == *"Kernel panic - not syncing: No working init found."* ]]; then @@ -508,10 +507,8 @@ main_emulation() { fi print_ln - # #IPS_INT_VLAN is always at least 1 for the default configuration - # elif [[ "$F_STARTUP" -eq 0 && "$NETWORK_MODE" == "None" && "${#IPS_INT_VLAN[@]}" -lt 2 ]] || \ - # [[ "$F_STARTUP" -eq 0 && "$NETWORK_MODE" == "default" && "${#IPS_INT_VLAN[@]}" -lt 2 ]]; then - elif [[ "$F_STARTUP" -eq 0 && "$NETWORK_MODE" == "None" ]] || [[ "$F_STARTUP" -eq 0 && "$NETWORK_MODE" == "default" ]]; then + elif [[ "$F_STARTUP" -eq 0 && "$NETWORK_MODE" == "None" ]] || \ + [[ "$F_STARTUP" -eq 0 && "$NETWORK_MODE" == "default" ]] || [[ "$DETECTED_IP" -eq 0 ]]; then mv "$LOG_PATH_MODULE"/qemu.initial.serial.log "$LOG_PATH_MODULE"/qemu.initial.serial_"$IMAGE_NAME"_"$INIT_FNAME"_base_init.log if [[ "$KINIT" == "rdinit="* ]]; then print_output "[*] Warning: Unknown EMBA startup found via rdinit - testing init" @@ -531,7 +528,8 @@ main_emulation() { F_STARTUP=$(grep -a -c "EMBA preInit script starting" "$LOG_PATH_MODULE"/qemu.initial.serial.log || true) F_STARTUP=$(( "$F_STARTUP" + "$(grep -a -c "Network configuration - ACTION" "$LOG_PATH_MODULE"/qemu.initial.serial.log || true)" )) # IPS_INT_VLAN is always at least 1 for the default configuration - if [[ "${#PANICS[@]}" -gt 0 ]] || [[ "$F_STARTUP" -eq 0 && "${#IPS_INT_VLAN[@]}" -lt 2 ]]; then + if [[ "${#PANICS[@]}" -gt 0 ]] || [[ "$F_STARTUP" -eq 0 && "${#IPS_INT_VLAN[@]}" -lt 2 ]] || \ + [[ "$DETECTED_IP" -eq 0 ]]; then if [[ "$KINIT" == "rdinit="* ]]; then print_output "[*] Warning: switching back to init" # strip rd from rdinit @@ -671,7 +669,11 @@ main_emulation() { # if we have a working emulation we stop here if [[ "$TCP" == "ok" ]]; then - break 2 + if [[ $(grep -c "tcp.*open" "$LOG_PATH_MODULE"/"$NMAP_LOG" 2>/dev/null) -gt 1 ]]; then + # we only exit if we have more than 1 open port detected. + # Otherwise we try to find a better solution + break 2 + fi fi else print_output "[-] No working emulation - removing emulation archive." @@ -1024,6 +1026,7 @@ get_networking_details_emulation() { sub_module_title "Network identification - $IMAGE_NAME" PANICS=() + export DETECTED_IP=0 if [[ -f "$LOG_PATH_MODULE"/qemu.initial.serial.log ]]; then ETH_INT="NONE" @@ -1129,6 +1132,7 @@ get_networking_details_emulation() { if [[ "$IP_ADDRESS_" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && ! [[ "$IP_ADDRESS_" == "127."* ]] && ! [[ "$IP_ADDRESS_" == "0.0.0.0" ]]; then print_ln print_output "[*] Identified IP address: $ORANGE$IP_ADDRESS_$NC" + DETECTED_IP=1 # get the network device NETWORK_DEVICE="$(echo "$INTERFACE_CAND" | grep device | cut -d: -f2- | sed "s/^.*\]:\ //" | awk '{print $1}' | cut -d: -f2 | tr -dc '[:print:]' || true)" # INTERFACE_CAND -> __inet_insert_ifa[PID: 139 (ifconfig)]: device:br0 ifa:0xc0a80001 @@ -1287,6 +1291,7 @@ get_networking_details_emulation() { for PANIC in "${PANICS[@]}"; do print_output "[!] WARNING: Kernel Panic detected: $ORANGE$PANIC$NC" + print_output "$NC" done color_qemu_log "$LOG_PATH_MODULE/qemu.initial.serial.log" else diff --git a/modules/L10_system_emulation/inferService.sh b/modules/L10_system_emulation/inferService.sh index a33a13333..0a3cc0d45 100755 --- a/modules/L10_system_emulation/inferService.sh +++ b/modules/L10_system_emulation/inferService.sh @@ -67,7 +67,7 @@ for BINARY in $("${BUSYBOX}" find / -name "lighttpd" -type f -o -name "upnp" -ty # check if this service is already in the service file: if ! "${BUSYBOX}" grep -q "${SERVICE_NAME}" /firmadyne/service 2>/dev/null; then # check if we have a configuration available and iterate - for LIGHT_CONFIG in $("${BUSYBOX}" find / -name "lighttpd.conf" -type f); do + for LIGHT_CONFIG in $("${BUSYBOX}" find / -name "lighttpd*.conf" -type f); do # write the service starter with config file "${BUSYBOX}" echo -e "[*] Writing EMBA service for $ORANGE${BINARY} - ${LIGHT_CONFIG}$NC" "${BUSYBOX}" echo -e -n "${BINARY} -f ${LIGHT_CONFIG}\n" >> /firmadyne/service @@ -75,7 +75,7 @@ for BINARY in $("${BUSYBOX}" find / -name "lighttpd" -type f -o -name "upnp" -ty fi elif [ "$("${BUSYBOX}" echo "${SERVICE_NAME}")" == "miniupnpd" ]; then if ! "${BUSYBOX}" grep -q "${SERVICE_NAME}" /firmadyne/service 2>/dev/null; then - for MINIUPNPD_CONFIG in $("${BUSYBOX}" find / -name "miniupnpd.conf" -type f); do + for MINIUPNPD_CONFIG in $("${BUSYBOX}" find / -name "miniupnpd*.conf" -type f); do "${BUSYBOX}" echo -e "[*] Writing EMBA service for $ORANGE${BINARY} - ${MINIUPNPD_CONFIG}$NC" "${BUSYBOX}" echo -e -n "${BINARY} -f ${MINIUPNPD_CONFIG}\n" >> /firmadyne/service done diff --git a/modules/L15_emulated_checks_nmap.sh b/modules/L15_emulated_checks_nmap.sh index a019a7b10..3a924688f 100755 --- a/modules/L15_emulated_checks_nmap.sh +++ b/modules/L15_emulated_checks_nmap.sh @@ -117,13 +117,14 @@ check_live_nmap_basic() { for SERVICE in "${NMAP_PORTS_SERVICES[@]}"; do print_output "[*] Service detected: $ORANGE$SERVICE$NC" SERVICE_NAME="$(escape_echo "$(echo "$SERVICE" | awk '{print $2}')")" + # just in case we have a / in our SERVICE_NAME + SERVICE_NAME="${SERVICE_NAME/\//\\\/}" if [[ "$SERVICE_NAME" == "unknown" ]] || [[ "$SERVICE_NAME" == "tcpwrapped" ]] || [[ -z "$SERVICE_NAME" ]]; then continue fi if [[ -f "$CSV_DIR"/s09_firmware_base_version_check.csv ]]; then # Let's check if we have already found details about this service in our other modules (S09, S115/S116) - # mapfile -t S09_L15_CHECK < <(grep "$SERVICE_NAME" "$CSV_DIR"/s09_firmware_base_version_check.csv || true) mapfile -t S09_L15_CHECK < <(awk -v IGNORECASE=1 -F\; '$2 $3 ~ /'"$SERVICE_NAME"'/' "$CSV_DIR"/s09_firmware_base_version_check.csv || true) if [[ "${#S09_L15_CHECK[@]}" -gt 0 ]]; then for S09_L15_MATCH in "${S09_L15_CHECK[@]}"; do @@ -134,7 +135,6 @@ check_live_nmap_basic() { fi if [[ -f "$CSV_DIR"/s116_qemu_version_detection.csv ]]; then - # mapfile -t S116_L15_CHECK < <(grep "$SERVICE_NAME" "$CSV_DIR"/s116_qemu_version_detection.csv || true) mapfile -t S116_L15_CHECK < <(awk -v IGNORECASE=1 -F\; '$2 $3 ~ /'"$SERVICE_NAME"'/' "$CSV_DIR"/s116_qemu_version_detection.csv || true) if [[ "${#S116_L15_CHECK[@]}" -gt 0 ]]; then for S116_L15_MATCH in "${S116_L15_CHECK[@]}"; do diff --git a/modules/L35_metasploit_check.sh b/modules/L35_metasploit_check.sh index a86f761d4..7edfa671b 100755 --- a/modules/L35_metasploit_check.sh +++ b/modules/L35_metasploit_check.sh @@ -82,7 +82,7 @@ check_live_metasploit() { if [[ -f "$LOG_PATH_MODULE"/metasploit-check-"$IP_ADDRESS_".txt ]] && [[ $(grep -a -i -c "Vulnerability identified for module" "$LOG_PATH_MODULE"/metasploit-check-"$IP_ADDRESS_".txt) -gt 0 ]]; then write_csv_log "Source" "Module" "CVE" "ARCH_END" "IP_ADDRESS" "PORTS" print_ln - print_output "[+] Possible Metasploit results for verification:" "" "$LOG_PATH_MODULE/metasploit-check-$IP_ADDRESS_.txt" + print_output "[+] Metasploit results for verification" "" "$LOG_PATH_MODULE/metasploit-check-$IP_ADDRESS_.txt" mapfile -t MSF_VULNS_VERIFIED < <(grep -a -i "Vulnerability identified for module" "$LOG_PATH_MODULE"/metasploit-check-"$IP_ADDRESS_".txt || true) for MSF_VULN in "${MSF_VULNS_VERIFIED[@]}"; do local MSF_CVE="" @@ -92,9 +92,11 @@ check_live_metasploit() { MSF_CVE="${MSF_CVE%\ }" if [[ -n "$MSF_CVE" ]]; then print_output "[+] Vulnerability verified: $ORANGE$MSF_MODULE$GREEN / $ORANGE$MSF_CVE$GREEN." + write_link "https://github.com/rapid7/metasploit-framework/tree/master/modules/exploits/${MSF_MODULE}.rb" # we write our csv entry later for every CVE entry else print_output "[+] Vulnerability verified: $ORANGE$MSF_MODULE$GREEN." + write_link "https://github.com/rapid7/metasploit-framework/tree/master/modules/exploits/${MSF_MODULE}.rb" MSF_CVE="NA" # if we have no CVE entry we can directly write our csv entry: write_csv_log "Metasploit framework" "$MSF_MODULE" "$MSF_CVE" "$ARCH_END" "$IP_ADDRESS_" "$PORTS" @@ -107,14 +109,20 @@ check_live_metasploit() { print_ln - print_output "[+] Possible Metasploit sessions for verification:" "" "$LOG_PATH_MODULE/metasploit-check-$IP_ADDRESS_.txt" - # sometimes we need two print_ln to get one in the web report?!? - print_ln - print_ln - # Print the session output from the metasploit log: - sed -n '/Active sessions/,/Stopping all jobs/p' "$LOG_PATH_MODULE"/metasploit-check-"$IP_ADDRESS_".txt | tee -a "$LOG_FILE" || true - print_ln + if grep -q "Active sessions" "$LOG_PATH_MODULE/metasploit-check-$IP_ADDRESS_.txt"; then + print_ln + print_output "[+] Possible Metasploit sessions for verification:" "" "$LOG_PATH_MODULE/metasploit-check-$IP_ADDRESS_.txt" + # sometimes we need two print_ln to get one in the web report?!? + print_ln + print_ln + # Print the session output from the metasploit log: + sed -n '/Active sessions/,/Stopping all jobs/p' "$LOG_PATH_MODULE"/metasploit-check-"$IP_ADDRESS_".txt | tee -a "$LOG_FILE" || true + print_ln + else + print_output "[-] No Metasploit session detected" + fi elif [[ -f "$LOG_PATH_MODULE"/metasploit-check-"$IP_ADDRESS_".txt ]]; then + # just for link the log file in the web reporter print_output "[-] No Metasploit results detected" "" "$LOG_PATH_MODULE/metasploit-check-$IP_ADDRESS_.txt" else print_output "[-] No Metasploit results detected" diff --git a/modules/P12_avm_freetz_ng_extract.sh b/modules/P12_avm_freetz_ng_extract.sh index b7bca7c8c..bd101f9b4 100755 --- a/modules/P12_avm_freetz_ng_extract.sh +++ b/modules/P12_avm_freetz_ng_extract.sh @@ -46,6 +46,11 @@ avm_extractor() { return fi local FRITZ_DIRS=0 + local FIT_IMAGES=() + local FIT_IMAGE="" + local RAM_DISKS=() + local RAM_DISK="" + local RAM_DISK_NAME="" export FRITZ_FILE=0 export FRITZ_VERSION="" @@ -67,11 +72,38 @@ avm_extractor() { print_output "[+] Detected Fritz version: $ORANGE$FRITZ_VERSION$NC" fi + # fitimages are handled here with fitimg - binwalk and unblob are also able to handle these images + # but it is currently more beautiful doing the AVM extraction in one place here + mapfile -t FIT_IMAGES < <(find "$EXTRACTION_DIR_" -type f -name "fit-image") + + if [[ "${#FIT_IMAGES[@]}" -gt 0 ]]; then + if [[ -f "$EXT_DIR"/fitimg-0.8/fitimg ]]; then + for FIT_IMAGE in "${FIT_IMAGES[@]}"; do + print_output "[*] Detected fit-image: $ORANGE$FIT_IMAGE$NC" + print_output "[*] Extracting fit-image with fitimg to $ORANGE$EXTRACTION_DIR/fit-image-extraction$NC" + mkdir -p "$EXTRACTION_DIR/fit-image-extraction" + "$EXT_DIR"/fitimg-0.8/fitimg -x "$FIT_IMAGE" -d "$EXTRACTION_DIR"/fit-image-extraction || true + mapfile -t RAM_DISKS < <(find "$EXTRACTION_DIR_"/fit-image-extraction -type f -name "*ramdisk") + print_ln + done + else + print_output "[-] Fitimg installation not available - check your installation" + fi + fi + if [[ "${#RAM_DISKS[@]}" -gt 0 ]]; then + for RAM_DISK in "${RAM_DISKS[@]}"; do + print_output "[*] Detected AVM ramdisk: $ORANGE$RAM_DISK$NC" + RAM_DISK_NAME="$(basename "$RAM_DISK")" + binwalk_deep_extract_helper 1 "$RAM_DISK" "$EXTRACTION_DIR_"/fit-image-extraction/"$RAM_DISK_NAME"_binwalk + print_ln + done + fi + if [[ "$FRITZ_FILES" -gt 0 ]]; then print_ln print_output "[*] Extracted $ORANGE$FRITZ_FILES$NC files and $ORANGE$FRITZ_DIRS$NC directories from the firmware image." write_csv_log "Extractor module" "Original file" "extracted file/dir" "file counter" "directory counter" "further details" - write_csv_log "Freetz-NG" "$AVM_FW_PATH_" "$EXTRACTION_DIR_" "$FRITZ_FILES" "$FRITZ_DIRS" "$FRITZ_VERSION" + write_csv_log "AVM extractor" "$AVM_FW_PATH_" "$EXTRACTION_DIR_" "$FRITZ_FILES" "$FRITZ_DIRS" "$FRITZ_VERSION" export DEEP_EXTRACTOR=1 MD5_DONE_DEEP+=( "$(md5sum "$AVM_FW_PATH_" | awk '{print $1}')" ) diff --git a/modules/S03_firmware_bin_base_analyzer.sh b/modules/S03_firmware_bin_base_analyzer.sh index 17284b8fe..2848018a0 100755 --- a/modules/S03_firmware_bin_base_analyzer.sh +++ b/modules/S03_firmware_bin_base_analyzer.sh @@ -79,7 +79,7 @@ os_identification() { write_log "[*] Initial OS guessing:" write_csv_log "Guessed OS" "confidential rating" "verified" "Linux root filesystems found" - OS_SEARCHER=("Linux" "FreeBSD" "VxWorks\|Wind" "FreeRTOS" "ADONIS" "eCos" "uC/OS" "SIPROTEC" "QNX" "CPU\ [34][12][0-9]-[0-9]" "CP443" "Sinamics" "UEFI" "HelenOS") + OS_SEARCHER=("Linux" "FreeBSD" "VxWorks\|Wind" "FreeRTOS" "ADONIS" "eCos" "uC/OS" "SIPROTEC" "QNX" "CPU\ [34][12][0-9]-[0-9]" "CP443" "Sinamics" "UEFI" "HelenOS" "Windows\ CE") print_dot declare -A OS_COUNTER=() local WAIT_PIDS_S03_1=() diff --git a/modules/S115_usermode_emulator.sh b/modules/S115_usermode_emulator.sh index 4e709f448..2b363fe61 100755 --- a/modules/S115_usermode_emulator.sh +++ b/modules/S115_usermode_emulator.sh @@ -750,7 +750,7 @@ s115_cleanup() { fi mapfile -t LOG_FILES < <(find "$LOG_PATH_MODULE""/" -xdev -type f -name "qemu_tmp*" 2>/dev/null) - ILLEGAL_INSTRUCTIONS=$(grep -l "Illegal instruction" "$LOG_PATH_MODULE""/"qemu_tmp* | wc -l) + ILLEGAL_INSTRUCTIONS=$(grep -l "Illegal instruction" "$LOG_PATH_MODULE""/"qemu_tmp* | wc -l || true) print_output "[*] Found $ORANGE$ILLEGAL_INSTRUCTIONS$NC binaries not emulated - Illegal instructions" if [[ "${#LOG_FILES[@]}" -gt 0 ]] ; then sub_module_title "Reporting phase" diff --git a/modules/S20_shell_check.sh b/modules/S20_shell_check.sh index 8c7b93d7a..a9dd5277a 100755 --- a/modules/S20_shell_check.sh +++ b/modules/S20_shell_check.sh @@ -104,7 +104,7 @@ S20_shell_check() sub_module_title "Summary of shell issues (semgrep)" if [[ "$S20_SEMGREP_VULNS" -gt 0 ]]; then print_output "[+] Found ""$ORANGE""$S20_SEMGREP_ISSUES"" issues""$GREEN"" (""$ORANGE""$S20_SEMGREP_VULNS"" vulnerabilites${GREEN}) in ""$ORANGE""$S20_SEMGREP_SCRIPTS""$GREEN"" shell scripts""$NC" "" "$SHELL_LOG" - else + elif [[ "$S20_SEMGREP_ISSUES" -gt 0 ]]; then print_output "[+] Found ""$ORANGE""$S20_SEMGREP_ISSUES"" issues""$GREEN"" in ""$ORANGE""$S20_SEMGREP_SCRIPTS""$GREEN"" shell scripts""$NC" "" "$SHELL_LOG" fi # highlight security findings in semgrep log: diff --git a/modules/S24_kernel_bin_identifier.sh b/modules/S24_kernel_bin_identifier.sh index b29f61948..56012a1c5 100755 --- a/modules/S24_kernel_bin_identifier.sh +++ b/modules/S24_kernel_bin_identifier.sh @@ -24,13 +24,12 @@ S24_kernel_bin_identifier() local NEG_LOG=0 local FILE="" local K_VER="" + local K_INITS=() local K_INIT="" local CFG_MD5="" export KCFG_MD5=() - if ! [[ -v FILE_ARR_LIMITED ]] || [[ "${#FILE_ARR_LIMITED[@]}" -eq 0 ]]; then - prepare_file_arr_limited "$FIRMWARE_PATH_CP" - fi + prepare_file_arr_limited "$FIRMWARE_PATH_CP" write_csv_log "Kernel version orig" "Kernel version stripped" "file" "generated elf" "identified init" "config extracted" "kernel symbols" @@ -55,15 +54,18 @@ S24_kernel_bin_identifier() print_output "$(indent "$(orange "$K_VER")")" print_ln - K_INIT=$(strings "$FILE" 2>/dev/null | grep -E "init=\/" | sort -u || true) - if [[ "$K_INIT" =~ init=\/.* ]]; then - print_output "[+] Init found in Linux kernel file $ORANGE$FILE$NC" - print_ln - print_output "$(indent "$(orange "$K_INIT")")" - print_ln - else - K_INIT="NA" - fi + # not perfect, but not too bad for now: + mapfile -t K_INITS < <(strings "$FILE" 2>/dev/null | grep -E "init=\/" | sed 's/.*rdinit/rdinit/' | sed 's/.*\ init/init/' | awk '{print $1}' | tr -d '"' | sort -u || true) + for K_INIT in "${K_INITS[@]}"; do + if [[ "$K_INIT" =~ init=\/.* ]]; then + print_output "[+] Init found in Linux kernel file $ORANGE$FILE$NC" + print_ln + print_output "$(indent "$(orange "$K_INIT")")" + print_ln + else + K_INIT="NA" + fi + done if [[ -e "$EXT_DIR"/vmlinux-to-elf/vmlinux-to-elf ]]; then print_output "[*] Testing possible Linux kernel file $ORANGE$FILE$NC with ${ORANGE}vmlinux-to-elf:$NC" @@ -95,18 +97,24 @@ S24_kernel_bin_identifier() K_VER_TMP="${K_VER/Linux version /}" demess_kv_version "$K_VER_TMP" + # -> KV_ARR if [[ "$K_ELF" == *"ELF "* ]]; then K_ELF="$(echo "$K_ELF" | cut -d: -f1)" K_SYMBOLS="$(readelf -s "$K_ELF" | grep -c "FUNC\|OBJECT" || true)" fi + # we should only get one element back, but as array for K_VER_CLEAN in "${KV_ARR[@]}"; do - # we should only get one element back, but as array - if [[ "$CFG_CNT" -gt 50 ]]; then - write_csv_log "$K_VER" "$K_VER_CLEAN" "$FILE" "$K_ELF" "$K_INIT" "$KCONFIG_EXTRACTED" "$K_SYMBOLS" + if [[ "${#K_INITS[@]}" -gt 0 ]]; then + for K_INIT in "${K_INITS[@]}"; do + if [[ "$CFG_CNT" -lt 50 ]]; then + KCONFIG_EXTRACTED="NA" + fi + write_csv_log "$K_VER" "$K_VER_CLEAN" "$FILE" "$K_ELF" "$K_INIT" "$KCONFIG_EXTRACTED" "$K_SYMBOLS" + done else - write_csv_log "$K_VER" "$K_VER_CLEAN" "$FILE" "$K_ELF" "$K_INIT" "NA" "$K_SYMBOLS" + write_csv_log "$K_VER" "$K_VER_CLEAN" "$FILE" "$K_ELF" "NA" "$KCONFIG_EXTRACTED" "$K_SYMBOLS" fi done NEG_LOG=1 diff --git a/modules/S25_kernel_check.sh b/modules/S25_kernel_check.sh index 70985b98f..49634683b 100755 --- a/modules/S25_kernel_check.sh +++ b/modules/S25_kernel_check.sh @@ -233,7 +233,8 @@ get_kernel_vulns() demess_kv_version "${KERNEL_VERSION[@]}" IFS=" " read -r -a KV_C_ARR <<< "$(echo "${KV_ARR[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')" for VER in "${KV_C_ARR[@]}" ; do - print_output "[*] Searching for possible exploits via linux-exploit-suggester.sh for kernel version $ORANGE$VER$NC" + sub_module_title "Possible exploits via linux-exploit-suggester.sh for kernel version $ORANGE$VER$NC" + print_output "[*] Search possible exploits via linux-exploit-suggester.sh for kernel version $ORANGE$VER$NC" print_output "$(indent "https://github.com/mzet-/linux-exploit-suggester")" "$EXT_DIR""/linux-exploit-suggester.sh" --skip-more-checks -f -d -k "$VER" >> "$LOG_PATH_MODULE""/linux_exploit_suggester_kernel_$VER.txt" tee -a "$LOG_FILE" < "$LOG_PATH_MODULE""/linux_exploit_suggester_kernel_$VER.txt" diff --git a/modules/S26_kernel_vuln_verifier.sh b/modules/S26_kernel_vuln_verifier.sh new file mode 100755 index 000000000..2a972ac77 --- /dev/null +++ b/modules/S26_kernel_vuln_verifier.sh @@ -0,0 +1,657 @@ +#!/bin/bash -p + +# EMBA - EMBEDDED LINUX ANALYZER +# +# Copyright 2020-2023 Siemens Energy AG +# +# EMBA comes with ABSOLUTELY NO WARRANTY. This is free software, and you are +# welcome to redistribute it under the terms of the GNU General Public License. +# See LICENSE file for usage of this software. +# +# EMBA is licensed under GPLv3 +# +# Author(s): Michael Messner + +# Description: After module s24 was able to identify the kernel, the downloader +# helper function "kernel_downloader" has downloaded the kernel sources +# This module checks if we have symbols and/or the kernel config extracted, +# identifies vulnerabilities via the version number and tries to verify the +# CVEs + +S26_kernel_vuln_verifier() +{ + module_log_init "${FUNCNAME[0]}" + module_title "Kernel vulnerability identification and verification" + pre_module_reporter "${FUNCNAME[0]}" + + HOME_DIR="$(pwd)" + # KERNEL_ARCH_PATH is the directory where we store all the kernels + KERNEL_ARCH_PATH="$EXT_DIR""/linux_kernel_sources" + S24_CSV_LOG="$CSV_DIR""/s24_kernel_bin_identifier.csv" + WAIT_PIDS_S26=() + NEG_LOG=0 + + if ! [[ -d "$KERNEL_ARCH_PATH" ]]; then + print_output "[-] Missing directory for kernel sources ... exit module now" + module_end_log "${FUNCNAME[0]}" "$NEG_LOG" + return + fi + + # we wait until the s24 module is finished and hopefully shows us a kernel version + module_wait "S24_kernel_bin_identifier" + + # now we should have a csv log with a kernel version: + if ! [[ -f "$S24_CSV_LOG" ]] || [[ "$(wc -l "$S24_CSV_LOG" | awk '{print $1}')" -lt 2 ]]; then + print_output "[-] No Kernel version file (s24 results) identified ..." + module_end_log "${FUNCNAME[0]}" "$NEG_LOG" + return + fi + + # extract kernel version + get_csv_data_s24 "$S24_CSV_LOG" + + local KERNEL_DATA="" + local KERNEL_ELF_EMBA=() + local ALL_KVULNS=() + export KERNEL_CONFIG_PATH="NA" + export KERNEL_ELF_PATH="" + + for K_VERSION in "${K_VERSIONS[@]}"; do + local K_FOUND=0 + print_output "[+] Identified kernel version: $ORANGE$K_VERSION$NC" + + mapfile -t KERNEL_ELF_EMBA < <(grep "$K_VERSION" "$S24_CSV_LOG" | cut -d\; -f4-7 | \ + grep -v "config extracted" | sort -u | sort -r -n -t\; -k4 || true) + + # we check for a kernel configuration + for KERNEL_DATA in "${KERNEL_ELF_EMBA[@]}"; do + if [[ "$(echo "$KERNEL_DATA" | cut -d\; -f3)" == "/"* ]]; then + # field 3 is the kernel config file + KERNEL_CONFIG_PATH=$(echo "$KERNEL_DATA" | cut -d\; -f3) + print_output "[+] Found kernel configuration file: $ORANGE$KERNEL_CONFIG_PATH$NC" + # we use the first entry with a kernel config detected + if [[ "$(echo "$KERNEL_DATA" | cut -d\; -f1)" == "/"* ]]; then + # field 1 is the matching kernel elf file - sometimes we have a config but no elf file + KERNEL_ELF_PATH=$(echo "$KERNEL_DATA" | cut -d\; -f1) + print_output "[+] Found kernel elf file: $ORANGE$KERNEL_ELF_PATH$NC" + K_FOUND=1 + break + fi + fi + done + + if [[ "$K_FOUND" -ne 1 ]]; then + print_output "[-] No kernel configuration file with matching elf file found for kernel $ORANGE$K_VERSION$NC." + fi + + if [[ "$K_FOUND" -ne 1 ]]; then + for KERNEL_DATA in "${KERNEL_ELF_EMBA[@]}"; do + # check for some path indicator for the elf file + if [[ "$(echo "$KERNEL_DATA" | cut -d\; -f1)" == "/"* ]]; then + # now we check for init entries + if ! [[ "$(echo "$KERNEL_DATA" | cut -d\; -f2)" == "NA" ]]; then + KERNEL_ELF_PATH=$(echo "$KERNEL_DATA" | cut -d\; -f1) + # we use the first entry with a kernel init detected + print_output "[+] Found kernel elf file with init entry: $ORANGE$KERNEL_ELF_PATH$NC" + K_FOUND=1 + break + fi + fi + done + fi + + if [[ "$K_FOUND" -ne 1 ]]; then + for KERNEL_DATA in "${KERNEL_ELF_EMBA[@]}"; do + # check for some path indicator for the elf file + if [[ "$(echo "$KERNEL_DATA" | cut -d\; -f1)" == "/"* ]]; then + # this means we have no kernel configuration found + # and no init entry -> we just use the first valid elf file + if ! [[ "$(echo "$KERNEL_DATA" | cut -d\; -f1)" == "NA" ]]; then + KERNEL_ELF_PATH=$(echo "$KERNEL_DATA" | cut -d\; -f1) + print_output "[+] Found kernel elf file: $ORANGE$KERNEL_ELF_PATH$NC" + # we use the first entry as final resort + K_FOUND=1 + break + fi + fi + done + fi + + if [[ "$K_FOUND" -ne 1 ]]; then + print_output "[-] No valid kernel information found for kernel $ORANGE$K_VERSION$NC." + continue + fi + + if ! [[ -f "$KERNEL_ELF_PATH" ]]; then + print_output "[-] Warning: Kernel ELF file not found" + module_end_log "${FUNCNAME[0]}" "$NEG_LOG" + continue + fi + if ! [[ -v K_VERSION ]]; then + print_output "[-] Missing kernel version .. exit now" + module_end_log "${FUNCNAME[0]}" "$NEG_LOG" + continue + fi + + CVE_DETAILS_PATH="$LOG_PATH_MODULE""/kernel-$K_VERSION-vulns.json" + + if ! [[ -f $PATH_CVE_SEARCH ]]; then + print_output "[-] CVE search binary search.py not found." + print_output "[-] Run the installer or install it from here: https://github.com/cve-search/cve-search." + print_output "[-] Installation instructions can be found on github.io: https://cve-search.github.io/cve-search/getting_started/installation.html#installation" + module_end_log "${FUNCNAME[0]}" "$NEG_LOG" + return + fi + + check_cve_search + + if [[ "$CVE_SEARCH" -eq 0 ]]; then + print_output "[*] Waiting for the cve-search environment ..." + sleep 120 + check_cve_search + + if [[ "$CVE_SEARCH" -eq 0 ]]; then + print_output "[*] Waiting for the cve-search environment ..." + sleep 120 + check_cve_search + fi + fi + if [[ "$CVE_SEARCH" -ne 1 ]]; then + print_cve_search_failure + return + fi + + if [[ -f "$KERNEL_ELF_PATH" ]]; then + extract_kernel_arch "$KERNEL_ELF_PATH" + fi + + if [[ "$K_VERSION" == *".0" ]]; then + K_VERSION_KORG=${K_VERSION%.0} + else + K_VERSION_KORG="$K_VERSION" + fi + # we need to wait for the downloaded linux kernel sources from the host + WAIT_CNT=0 + while ! [[ -f "$KERNEL_ARCH_PATH/linux-$K_VERSION_KORG.tar.gz" ]]; do + print_output "[*] Waiting for kernel sources ..." "no_log" + ((WAIT_CNT+=1)) + if [[ "$WAIT_CNT" -gt 60 ]] || [[ -f "$TMP_DIR"/linux_download_failed ]]; then + print_output "[-] No valid kernel source file available ... check for further kernel versions" + continue 2 + fi + sleep 5 + done + + # now we have a file with the kernel sources ... we do not know if this file is complete. + # Probably it is just downloaded partly and we need to wait a bit longer + WAIT_CNT=0 + print_output "[*] Testing kernel sources ..." "no_log" + while ! gunzip -t "$KERNEL_ARCH_PATH/linux-$K_VERSION_KORG.tar.gz" 2> /dev/null; do + print_output "[*] Testing kernel sources ..." "no_log" + ((WAIT_CNT+=1)) + if [[ "$WAIT_CNT" -gt 60 ]] || [[ -f "$TMP_DIR"/linux_download_failed ]]; then + print_output "[-] No valid kernel source file available ... check for further kernel versions" + continue 2 + fi + sleep 5 + done + + print_output "[*] Kernel sources for version $ORANGE$K_VERSION$NC available" + write_link "$LOG_DIR/kernel_downloader.log" + + KERNEL_DIR="$LOG_PATH_MODULE/linux-$K_VERSION_KORG" + if [[ -d "$KERNEL_DIR" ]]; then + rm -rf "$KERNEL_DIR" + fi + if ! [[ -d "$KERNEL_DIR" ]] && [[ "$(file "$KERNEL_ARCH_PATH/linux-$K_VERSION_KORG.tar.gz")" == *"gzip compressed data"* ]]; then + print_output "[*] Kernel version $ORANGE$K_VERSION$NC extraction ... " + tar -xzf "$KERNEL_ARCH_PATH/linux-$K_VERSION_KORG.tar.gz" -C "$LOG_PATH_MODULE" + fi + + # we get a json result file with the results in $CVE_DETAILS_PATH + get_cve_kernel_data "$K_VERSION" + + if ! [[ -f "$CVE_DETAILS_PATH" ]]; then + print_output "[-] No CVE details generated ... check for further kernel version" + continue + fi + + print_output "[*] Create CVE vulnerabilities array for kernel version $ORANGE$K_VERSION$NC ..." + mapfile -t ALL_KVULNS < <(jq -rc '"\(.id):\(.cvss):\(.cvss3):\(.summary)"' "$CVE_DETAILS_PATH") + # readable log file for the web report: + jq -rc '"\(.id):\(.cvss):\(.cvss3):\(.summary)"' "$CVE_DETAILS_PATH" > "$LOG_PATH_MODULE""/kernel-$K_VERSION-vulns.log" + + print_ln + print_output "[+] Extracted $ORANGE${#ALL_KVULNS[@]}$GREEN vulnerabilities based on kernel version only" "" "$LOG_PATH_MODULE""/kernel-$K_VERSION-vulns.log" + + if [[ -f "$KERNEL_CONFIG_PATH" ]] && [[ -d "$KERNEL_DIR" ]]; then + compile_kernel "$KERNEL_CONFIG_PATH" "$KERNEL_DIR" "$ORIG_K_ARCH" + fi + + print_ln + sub_module_title "Identify kernel symbols ..." + readelf -s "$KERNEL_ELF_PATH" | grep "FUNC\|OBJECT" | sed 's/.*FUNC//' | sed 's/.*OBJECT//' | awk '{print $4}' | \ + sed 's/\[\.\.\.\]//' > "$LOG_PATH_MODULE"/symbols.txt + SYMBOLS_CNT=$(wc -l "$LOG_PATH_MODULE"/symbols.txt | awk '{print $1}') + print_output "[*] Extracted $ORANGE$SYMBOLS_CNT$NC symbols from kernel" + + if [[ -d "$LOG_DIR""/firmware" ]]; then + print_output "[*] Identify kernel modules symbols ..." + find "$LOG_DIR/firmware" -name "*.ko" -exec readelf -a {} \; | grep FUNC | sed 's/.*FUNC//' | \ + awk '{print $4}' | sed 's/\[\.\.\.\]//' >> "$LOG_PATH_MODULE"/symbols.txt + fi + + uniq "$LOG_PATH_MODULE"/symbols.txt > "$LOG_PATH_MODULE"/symbols_uniq.txt + SYMBOLS_CNT=$(wc -l "$LOG_PATH_MODULE"/symbols_uniq.txt | awk '{print $1}') + + if [[ "$SYMBOLS_CNT" -eq 0 ]]; then + print_output "[-] No symbols found ... check for further kernel version" + continue + fi + + print_ln + print_output "[+] Extracted $ORANGE$SYMBOLS_CNT$GREEN unique symbols" + print_ln + + split_symbols_file + + sub_module_title "Linux kernel vulnerability verification" + + export CNT_PATHS_UNK=0 + export CNT_PATHS_FOUND=0 + export CNT_PATHS_NOT_FOUND=0 + export VULN_CNT=1 + export CNT_PATHS_FOUND_WRONG_ARCH=0 + + print_ln + print_output "[*] Checking vulnerabilities for kernel version $ORANGE$K_VERSION$NC" + print_ln + + for VULN in "${ALL_KVULNS[@]}"; do + NEG_LOG=1 + K_PATHS=() + K_PATHS_FILES_TMP=() + K_PATH="missing vulnerability path from advisory" + + CVE=$(echo "$VULN" | cut -d: -f1) + print_output "[*] Testing vulnerability $ORANGE$VULN_CNT$NC / $ORANGE${#ALL_KVULNS[@]}$NC / $ORANGE$CVE$NC" + + CVSS2="$(echo "$VULN" | cut -d: -f2)" + CVSS3="$(echo "$VULN" | cut -d: -f3)" + SUMMARY="$(echo "$VULN" | cut -d: -f4-)" + + # extract kernel source paths from summary -> we use these paths to check if they are used by our + # symbols or during kernel compilation + mapfile -t K_PATHS < <(echo "$SUMMARY" | tr ' ' '\n' | grep ".*\.[chS]$" | sed -r 's/CVE-[0-9]+-[0-9]+:[0-9].*://' \ + | sed -r 's/CVE-[0-9]+-[0-9]+:null.*://' | sed 's/^(//' | sed 's/)$//' | sed 's/,$//' | sed 's/\.$//' | cut -d: -f1 || true) + + for K_PATH in "${K_PATHS[@]}"; do + # we have only a filename without path -> we search for possible candidate files in the kernel sources + if ! [[ "$K_PATH" == *"/"* ]]; then + print_output "[*] Found file name $ORANGE$K_PATH$NC for $ORANGE$CVE$NC without path details ... looking for candidates now" + mapfile -t K_PATHS_FILES_TMP < <(find "$KERNEL_DIR" -name "$K_PATH" | sed "s&$KERNEL_DIR\/&&") + fi + K_PATHS+=("${K_PATHS_FILES_TMP[@]}") + done + + if [[ "${#K_PATHS[@]}" -gt 0 ]]; then + for K_PATH in "${K_PATHS[@]}"; do + if [[ -f "$KERNEL_DIR/$K_PATH" ]]; then + # check if arch is in path -> if so we check if our architecture is also in the path + # if we find our architecture then we can proceed with symbol_verifier + if [[ "$K_PATH" == "arch/"* ]]; then + if [[ "$K_PATH" == "arch/$ORIG_K_ARCH/"* ]]; then + ((CNT_PATHS_FOUND+=1)) + symbol_verifier "$CVE" "$K_VERSION" "$K_PATH" "$CVSS2/$CVSS3" & + WAIT_PIDS_S26+=( "$!" ) + compile_verifier "$CVE" "$K_VERSION" "$K_PATH" "$CVSS2/$CVSS3" & + WAIT_PIDS_S26+=( "$!" ) + else + # this vulnerability is for a different architecture -> we can skip it for our kernel + print_output "[-] Vulnerable path for different architecture found for $ORANGE$K_PATH$NC - not further processing $ORANGE$CVE$NC" + ((CNT_PATHS_FOUND_WRONG_ARCH+=1)) + fi + else + ((CNT_PATHS_FOUND+=1)) + symbol_verifier "$CVE" "$K_VERSION" "$K_PATH" "$CVSS2/$CVSS3" & + WAIT_PIDS_S26+=( "$!" ) + compile_verifier "$CVE" "$K_VERSION" "$K_PATH" "$CVSS2/$CVSS3" & + WAIT_PIDS_S26+=( "$!" ) + fi + else + # no source file in our kernel sources -> no vulns + print_output "[-] $ORANGE$CVE$NC - $ORANGE$K_PATH$NC - vulnerable source file not found in kernel sources" + ((CNT_PATHS_NOT_FOUND+=1)) + fi + max_pids_protection 20 "${WAIT_PIDS_S26[@]}" + done + else + print_output "[-] $CVE - $K_PATH" + ((CNT_PATHS_UNK+=1)) + fi + ((VULN_CNT+=1)) + done + + wait_for_pid "${WAIT_PIDS_S26[@]}" + + final_log_kernel_vulns "$K_VERSION" "${ALL_KVULNS[@]}" + done + + module_end_log "${FUNCNAME[0]}" "$NEG_LOG" +} + +split_symbols_file() { + print_output "[*] Splitting symbols file for processing" + split -l 100 "$LOG_PATH_MODULE"/symbols_uniq.txt "$LOG_PATH_MODULE"/symbols_uniq.split. + sed -i 's/^/EXPORT_SYMBOL\(/' "$LOG_PATH_MODULE"/symbols_uniq.split.* + sed -i 's/$/\)/' "$LOG_PATH_MODULE"/symbols_uniq.split.* + + split -l 100 "$LOG_PATH_MODULE"/symbols_uniq.txt "$LOG_PATH_MODULE"/symbols_uniq.split_gpl. + sed -i 's/^/EXPORT_SYMBOL_GPL\(/' "$LOG_PATH_MODULE"/symbols_uniq.split_gpl.* + sed -i 's/$/\)/' "$LOG_PATH_MODULE"/symbols_uniq.split_gpl.* +} + +get_cve_kernel_data() { + sub_module_title "Version based vulnerability detection" + local K_VERSION_="${1:-}" + print_output "[*] Extract CVE data for kernel version $ORANGE$K_VERSION_$NC" + "$PATH_CVE_SEARCH" -p "linux_kernel:""$K_VERSION_"":" -o json > "$CVE_DETAILS_PATH" +} + +extract_kernel_arch() { + KERNEL_ELF_PATH="${1:-}" + ORIG_K_ARCH=$(file "$KERNEL_ELF_PATH" | cut -d, -f2) + + # for ARM -> ARM aarch64 to ARM64 + ORIG_K_ARCH=${ORIG_K_ARCH/ARM\ aarch64/arm64} + # for MIPS64 -> MIPS64 to MIPS + ORIG_K_ARCH=${ORIG_K_ARCH/MIPS64/MIPS} + ORIG_K_ARCH=${ORIG_K_ARCH/*PowerPC*/powerpc} + + ORIG_K_ARCH=$(echo "$ORIG_K_ARCH" | tr -d ' ' | tr "[:upper:]" "[:lower:]") + print_output "[+] Identified kernel architecture $ORANGE$ORIG_K_ARCH$NC" +} + +symbol_verifier() { + local CVE="${1:-}" + local K_VERSION="${2:-}" + local K_PATH="${3:-}" + local CVSS="${4:-}" + local VULN_FOUND=0 + + for CHUNK_FILE in "$LOG_PATH_MODULE"/symbols_uniq.split.* ; do + # echo "testing chunk file $CHUNK_FILE" + if grep -q -f "$CHUNK_FILE" "$KERNEL_DIR/$K_PATH" ; then + # echo "verified chunk file $CHUNK_FILE" + print_output "[+] $CVE ($CVSS) - $K_PATH verified - exported symbol$NC" + echo "$CVE ($CVSS) - $K_VERSION - exported symbol verified - $K_PATH" >> "$LOG_PATH_MODULE""/${CVE}_symbol_verified.txt" + VULN_FOUND=1 + break + fi + done + + if [[ "$VULN_FOUND" -eq 1 ]]; then + # if we have already a match for this path we can skip the 2nd check + # this is only for speed up the process a bit + return + fi + + for CHUNK_FILE in "$LOG_PATH_MODULE"/symbols_uniq.split_gpl.* ; do + # echo "testing chunk file $CHUNK_FILE" + if grep -q -f "$CHUNK_FILE" "$KERNEL_DIR/$K_PATH" ; then + # print_output "[*] verified chunk file $CHUNK_FILE (GPL)" + print_output "[+] $CVE ($CVSS) - $K_PATH verified - exported symbol (gpl)$NC" + echo "$CVE ($CVSS) - $K_VERSION - exported symbol verified (gpl) - $K_PATH" >> "$LOG_PATH_MODULE""/${CVE}_symbol_verified.txt" + VULN_FOUND=1 + break + fi + done +} + +compile_verifier() { + local CVE_="${1:-}" + local K_VERSION="${2:-}" + local K_PATH="${3:-}" + local CVSS="${4:-}" + local VULN_FOUND=0 + if ! [[ -f "$LOG_PATH_MODULE"/kernel-compile-files.log ]]; then + return + fi + + if grep -q "$K_PATH" "$LOG_PATH_MODULE"/kernel-compile-files.log ; then + print_output "[+] $CVE_ ($CVSS) - $K_PATH verified - compiled path" + echo "$CVE_ ($CVSS) - $K_VERSION - compiled path verified - $K_PATH" >> "$LOG_PATH_MODULE""/${CVE_}_compiled_verified.txt" + fi +} + +compile_kernel() { + # this is based on the great work shown here https://arxiv.org/pdf/2209.05217.pdf + local KERNEL_CONFIG_FILE="${1:-}" + local KERNEL_DIR="${2:-}" + local KARCH="${3:-}" + export COMPILE_SOURCE_FILES=0 + + if ! [[ -f "$KERNEL_CONFIG_FILE" ]]; then + print_output "[-] No supported kernel config found - $ORANGE$KERNEL_CONFIG_FILE$NC" + return + fi + if ! [[ -d "$KERNEL_DIR" ]]; then + print_output "[-] No supported kernel source directory found - $ORANGE$KERNEL_DIR$NC" + return + fi + sub_module_title "Compile Linux kernel - dry run mode" + + KARCH=$(echo "$KARCH" | tr '[:upper:]' '[:lower:]') + if ! [[ -d "$KERNEL_DIR"/arch/"$KARCH" ]]; then + print_output "[!] No supported architecture found - $ORANGE$KARCH$NC" + return + fi + + cd "$KERNEL_DIR" || exit + # print_output "[*] Create default kernel config for $ORANGE$KARCH$NC architecture" + # LANG=en make ARCH="$KARCH" defconfig | tee -a "$LOG_PATH_MODULE"/kernel-compile-defconfig.log || true + # print_output "[*] Finished creating default kernel config for $ORANGE$KARCH$NC architecture" "" "$LOG_PATH_MODULE/kernel-compile-defconfig.log" + print_ln + print_output "[*] Install kernel config of the identified configuration of the firmware" + cp "$KERNEL_CONFIG_FILE" .config + # https://stackoverflow.com/questions/4178526/what-does-make-oldconfig-do-exactly-in-the-linux-kernel-makefile + LANG=en make ARCH="$KARCH" olddefconfig | tee -a "$LOG_PATH_MODULE"/kernel-compile-olddefconfig.log + print_output "[*] Finished updating kernel config with the identified firmware configuration" "" "$LOG_PATH_MODULE/kernel-compile-olddefconfig.log" + print_ln + print_output "[*] Starting kernel compile dry run ..." + LANG=en make ARCH="$KARCH" target=all -Bndi | tee -a "$LOG_PATH_MODULE"/kernel-compile.log + print_ln + print_output "[*] Finished kernel compile dry run ... generated used source files" "" "$LOG_PATH_MODULE/kernel-compile.log" + cd "$HOME_DIR" || exit + if [[ -f "$LOG_PATH_MODULE"/kernel-compile.log ]]; then + tr ' ' '\n' < "$LOG_PATH_MODULE"/kernel-compile.log | grep ".*\.[chS]" | tr -d '"' | tr -d ')' \ + | tr -d '(' | sed 's/^\.\///' | sed '/^\/.*/d' | tr -d ';' | sed 's/^>//' | sed 's/^-o//' | tr -d \' \ + | sed 's/--defines=//' | sed 's/\.$//' | sort -u > "$LOG_PATH_MODULE"/kernel-compile-files.log + COMPILE_SOURCE_FILES=$(wc -l "$LOG_PATH_MODULE"/kernel-compile-files.log | awk '{print $1}') + print_ln + print_output "[+] Found $ORANGE$COMPILE_SOURCE_FILES$GREEN used source files during compilation" "" "$LOG_PATH_MODULE/kernel-compile-files.log" + else + print_output "[-] Found ${RED}NO$NC used source files during compilation" + fi +} + +final_log_kernel_vulns() { + sub_module_title "Linux kernel verification results" + local K_VERSION="${1:-}" + shift + local ALL_KVULNS=("$@") + + if ! [[ -v ALL_KVULNS ]]; then + print_output "[-] No module results" + return + fi + + find "$LOG_PATH_MODULE" -name "symbols_uniq.split.*" -delete || true + find "$LOG_PATH_MODULE" -name "symbols_uniq.split_gpl.*" -delete || true + + NEG_LOG=1 + + local VULN="" + local SYM_USAGE_VERIFIED=0 + local VULN_PATHS_VERIFIED_SYMBOLS=0 + local VULN_PATHS_VERIFIED_COMPILED=0 + local CVE_VERIFIED_SYMBOLS=0 + local CVE_VERIFIED_COMPILED=0 + local CVE_VERIFIED_ONE=0 + local CVE_VERIFIED_OVERLAP=0 + local CVE_VERIFIED_OVERLAP_CRITICAL=() + local CVE_VERIFIED_ONE_CRITICAL=() + + print_ln + print_output "[*] Generating final kernel report ..." "no_log" + echo "Kernel version;Architecture;CVE;CVSSv2;CVSSv3;Verified with symbols;Verified with compile files" >> "$LOG_PATH_MODULE"/cve_results_kernel_"$K_VERSION".csv + + # we walk through the original version based kernel vulnerabilities and report the results + # from symbols and kernel configuration + for VULN in "${ALL_KVULNS[@]}"; do + local CVE="" + local CVSS2="" + local CVSS3="" + local CVE_SYMBOL_FOUND=0 + local CVE_COMPILE_FOUND=0 + local CVE_SYMBOL_FOUND=0 + local CVE_COMPILE_FOUND=0 + + CVE=$(echo "$VULN" | cut -d: -f1) + CVSS2="$(echo "$VULN" | cut -d: -f2)" + CVSS3="$(echo "$VULN" | cut -d: -f3)" + CVE_SYMBOL_FOUND=$(find "$LOG_PATH_MODULE" -name "${CVE}_symbol_verified.txt" | wc -l) + CVE_COMPILE_FOUND=$(find "$LOG_PATH_MODULE" -name "${CVE}_compiled_verified.txt" | wc -l) + echo "$K_VERSION;$ORIG_K_ARCH;$CVE;$CVSS2;$CVSS3;$CVE_SYMBOL_FOUND;$CVE_COMPILE_FOUND" >> "$LOG_PATH_MODULE"/cve_results_kernel_"$K_VERSION".csv + done + + SYM_USAGE_VERIFIED=$(wc -l "$LOG_PATH_MODULE"/CVE-*symbol_* | tail -1 | awk '{print $1}' 2>/dev/null || true) + # nosemgrep + VULN_PATHS_VERIFIED_SYMBOLS=$(cat "$LOG_PATH_MODULE"/CVE-*symbol_verified.txt 2>/dev/null | grep "exported symbol" | sed 's/.*verified - //' | sed 's/.*verified (GPL) - //' | sort -u | wc -l || true) + # nosemgrep + VULN_PATHS_VERIFIED_COMPILED=$(cat "$LOG_PATH_MODULE"/CVE-*compiled_verified.txt 2>/dev/null | grep "compiled path verified" | sed 's/.*verified - //' | sort -u | wc -l || true) + # nosemgrep + CVE_VERIFIED_SYMBOLS=$(cat "$LOG_PATH_MODULE"/CVE-*symbol_verified.txt 2>/dev/null | grep "exported symbol" | cut -d\ -f1 | sort -u | wc -l || true) + # nosemgrep + CVE_VERIFIED_COMPILED=$(cat "$LOG_PATH_MODULE"/CVE-*compiled_verified.txt 2>/dev/null| grep "compiled path verified" | cut -d\ -f1 | sort -u | wc -l || true) + CVE_VERIFIED_ONE=$(cut -d\; -f6-7 "$LOG_PATH_MODULE"/cve_results_kernel_"$K_VERSION".csv | grep -c "1" || true) + CVE_VERIFIED_OVERLAP=$(grep -c ";1;1" "$LOG_PATH_MODULE"/cve_results_kernel_"$K_VERSION".csv || true) + mapfile -t CVE_VERIFIED_OVERLAP_CRITICAL < <(grep ";1;1$" "$LOG_PATH_MODULE"/cve_results_kernel_"$K_VERSION".csv | grep ";9.[0-9];\|;10;" || true) + mapfile -t CVE_VERIFIED_ONE_CRITICAL < <(grep ";1;\|;1$" "$LOG_PATH_MODULE"/cve_results_kernel_"$K_VERSION".csv | grep ";9.[0-9];\|;10;" || true) + + print_output "[+] Identified $ORANGE${#ALL_KVULNS[@]}$GREEN unverified CVE vulnerabilities for kernel version $ORANGE$K_VERSION$NC" + print_output "[*] Detected architecture $ORANGE$ORIG_K_ARCH$NC" + print_output "[*] Extracted $ORANGE$SYMBOLS_CNT$NC unique symbols from kernel and modules" + if [[ -v COMPILE_SOURCE_FILES ]]; then + print_output "[*] Extracted $ORANGE$COMPILE_SOURCE_FILES$NC used source files during compilation" + fi + print_output "[*] Found $ORANGE$CNT_PATHS_UNK$NC advisories with missing vulnerable path details" + print_output "[*] Found $ORANGE$CNT_PATHS_NOT_FOUND$NC path details in CVE advisories but no real kernel path found in vanilla kernel source" + print_output "[*] Found $ORANGE$CNT_PATHS_FOUND$NC path details in CVE advisories with real kernel path" + print_output "[*] Found $ORANGE$CNT_PATHS_FOUND_WRONG_ARCH$NC path details in CVE advisories with real kernel path but wrong architecture" + print_output "[*] $ORANGE$SYM_USAGE_VERIFIED$NC symbol usage verified" + print_output "[*] $ORANGE$VULN_PATHS_VERIFIED_SYMBOLS$NC vulnerable paths verified via symbols" + print_output "[*] $ORANGE$VULN_PATHS_VERIFIED_COMPILED$NC vulnerable paths verified via compiled paths" + print_ln + + if [[ "$CVE_VERIFIED_SYMBOLS" -gt 0 ]]; then + print_output "[+] Verified CVEs: $ORANGE$CVE_VERIFIED_SYMBOLS$GREEN (exported symbols)" + fi + if [[ "$CVE_VERIFIED_COMPILED" -gt 0 ]]; then + print_output "[+] Verified CVEs: $ORANGE$CVE_VERIFIED_COMPILED$GREEN (compiled paths)" + fi + if [[ "$CVE_VERIFIED_ONE" -gt 0 ]]; then + print_output "[+] Verified CVEs: $ORANGE$CVE_VERIFIED_ONE$GREEN (one mechanism succeeded)" + fi + if [[ "$CVE_VERIFIED_OVERLAP" -gt 0 ]]; then + print_output "[+] Verified CVEs: $ORANGE$CVE_VERIFIED_OVERLAP$GREEN (both mechanisms overlap)" + fi + + if [[ "${#CVE_VERIFIED_ONE_CRITICAL[@]}" -gt 0 ]]; then + print_ln + print_output "[+] Verified CRITICAL CVEs: $ORANGE${#CVE_VERIFIED_ONE_CRITICAL[@]}$GREEN (one mechanism succeeded)" + for CVE_VERIFIED_ONE_CRITICAL_ in "${CVE_VERIFIED_ONE_CRITICAL[@]}"; do + CVE_CRITICAL=$(echo "$CVE_VERIFIED_ONE_CRITICAL_" | cut -d\; -f3) + CVSS2_CRITICAL=$(echo "$CVE_VERIFIED_ONE_CRITICAL_" | cut -d\; -f4) + CVSS3_CRITICAL=$(echo "$CVE_VERIFIED_ONE_CRITICAL_" | cut -d\; -f5) + identify_exploits "$CVE_CRITICAL" + print_output "$(indent "$(orange "$ORANGE$CVE_CRITICAL$GREEN\t-\t$ORANGE$CVSS2_CRITICAL$GREEN / $ORANGE$CVSS3_CRITICAL$GREEN\t-\tExploit/PoC: $ORANGE$EXPLOIT_DETECTED $EXP / $POC_DETECTED $POC$NC")")" + done + fi + + if [[ "${#CVE_VERIFIED_OVERLAP_CRITICAL[@]}" -gt 0 ]]; then + print_ln + print_output "[+] Verified CRITICAL CVEs: $ORANGE${#CVE_VERIFIED_OVERLAP_CRITICAL[@]}$GREEN (both mechanisms overlap)" + for CVE_VERIFIED_OVERLAP_CRITICAL_ in "${CVE_VERIFIED_OVERLAP_CRITICAL[@]}"; do + CVE_CRITICAL=$(echo "$CVE_VERIFIED_OVERLAP_CRITICAL_" | cut -d\; -f3) + CVSS2_CRITICAL=$(echo "$CVE_VERIFIED_OVERLAP_CRITICAL_" | cut -d\; -f4) + CVSS3_CRITICAL=$(echo "$CVE_VERIFIED_OVERLAP_CRITICAL_" | cut -d\; -f5) + identify_exploits "$CVE_CRITICAL" + print_output "$(indent "$(orange "$ORANGE$CVE_CRITICAL$GREEN\t-\t$ORANGE$CVSS2_CRITICAL$GREEN / $ORANGE$CVSS3_CRITICAL$GREEN\t-\tExploit/PoC: $ORANGE$EXPLOIT_DETECTED $EXP / $POC_DETECTED $POC$NC")")" + done + fi + write_log "[*] Statistics:$K_VERSION:${#ALL_KVULNS[@]}:$CVE_VERIFIED_SYMBOLS:$CVE_VERIFIED_COMPILED" +} + +identify_exploits() { + local CVE_VALUE="${1:-}" + export EXPLOIT_DETECTED="no" + export POC_DETECTED="no" + export POC="" + export EXP="" + + local MSF_DB_PATH="$CONFIG_DIR/msf_cve-db.txt" + local KNOWN_EXP_CSV="$EXT_DIR/known_exploited_vulnerabilities.csv" + + if command -v cve_searchsploit >/dev/null; then + if cve_searchsploit "$CVE_VALUE" 2>/dev/null | grep -q "Exploit DB Id:"; then + EXPLOIT_DETECTED="yes" + EXP="(EDB)" + fi + fi + if [[ -f "$MSF_DB_PATH" ]]; then + if grep -q -E "$CVE_VALUE"$ "$MSF_DB_PATH"; then + EXPLOIT_DETECTED="yes" + EXP="$EXP(MSF)" + fi + fi + if [[ -f "$KNOWN_EXP_CSV" ]]; then + if grep -q \""${CVE_VALUE}"\", "$KNOWN_EXP_CSV"; then + EXPLOIT_DETECTED="yes" + EXP="$EXP(KNOWN)" + fi + fi + if [[ -f "$TRICKEST_DB_PATH" ]]; then + if grep -q -E "$CVE_VALUE\.md" "$TRICKEST_DB_PATH"; then + POC_DETECTED="yes" + POC="$POC(GH)" + fi + fi + if [[ -f "$CONFIG_DIR/Snyk_PoC_results.csv" ]]; then + if grep -q -E "^$CVE_VALUE;" "$CONFIG_DIR/Snyk_PoC_results.csv"; then + POC_DETECTED="yes" + POC="$POC(SNYK)" + fi + fi + if [[ -f "$CONFIG_DIR/PS_PoC_results.csv" ]]; then + if grep -q -E "^$CVE_VALUE;" "$CONFIG_DIR/PS_PoC_results.csv"; then + POC_DETECTED="yes" + POC="$POC(PS)" + fi + fi +} + +get_csv_data_s24() { + local S24_CSV_LOG="${1:-}" + + if ! [[ -f "$S24_CSV_LOG" ]];then + print_output "[-] No EMBA log found ..." + return + fi + + export K_VERSIONS=() + + # currently we only support one kernel version + # if we detect multiple kernel versions we only process the first one after sorting + mapfile -t K_VERSIONS < <(cut -d\; -f2 "$S24_CSV_LOG" | tail -n +2 | grep -v "NA" | sort -u) +}