diff --git a/README.md b/README.md index 00041338..40b68ffd 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Dependency check -d Only check dependencies -F Check dependencies but ignore errors -Test kernel config +Special tests -k [./config] Kernel config path Modify output @@ -126,6 +126,7 @@ For using _emba_ with all features, you will need following tools on your __Kali - `Option: docker` - `Option: yara` - `Option: qemu static user mode emulators` +- `Option: binwalk` To check these dependencies, only run `sudo ./emba.sh -d` diff --git a/emba.sh b/emba.sh index baa39ac6..d5257a3a 100755 --- a/emba.sh +++ b/emba.sh @@ -64,6 +64,8 @@ main() export ONLY_DEP=0 # test only dependency export FORCE=0 export QEMULATION=0 + export PRE_CHECK=0 # test and extract binary files with binwalk + # afterwards do a default emba scan export LOG_DIR="./logs" export CONFIG_DIR="./config" @@ -86,7 +88,7 @@ main() exit 1 fi - while getopts a:A:cde:Ef:Fhk:l:m:psvz OPT ; do + while getopts a:A:cde:Ef:Fhk:l:m:sz OPT ; do case $OPT in a) export ARCH="$OPTARG" @@ -151,15 +153,26 @@ main() FIRMWARE_PATH="$(abs_path "$FIRMWARE_PATH")" + echo + if [[ -d "$FIRMWARE_PATH" ]]; then + PRE_CHECK=0 + print_output "[*] Firmware directory detected." "no_log" + print_output "[*] Emba starts with testing the environment." "no_log" + elif [[ -f "$FIRMWARE_PATH" ]]; then + PRE_CHECK=1 + print_output "[*] Firmware binary detected." "no_log" + print_output "[*] Emba starts with some basic tests on it." "no_log" + else + print_output "[-] Invalid firmware file" "no_log" + print_help + exit 1 + fi + if [[ $ONLY_DEP -eq 0 ]] ; then # check if LOG_DIR exists and prompt to terminal to delete its content (y/n) log_folder set_exclude - - if [[ $KERNEL -eq 0 ]] ; then - architecture_check - fi fi dependency_check @@ -176,9 +189,53 @@ main() fi fi + if [[ $PRE_CHECK -eq 1 ]] ; then + if [[ -f "$FIRMWARE_PATH" ]]; then + + echo + print_output "[!] Extraction started on ""$(date)""\\n""$(indent "$NC""Firmware binary path: ""$FIRMWARE_PATH")" "no_log" + + # 'main' functions of imported modules + # in the pre-check phase we execute all modules with P[Number]_Name.sh + + if [[ ${#SELECT_MODULES[@]} -eq 0 ]] ; then + local MODULES + MODULES=$(find "$MOD_DIR" -name "P*_*.sh" | sort -V 2> /dev/null) + for MODULE_FILE in $MODULES ; do + if ( file "$MODULE_FILE" | grep -q "shell script" ) ; then + MODULE_BN=$(basename "$MODULE_FILE") + MODULE_MAIN=${MODULE_BN%.*} + $MODULE_MAIN + fi + done + else + for SELECT_NUM in "${SELECT_MODULES[@]}" ; do + local MODULE + MODULE=$(find "$MOD_DIR" -name "P""$SELECT_NUM""_*.sh" | sort -V 2> /dev/null) + if ( file "$MODULE" | grep -q "shell script" ) ; then + MODULE_BN=$(basename "$MODULE") + MODULE_MAIN=${MODULE_BN%.*} + $MODULE_MAIN + fi + done + fi + + echo + print_output "[!] Extraction ended on ""$(date)"" and took about ""$(date -d@$SECONDS -u +%H:%M:%S)"" \\n" "no_log" + + fi + fi + if [[ $FIRMWARE -eq 1 ]] ; then if [[ -d "$FIRMWARE_PATH" ]]; then + echo + print_output "=================================================================\n" "no_log" + + if [[ $KERNEL -eq 0 ]] ; then + architecture_check + fi + check_firmware prepare_binary_arr diff --git a/helpers/dependency_check.sh b/helpers/dependency_check.sh index bcc2e3c4..bf179a41 100644 --- a/helpers/dependency_check.sh +++ b/helpers/dependency_check.sh @@ -38,7 +38,7 @@ dependency_check() echo -e "$RED"" This script is only tested on KALI linux""$NC" 1>&2 fi - if [[ $ONLY_DEP -eq 1 ]] && [[ -z "$ARCH" ]] ; then + if [[ $ONLY_DEP -eq 1 ]] && [[ -z "$ARCH" ]] || [[ "$PRE_CHECK" -eq 1 ]]; then print_output " architecture - ""$ORANGE""not checked""$NC" "no_log" elif [[ $FIRMWARE -eq 1 ]] || { [[ $ONLY_DEP -eq 1 ]] && [[ -n "$ARCH" ]] ; } ; then print_output " architecture - \\c" "no_log" diff --git a/helpers/print.sh b/helpers/print.sh index 74f6eb2d..612a92bf 100644 --- a/helpers/print.sh +++ b/helpers/print.sh @@ -266,7 +266,7 @@ print_help() echo -e "$CYAN""-a [MIPS]""$NC"" Architecture of the linux firmware [MIPS, ARM, x86, x64, PPC]" echo -e "$CYAN""-A [MIPS]""$NC"" Force Architecture of the linux firmware [MIPS, ARM, x86, x64, PPC] (disable architecture check)" echo -e "$CYAN""-l [./path]""$NC"" Log path" - echo -e "$CYAN""-f [./path]""$NC"" Firmware path" + echo -e "$CYAN""-f [./path]""$NC"" Extracted firmware root directory path" echo -e "$CYAN""-e [./path]""$NC"" Exclude paths from testing (multiple usage possible)" echo -e "$CYAN""-m [MODULE_NO.]""$NC"" Test only with set modules [e.g. -m 05 -m 10 ... ]] (multiple usage possible)" echo -e "$CYAN""-c""$NC"" Enable cwe-checker" @@ -274,7 +274,7 @@ print_help() echo -e "\\nDependency check" echo -e "$CYAN""-d""$NC"" Only check dependencies" echo -e "$CYAN""-F""$NC"" Check dependencies but ignore errors" - echo -e "\\nTest kernel config" + echo -e "\\nSpecial tests" echo -e "$CYAN""-k [./config]""$NC"" Kernel config path" echo -e "\\nModify output" echo -e "$CYAN""-s""$NC"" Print only relative paths" diff --git a/installer.sh b/installer.sh index c500df55..0475e4fb 100755 --- a/installer.sh +++ b/installer.sh @@ -35,7 +35,14 @@ apt-get install shellcheck -y apt-get install device-tree-compiler -y apt-get install docker.io -y apt-get install unzip -y -apt-get install qemu-user-static -y +if ! command -v qemu-mips-static > /dev/null ; then + echo -e "\\n""$ORANGE""$BOLD""Install qemu package""$NC" + apt-get install qemu-user-static -y +fi +if ! command -v binwalk > /dev/null ; then + echo -e "\\n""$ORANGE""$BOLD""Install binwalk package""$NC" + apt-get install binwalk -y +fi if ! [[ -d "external" ]] ; then @@ -144,6 +151,9 @@ if ! [[ -f "external/objdump" ]] ; then if [[ -f "external/binutils-2.34/binutils/objdump" ]] ; then mv "external/binutils-2.34/binutils/objdump" "external/objdump" rm -R external/binutils-2.34 + if [[ -f "external/objdump" ]] ; then + echo -e "$GREEN""objdump installed successfully""$NC" + fi else echo -e "$ORANGE""objdump installation failed - check it manually""$NC" fi @@ -151,19 +161,19 @@ else echo -e "$ORANGE""objdump is already downloaded and compiled""$NC" fi -# aha for html generation -echo -e "\\n""$ORANGE""$BOLD""Downloading aha""$NC" -if ! [[ -f "external/aha" ]] ; then - apt-get install make - wget https://github.com/theZiz/aha/archive/master.zip -O external/aha-master.zip - unzip ./external/aha-master.zip -d ./external - rm external/aha-master.zip - cd ./external/aha-master || exit 1 - echo -e "$ORANGE""$BOLD""Compile aha""$NC" - make - cd ../.. || exit 1 - mv "external/aha-master/aha" "external/aha" - rm -R external/aha-master -else - echo -e "$ORANGE""aha is already downloaded and compiled""$NC" -fi +# aha for html generation - future extension of emba +#echo -e "\\n""$ORANGE""$BOLD""Downloading aha""$NC" +#if ! [[ -f "external/aha" ]] ; then +# apt-get install make +# wget https://github.com/theZiz/aha/archive/master.zip -O external/aha-master.zip +# unzip ./external/aha-master.zip -d ./external +# rm external/aha-master.zip +# cd ./external/aha-master || exit 1 +# echo -e "$ORANGE""$BOLD""Compile aha""$NC" +# make +# cd ../.. || exit 1 +# mv "external/aha-master/aha" "external/aha" +# rm -R external/aha-master +#else +# echo -e "$ORANGE""aha is already downloaded and compiled""$NC" +#fi diff --git a/modules/P02_firmware_bin_file_check.sh b/modules/P02_firmware_bin_file_check.sh new file mode 100644 index 00000000..aa2eddcb --- /dev/null +++ b/modules/P02_firmware_bin_file_check.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# emba - EMBEDDED LINUX ANALYZER +# +# Copyright 2020 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, Pascal Eckmann + +P02_firmware_bin_file_check() { + module_log_init "firmware_bin_file_log" + module_title "Binary firmware file analyzer" + + local FILE_BIN_OUT + FILE_BIN_OUT=$(file "$FIRMWARE_PATH") + local FILE_LS_OUT + FILE_LS_OUT=$(ls -lh "$FIRMWARE_PATH") + + print_output "[*] Details of the binary file:" + print_output "$(indent "$FILE_LS_OUT")" + print_output "$(indent "$FILE_BIN_OUT")" + + # probably we can do a lot more stuff in the future ... +} diff --git a/modules/P05_firmware_bin_extractor.sh b/modules/P05_firmware_bin_extractor.sh new file mode 100644 index 00000000..4927b56b --- /dev/null +++ b/modules/P05_firmware_bin_extractor.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# emba - EMBEDDED LINUX ANALYZER +# +# Copyright 2020 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, Pascal Eckmann + +P05_firmware_bin_extractor() { + module_log_init "firmware_bin_extractor_log" + module_title "Binary firmware extractor" + + binwalking + # probably we can do something more in the future +} + +binwalking() { + sub_module_title "Analyze binary firmware blob with binwalk" + + local MAIN_BINWALK + print_output "[*] basic analysis with binwalk" + MAIN_BINWALK=$(binwalk "$FIRMWARE_PATH") + echo "$MAIN_BINWALK" + + echo + print_output "[*] Entropy testing with binwalk ... " + print_output "$(binwalk -E -F -J "$FIRMWARE_PATH")" + mv "$(basename "$FIRMWARE_PATH".png)" "$LOG_DIR"/"$(basename "$FIRMWARE_PATH"_entropy.png)" 2> /dev/null + + # This test takes a long time and so I have removed it + # we come back to this topic later on - leave it here for the future + #print_output "\n[*] Architecture testing with binwalk ... could take a while" + #binwalk -Y "$FIRMWARE_BIN_PATH" + + OUTPUT_DIR=$(basename "$FIRMWARE_PATH") + OUTPUT_DIR="$LOG_DIR"/"$OUTPUT_DIR"_binwalk_emba + + echo + print_output "[*] Extracting firmware to directory $OUTPUT_DIR" + print_output "$(binwalk -e -M -C "$OUTPUT_DIR" "$FIRMWARE_PATH")" +} diff --git a/modules/P07_firmware_bin_base_analyzer.sh b/modules/P07_firmware_bin_base_analyzer.sh new file mode 100644 index 00000000..97819bf1 --- /dev/null +++ b/modules/P07_firmware_bin_base_analyzer.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# emba - EMBEDDED LINUX ANALYZER +# +# Copyright 2020 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, Pascal Eckmann + +P07_firmware_bin_base_analyser() { + module_log_init "firmware_bin_base_analyser_log" + module_title "Binary firmware OS detection" + + os_identification +} + +os_identification() { + + # We can improve this search stuff a lot in the future: + COUNTER_Linux="$(find "$OUTPUT_DIR" -type f -exec strings {} \; | grep -c Linux 2> /dev/null)" + COUNTER_Linux_FW="$(strings "$FIRMWARE_PATH" | grep -c Linux 2> /dev/null)" + COUNTER_Linux=$((COUNTER_Linux+COUNTER_Linux_FW)) + + COUNTER_VxWorks="$(find "$OUTPUT_DIR" -type f -exec strings {} \; | grep -c VxWorks 2> /dev/null)" + COUNTER_VxWorks_FW="$(strings "$FIRMWARE_PATH" | grep -c VxWorks 2> /dev/null)" + COUNTER_VxWorks=$((COUNTER_VxWorks+COUNTER_VxWorks_FW)) + + COUNTER_FreeRTOS="$(find "$OUTPUT_DIR" -type f -exec strings {} \; | grep -c FreeRTOS 2> /dev/null)" + COUNTER_FreeRTOS_FW="$(strings "$FIRMWARE_PATH" | grep -c FreeRTOS 2> /dev/null)" + COUNTER_FreeRTOS=$((COUNTER_FreeRTOS+COUNTER_FreeRTOS_FW)) + + COUNTER_eCos="$(find "$OUTPUT_DIR" -type f -exec strings {} \; | grep -c eCos 2> /dev/null)" + COUNTER_eCos_FW="$(strings "$FIRMWARE_PATH" | grep -c eCos 2> /dev/null)" + COUNTER_eCos=$((COUNTER_eCos+COUNTER_eCos_FW)) + + if [[ $((COUNTER_VxWorks+COUNTER_FreeRTOS+COUNTER_eCos)) -gt 0 ]] ; then + print_output "$(indent "$(orange "Operating system detection:")")" "no_log" + if [[ $COUNTER_VxWorks -gt 0 ]] ; then print_output "$(indent "$(orange "VxWorks ""$COUNTER_VxWorks")")" "no_log" ; fi + if [[ $COUNTER_FreeRTOS -gt 0 ]] ; then print_output "$(indent "$(orange "FreeRTOS ""$COUNTER_FreeRTOS")")" "no_log" ; fi + if [[ $COUNTER_eCos -gt 0 ]] ; then print_output "$(indent "$(orange "eCos ""$COUNTER_eCos")")" "no_log" ; fi + if [[ $COUNTER_Linux -gt 0 ]] ; then print_output "$(indent "$(orange "Linux ""$COUNTER_Linux")")" "no_log"; fi + fi + + echo + print_output "[*] Trying to identify a Linux root path in $OUTPUT_DIR" + # just to check if there is somewhere a linux filesystem in the extracted stuff + # emba is able to handle the rest + LINUX_PATH_COUNTER="$(find "$OUTPUT_DIR" "${EXCL_FIND[@]}" -type d -iname bin -o -type d -iname busybox -o -type d -iname sbin -o -type d -iname etc 2> /dev/null | wc -l)" + if [[ $LINUX_PATH_COUNTER -gt 0 ]] ; then + print_output "[+] Found possible Linux system in $OUTPUT_DIR" + export FIRMWARE=1 + export FIRMWARE_PATH="$OUTPUT_DIR" + fi +}