mirror of
https://github.com/e-m-b-a/emba.git
synced 2026-10-12 02:13:21 +00:00
695 lines
22 KiB
Bash
Executable File
695 lines
22 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# emba - EMBEDDED LINUX ANALYZER
|
|
#
|
|
# Copyright 2020-2021 Siemens AG
|
|
# Copyright 2020-2021 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
|
|
# Contributor(s): Stefan Haboeck
|
|
|
|
# Description: Main script for load all necessary files and call main function of modules
|
|
|
|
INVOCATION_PATH="."
|
|
|
|
import_helper()
|
|
{
|
|
local HELPERS
|
|
local HELPER_COUNT
|
|
mapfile -d '' HELPERS < <(find "$HELP_DIR" -iname "*.sh" -print0 2> /dev/null)
|
|
for HELPER_FILE in "${HELPERS[@]}" ; do
|
|
if ( file "$HELPER_FILE" | grep -q "shell script" ) && ! [[ "$HELPER_FILE" =~ \ |\' ]] ; then
|
|
# https://github.com/koalaman/shellcheck/wiki/SC1090
|
|
# shellcheck source=/dev/null
|
|
source "$HELPER_FILE"
|
|
(( HELPER_COUNT+=1 ))
|
|
fi
|
|
done
|
|
print_output "==> ""$GREEN""Imported ""$HELPER_COUNT"" necessary files""$NC" "no_log"
|
|
}
|
|
|
|
import_module()
|
|
{
|
|
local MODULES
|
|
local MODULE_COUNT
|
|
mapfile -t MODULES < <(find "$MOD_DIR" -name "*.sh" | sort -V 2> /dev/null)
|
|
for MODULE_FILE in "${MODULES[@]}" ; do
|
|
if ( file "$MODULE_FILE" | grep -q "shell script" ) && ! [[ "$MODULE_FILE" =~ \ |\' ]] ; then
|
|
# https://github.com/koalaman/shellcheck/wiki/SC1090
|
|
# shellcheck source=/dev/null
|
|
source "$MODULE_FILE"
|
|
(( MODULE_COUNT+=1 ))
|
|
fi
|
|
done
|
|
print_output "==> ""$GREEN""Imported ""$MODULE_COUNT"" module/s""$NC" "no_log"
|
|
}
|
|
|
|
sort_modules()
|
|
{
|
|
local SORTED_MODULES
|
|
for MODULE_FILE in "${MODULES[@]}" ; do
|
|
if ( file "$MODULE_FILE" | grep -q "shell script" ) && ! [[ "$MODULE_FILE" =~ \ |\' ]] ; then
|
|
THREAD_PRIO=0
|
|
# https://github.com/koalaman/shellcheck/wiki/SC1090
|
|
# shellcheck source=/dev/null
|
|
source "$MODULE_FILE"
|
|
if [[ $THREAD_PRIO -eq 1 ]] ; then
|
|
SORTED_MODULES=( "$MODULE_FILE" "${SORTED_MODULES[@]}" )
|
|
else
|
|
SORTED_MODULES=( "${SORTED_MODULES[@]}" "$MODULE_FILE" )
|
|
fi
|
|
fi
|
|
done
|
|
MODULES=( "${SORTED_MODULES[@]}" )
|
|
}
|
|
|
|
# $1: module group letter [P, S, F]
|
|
# $2: 0=single thread 1=multithread
|
|
# $3: HTML=1 - generate html file
|
|
run_modules()
|
|
{
|
|
MODULE_GROUP="$1"
|
|
printf -v THREADING_SET '%d\n' "$2" 2>/dev/null
|
|
THREADING_MOD_GROUP="$THREADING_SET"
|
|
|
|
local SELECT_PRE_MODULES_COUNT=0
|
|
|
|
for SELECT_NUM in "${SELECT_MODULES[@]}" ; do
|
|
if [[ "$SELECT_NUM" =~ ^["${MODULE_GROUP,,}","${MODULE_GROUP^^}"]{1} ]]; then
|
|
(( SELECT_PRE_MODULES_COUNT+=1 ))
|
|
fi
|
|
done
|
|
|
|
if [[ ${#SELECT_MODULES[@]} -eq 0 ]] || [[ $SELECT_PRE_MODULES_COUNT -eq 0 ]]; then
|
|
local MODULES
|
|
mapfile -t MODULES < <(find "$MOD_DIR" -name "${MODULE_GROUP^^}""*_*.sh" | sort -V 2> /dev/null)
|
|
if [[ $THREADING_SET -eq 1 && "${MODULE_GROUP^^}" != "P" ]] ; then
|
|
sort_modules
|
|
fi
|
|
for MODULE_FILE in "${MODULES[@]}" ; do
|
|
if ( file "$MODULE_FILE" | grep -q "shell script" ) && ! [[ "$MODULE_FILE" =~ \ |\' ]] ; then
|
|
if [[ "${MODULE_GROUP^^}" == "P" ]]; then
|
|
# we are able to enable/disable threading on module basis in the the pre-checker modules with the header:
|
|
# export PRE_THREAD_ENA=1/0
|
|
# shellcheck source=/dev/null
|
|
source "$MODULE_FILE"
|
|
if [[ $PRE_THREAD_ENA -eq 0 ]] ; then
|
|
THREADING_SET=0
|
|
fi
|
|
fi
|
|
MODULE_BN=$(basename "$MODULE_FILE")
|
|
MODULE_MAIN=${MODULE_BN%.*}
|
|
module_start_log "$MODULE_MAIN"
|
|
if [[ $THREADING_SET -eq 1 ]]; then
|
|
$MODULE_MAIN &
|
|
WAIT_PIDS+=( "$!" )
|
|
max_pids_protection "$MAX_MODS" "${WAIT_PIDS[@]}"
|
|
else
|
|
$MODULE_MAIN
|
|
fi
|
|
reset_module_count
|
|
fi
|
|
if [[ "${MODULE_GROUP^^}" == "P" ]]; then
|
|
THREADING_SET="$THREADING_MOD_GROUP"
|
|
fi
|
|
done
|
|
else
|
|
for SELECT_NUM in "${SELECT_MODULES[@]}" ; do
|
|
if [[ "$SELECT_NUM" =~ ^["${MODULE_GROUP,,}","${MODULE_GROUP^^}"]{1}[0-9]+ ]]; then
|
|
local MODULE
|
|
MODULE=$(find "$MOD_DIR" -name "${MODULE_GROUP^^}""${SELECT_NUM:1}""_*.sh" | sort -V 2> /dev/null)
|
|
if ( file "$MODULE" | grep -q "shell script" ) && ! [[ "$MODULE" =~ \ |\' ]] ; then
|
|
MODULE_BN=$(basename "$MODULE")
|
|
MODULE_MAIN=${MODULE_BN%.*}
|
|
module_start_log "$MODULE_MAIN"
|
|
if [[ $THREADING_SET -eq 1 ]]; then
|
|
$MODULE_MAIN &
|
|
WAIT_PIDS+=( "$!" )
|
|
max_pids_protection "$MAX_MODS" "${WAIT_PIDS[@]}"
|
|
else
|
|
$MODULE_MAIN
|
|
fi
|
|
reset_module_count
|
|
fi
|
|
elif [[ "$SELECT_NUM" =~ ^["${MODULE_GROUP,,}","${MODULE_GROUP^^}"]{1} ]]; then
|
|
local MODULES
|
|
mapfile -t MODULES < <(find "$MOD_DIR" -name "${MODULE_GROUP^^}""*_*.sh" | sort -V 2> /dev/null)
|
|
if [[ $THREADING_SET -eq 1 ]] ; then
|
|
sort_modules
|
|
fi
|
|
for MODULE_FILE in "${MODULES[@]}" ; do
|
|
if ( file "$MODULE_FILE" | grep -q "shell script" ) && ! [[ "$MODULE_FILE" =~ \ |\' ]] ; then
|
|
if [[ "${MODULE_GROUP^^}" == "P" ]]; then
|
|
# we are able to enable/disable threading on module basis in the the pre-checker modules with the header:
|
|
# export PRE_THREAD_ENA=1/0
|
|
# shellcheck source=/dev/null
|
|
source "$MODULE_FILE"
|
|
if [[ $PRE_THREAD_ENA -eq 0 ]] ; then
|
|
THREADING_SET=0
|
|
fi
|
|
fi
|
|
|
|
MODULE_BN=$(basename "$MODULE_FILE")
|
|
MODULE_MAIN=${MODULE_BN%.*}
|
|
module_start_log "$MODULE_MAIN"
|
|
if [[ $THREADING_SET -eq 1 ]]; then
|
|
$MODULE_MAIN &
|
|
WAIT_PIDS+=( "$!" )
|
|
max_pids_protection "$MAX_MODS" "${WAIT_PIDS[@]}"
|
|
else
|
|
$MODULE_MAIN
|
|
fi
|
|
reset_module_count
|
|
fi
|
|
if [[ "${MODULE_GROUP^^}" == "P" ]]; then
|
|
THREADING_SET="$THREADING_MOD_GROUP"
|
|
fi
|
|
done
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
main()
|
|
{
|
|
set -a
|
|
trap cleaner INT
|
|
|
|
INVOCATION_PATH="$(dirname "$0")"
|
|
|
|
export ARCH_CHECK=1
|
|
export RTOS=0 # Testing RTOS based OS
|
|
export CWE_CHECKER=0
|
|
export DEEP_EXTRACTOR=0
|
|
export FACT_EXTRACTOR=0
|
|
export FIRMWARE=0
|
|
export FORCE=0
|
|
export FORMAT_LOG=0
|
|
export HTML=0
|
|
export IN_DOCKER=0
|
|
export KERNEL=0
|
|
export LOG_GREP=0
|
|
export FINAL_FW_RM=0 # remove the firmware working copy after testing (do not waste too much disk space)
|
|
export MOD_RUNNING=0 # for tracking how many modules currently running
|
|
export ONLY_DEP=0 # test only dependency
|
|
export ONLINE_CHECKS=0 # checks with internet connection needed (e.g. upload of firmware to virustotal)
|
|
export PHP_CHECK=1
|
|
export PRE_CHECK=0 # test and extract binary files with binwalk
|
|
# afterwards do a default emba scan
|
|
export PYTHON_CHECK=1
|
|
export QEMULATION=0
|
|
# to get rid of all the running stuff we are going to kill it after RUNTIME
|
|
export QRUNTIME="20s"
|
|
|
|
export SHELLCHECK=1
|
|
export SHORT_PATH=0 # short paths in cli output
|
|
export THREADED=0 # 0 -> single thread
|
|
# 1 -> multi threaded
|
|
export USE_DOCKER=0
|
|
export YARA=1
|
|
|
|
export MAX_EXT_SPACE=11000 # a useful value, could be adjusted if you deal with very big firmware images
|
|
export LOG_DIR="$INVOCATION_PATH""/logs"
|
|
export TMP_DIR="$LOG_DIR""/tmp"
|
|
export MAIN_LOG_FILE="emba.log"
|
|
export CONFIG_DIR="$INVOCATION_PATH""/config"
|
|
export EXT_DIR="$INVOCATION_PATH""/external"
|
|
export HELP_DIR="$INVOCATION_PATH""/helpers"
|
|
export MOD_DIR="$INVOCATION_PATH""/modules"
|
|
export BASE_LINUX_FILES="$CONFIG_DIR""/linux_common_files.txt"
|
|
export PATH_CVE_SEARCH="./external/cve-search/bin/search.py"
|
|
export MSF_PATH="/usr/share/metasploit-framework/modules/"
|
|
if [[ -f "$CONFIG_DIR"/msf_cve-db.txt ]]; then
|
|
export MSF_DB_PATH="$CONFIG_DIR"/msf_cve-db.txt
|
|
fi
|
|
export VT_API_KEY_FILE="$CONFIG_DIR"/vt_api_key.txt # virustotal API key for P03 module
|
|
|
|
echo
|
|
|
|
import_helper
|
|
import_module
|
|
|
|
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_help
|
|
exit 1
|
|
fi
|
|
|
|
export EMBA_COMMAND
|
|
EMBA_COMMAND="$(dirname "$0")""/emba.sh ""$*"
|
|
|
|
while getopts a:A:cdDe:Ef:Fghik:l:m:N:op:rstxX:Y:WzZ: OPT ; do
|
|
case $OPT in
|
|
a)
|
|
export ARCH="$OPTARG"
|
|
;;
|
|
A)
|
|
export ARCH="$OPTARG"
|
|
export ARCH_CHECK=0
|
|
;;
|
|
c)
|
|
export CWE_CHECKER=1
|
|
;;
|
|
d)
|
|
export ONLY_DEP=1
|
|
;;
|
|
D)
|
|
export USE_DOCKER=1
|
|
;;
|
|
e)
|
|
export EXCLUDE=("${EXCLUDE[@]}" "$OPTARG")
|
|
;;
|
|
E)
|
|
export QEMULATION=1
|
|
;;
|
|
f)
|
|
export FIRMWARE=1
|
|
export FIRMWARE_PATH="$OPTARG"
|
|
export FIRMWARE_PATH_BAK="$FIRMWARE_PATH" # as we rewrite the firmware path variable in the pre-checker phase
|
|
# we store the original firmware path variable
|
|
;;
|
|
F)
|
|
export FORCE=1
|
|
;;
|
|
g)
|
|
export LOG_GREP=1
|
|
;;
|
|
h)
|
|
print_help
|
|
exit 0
|
|
;;
|
|
i)
|
|
export IN_DOCKER=1
|
|
;;
|
|
k)
|
|
export KERNEL=1
|
|
export KERNEL_CONFIG="$OPTARG"
|
|
;;
|
|
l)
|
|
export LOG_DIR="$OPTARG"
|
|
export TMP_DIR="$LOG_DIR""/tmp"
|
|
;;
|
|
m)
|
|
SELECT_MODULES=("${SELECT_MODULES[@]}" "$OPTARG")
|
|
;;
|
|
N)
|
|
export FW_NOTES="$OPTARG"
|
|
;;
|
|
o)
|
|
export ONLINE_CHECKS=1
|
|
;;
|
|
p)
|
|
export PROFILE="$OPTARG"
|
|
;;
|
|
r)
|
|
export FINAL_FW_RM=1
|
|
;;
|
|
s)
|
|
export SHORT_PATH=1
|
|
;;
|
|
t)
|
|
export THREADED=1
|
|
;;
|
|
x)
|
|
export DEEP_EXTRACTOR=1
|
|
;;
|
|
W)
|
|
export HTML=1
|
|
;;
|
|
X)
|
|
export FW_VERSION="$OPTARG"
|
|
;;
|
|
Y)
|
|
export FW_VENDOR="$OPTARG"
|
|
;;
|
|
z)
|
|
export FORMAT_LOG=1
|
|
;;
|
|
Z)
|
|
export FW_DEVICE="$OPTARG"
|
|
;;
|
|
*)
|
|
print_output "[-] Invalid option" "no_log"
|
|
print_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo
|
|
|
|
# profile handling
|
|
if [[ -n "$PROFILE" ]]; then
|
|
if [[ -f "$PROFILE" ]]; then
|
|
print_bar "no_log"
|
|
if [[ $IN_DOCKER -ne 1 ]] ; then
|
|
print_output "[*] Loading emba scan profile with the following settings:" "no_log"
|
|
else
|
|
print_output "[*] Loading emba scan profile." "no_log"
|
|
fi
|
|
# all profile output and settings are done by the profile file located in ./scan-profiles/
|
|
# shellcheck disable=SC1090
|
|
source "$PROFILE"
|
|
print_output "[*] Profile $PROFILE loaded." "no_log"
|
|
print_bar "no_log"
|
|
else
|
|
print_output "[!] Profile $PROFILE not found." "no_log"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# check provided paths for validity
|
|
check_path_valid "$FIRMWARE_PATH"
|
|
check_path_valid "$KERNEL_CONFIG"
|
|
check_path_valid "$LOG_DIR"
|
|
|
|
if [[ $IN_DOCKER -eq 1 ]] ; then
|
|
# set external path new for docker
|
|
export EXT_DIR="/external"
|
|
fi
|
|
|
|
# Check all dependencies of emba
|
|
dependency_check
|
|
|
|
if [[ $IN_DOCKER -eq 0 ]] ; then
|
|
# check if LOG_DIR exists and prompt to terminal to delete its content (Y/n)
|
|
log_folder
|
|
fi
|
|
|
|
# create log directory, if not exists and needed subdirectories
|
|
create_log_dir
|
|
|
|
# Print additional information about the firmware (-Y, -X, -Z, -N)
|
|
print_firmware_info "$FW_VENDOR" "$FW_VERSION" "$FW_DEVICE" "$FW_NOTES"
|
|
check_init_size
|
|
|
|
# Now we have the firmware and log path, lets set some additional paths
|
|
FIRMWARE_PATH="$(abs_path "$FIRMWARE_PATH")"
|
|
export MAIN_LOG="$LOG_DIR""/""$MAIN_LOG_FILE"
|
|
|
|
if [[ $KERNEL -eq 1 ]] ; then
|
|
LOG_DIR="$LOG_DIR""/""$(basename "$KERNEL_CONFIG")"
|
|
fi
|
|
|
|
check_start_cve_database
|
|
|
|
# Check firmware type (file/directory)
|
|
# copy the firmware outside of the docker and not a second time within the docker
|
|
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"
|
|
if [[ $IN_DOCKER -eq 0 ]] ; then
|
|
# in docker environment the firmware is already available
|
|
print_output " The provided firmware will be copied to $ORANGE""$FIRMWARE_PATH_CP""/""$(basename "$FIRMWARE_PATH")""$NC" "no_log"
|
|
cp -R "$FIRMWARE_PATH" "$FIRMWARE_PATH_CP""/""$(basename "$FIRMWARE_PATH")"
|
|
FIRMWARE_PATH="$FIRMWARE_PATH_CP""/""$(basename "$FIRMWARE_PATH")"
|
|
OUTPUT_DIR="$FIRMWARE_PATH_CP"
|
|
fi
|
|
elif [[ -f "$FIRMWARE_PATH" ]]; then
|
|
PRE_CHECK=1
|
|
print_output "[*] Firmware binary detected." "no_log"
|
|
print_output " Emba starts with the pre-testing phase." "no_log"
|
|
else
|
|
print_output "[!] Invalid firmware file" "no_log"
|
|
print_help
|
|
exit 1
|
|
fi
|
|
|
|
# calculate the maximum modules are running in parallel
|
|
if [[ $THREADED -eq 1 ]]; then
|
|
# the maximum modules in parallel -> after S09 is finished this value gets adjusted
|
|
# rule of thumb - per core one module
|
|
MAX_MODS="$(grep -c ^processor /proc/cpuinfo)"
|
|
|
|
# if we have only one core we run two modules in parallel
|
|
if [[ "$MAX_MODS" -lt 2 ]]; then
|
|
MAX_MODS=2
|
|
fi
|
|
export MAX_MODS
|
|
print_output " Emba is running with $ORANGE$MAX_MODS$NC modules in parallel." "no_log"
|
|
fi
|
|
|
|
# Change log output to color for web report and prepare report
|
|
if [[ $HTML -eq 1 ]] ; then
|
|
if [[ $FORMAT_LOG -eq 0 ]] ; then
|
|
FORMAT_LOG=1
|
|
print_output "[*] Activate colored log for webreport" "no_log"
|
|
fi
|
|
print_output "[*] Prepare webreport" "no_log"
|
|
prepare_report
|
|
fi
|
|
|
|
if [[ $LOG_GREP -eq 1 ]] ; then
|
|
# Create grep-able log file
|
|
create_grep_log
|
|
write_grep_log "sudo ""$EMBA_COMMAND" "COMMAND"
|
|
fi
|
|
|
|
# Exclude paths from testing and set EXCL_FIND for find command (prune paths dynamicially)
|
|
set_exclude
|
|
|
|
#######################################################################################
|
|
# Kernel configuration check
|
|
#######################################################################################
|
|
if [[ $KERNEL -eq 1 ]] && [[ $FIRMWARE -eq 0 ]] ; then
|
|
if ! [[ -f "$KERNEL_CONFIG" ]] ; then
|
|
print_output "[-] Invalid kernel configuration file: $ORANGE$KERNEL_CONFIG" "no_log"
|
|
exit 1
|
|
else
|
|
if ! [[ -d "$LOG_DIR" ]] ; then
|
|
mkdir "$LOG_DIR"
|
|
fi
|
|
S25_kernel_check
|
|
fi
|
|
fi
|
|
|
|
# we use the metasploit path for exploit information from the metasploit framework
|
|
if [[ -d "$MSF_PATH" ]]; then
|
|
generate_msf_db &
|
|
fi
|
|
|
|
|
|
#######################################################################################
|
|
# Docker
|
|
#######################################################################################
|
|
if [[ $USE_DOCKER -eq 1 ]] ; then
|
|
if ! [[ $EUID -eq 0 ]] ; then
|
|
print_output "[!] Using emba with docker-compose requires root permissions" "no_log"
|
|
print_output "$(indent "Run emba with root permissions to use docker")" "no_log"
|
|
exit 1
|
|
fi
|
|
if ! command -v docker-compose > /dev/null ; then
|
|
print_output "[!] No docker-compose found" "no_log"
|
|
print_output "$(indent "Install docker-compose via apt-get install docker-compose to use emba with docker")" "no_log"
|
|
exit 1
|
|
fi
|
|
|
|
OPTIND=1
|
|
ARGUMENTS=()
|
|
while getopts a:A:cdDe:Ef:Fghik:l:m:N:op:rstX:Y:WxzZ: OPT ; do
|
|
case $OPT in
|
|
D|f|i|l)
|
|
;;
|
|
*)
|
|
if [[ "${#OPTARG[@]}" -gt 0 ]] ; then
|
|
ARGUMENTS=( "${ARGUMENTS[@]}" "-$OPT" "${OPTARG[@]}" )
|
|
else
|
|
ARGUMENTS=( "${ARGUMENTS[@]}" "-$OPT" )
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo
|
|
|
|
if ! docker images | grep -qE "^emba[[:space:]]*latest"; then
|
|
print_output "[*] Emba sets up the docker environment.\\n" "no_log"
|
|
EMBA="$INVOCATION_PATH" FIRMWARE="$FIRMWARE_PATH" LOG="$LOG_DIR" docker-compose build emba
|
|
DBUILD_RETURN=$?
|
|
|
|
if [[ $DBUILD_RETURN -ne 0 ]] ; then
|
|
print_output "[-] Emba docker build failed!" "no_log"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if docker images | grep -qE "^emba[[:space:]]*latest"; then
|
|
setup_docker_iptables
|
|
|
|
print_output "[*] Emba initializes docker container.\\n" "no_log"
|
|
EMBA="$INVOCATION_PATH" FIRMWARE="$FIRMWARE_PATH" LOG="$LOG_DIR" docker-compose run --rm emba -c './emba.sh -l /log -f /firmware -i "$@"' _ "${ARGUMENTS[@]}"
|
|
D_RETURN=$?
|
|
|
|
if [[ $D_RETURN -eq 0 ]] ; then
|
|
if [[ $ONLY_DEP -eq 0 ]] ; then
|
|
print_output "[*] Emba finished analysis in docker container.\\n" "no_log"
|
|
print_output "[*] Firmware tested: $ORANGE$FIRMWARE_PATH$NC" "no_log"
|
|
print_output "[*] Log directory: $ORANGE$LOG_DIR$NC" "no_log"
|
|
exit
|
|
fi
|
|
else
|
|
print_output "[-] Emba failed in docker mode!" "no_log"
|
|
exit 1
|
|
fi
|
|
else
|
|
print_output "[-] Emba failed in docker mode!" "no_log"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
|
|
#######################################################################################
|
|
# Pre-Check (P-modules)
|
|
#######################################################################################
|
|
if [[ $PRE_CHECK -eq 1 ]] ; then
|
|
if [[ -f "$FIRMWARE_PATH" ]]; then
|
|
|
|
echo
|
|
if [[ -d "$LOG_DIR" ]]; then
|
|
print_output "[!] Pre-checking phase started on ""$(date)""\\n""$(indent "$NC""Firmware binary path: ""$FIRMWARE_PATH")" "main"
|
|
else
|
|
print_output "[!] Pre-checking phase started on ""$(date)""\\n""$(indent "$NC""Firmware binary path: ""$FIRMWARE_PATH")" "no_log"
|
|
fi
|
|
|
|
# 'main' functions of imported modules
|
|
# in the pre-check phase we execute all modules with P[Number]_Name.sh
|
|
|
|
## IMPORTANT NOTE: Threading is handled withing the pre-checking modules, therefore overwriting $THREADED as 0
|
|
## as there are internal dependencies it is easier to handle it in the modules
|
|
#run_modules "P" "0" "0"
|
|
run_modules "P" "$THREADED" "0"
|
|
|
|
# if we running threaded we ware going to wait for the slow guys here
|
|
if [[ $THREADED -eq 1 ]]; then
|
|
wait_for_pid "${WAIT_PIDS[@]}"
|
|
fi
|
|
|
|
if [[ $LINUX_PATH_COUNTER -gt 0 || ${#ROOT_PATH[@]} -gt 1 ]] ; then
|
|
FIRMWARE=1
|
|
FIRMWARE_PATH="$(abs_path "$OUTPUT_DIR")"
|
|
fi
|
|
|
|
echo
|
|
if [[ -d "$LOG_DIR" ]]; then
|
|
print_output "[!] Pre-checking phase ended on ""$(date)"" and took about ""$(date -d@$SECONDS -u +%H:%M:%S)"" \\n" "main"
|
|
else
|
|
print_output "[!] Pre-checking phase ended on ""$(date)"" and took about ""$(date -d@$SECONDS -u +%H:%M:%S)"" \\n" "no_log"
|
|
fi
|
|
|
|
# useful prints for debugging:
|
|
# print_output "[!] Firmware value: $FIRMWARE"
|
|
# print_output "[!] Firmware path: $FIRMWARE_PATH"
|
|
# print_output "[!] Output dir: $OUTPUT_DIR"
|
|
# print_output "[!] LINUX_PATH_COUNTER: $LINUX_PATH_COUNTER"
|
|
# print_output "[!] LINUX_PATH_ARRAY: ${#ROOT_PATH[@]}"
|
|
fi
|
|
fi
|
|
|
|
#######################################################################################
|
|
# Firmware-Check (S modules)
|
|
#######################################################################################
|
|
WAIT_PIDS=()
|
|
if [[ $FIRMWARE -eq 1 ]] ; then
|
|
print_output "\n=================================================================\n" "no_log"
|
|
check_firmware
|
|
prepare_binary_arr
|
|
if [[ -d "$FIRMWARE_PATH" ]]; then
|
|
|
|
export RTOS=0
|
|
|
|
prepare_file_arr
|
|
|
|
if [[ $KERNEL -eq 0 ]] ; then
|
|
architecture_check
|
|
architecture_dep_check
|
|
fi
|
|
|
|
if [[ "${#ROOT_PATH[@]}" -eq 0 ]]; then
|
|
detect_root_dir_helper "$FIRMWARE_PATH" "main"
|
|
fi
|
|
|
|
set_etc_paths
|
|
echo
|
|
|
|
else
|
|
# here we can deal with other non linux things like RTOS specific checks
|
|
# lets call it R* modules
|
|
# 'main' functions of imported finishing modules
|
|
|
|
export RTOS=1
|
|
|
|
prepare_file_arr
|
|
fi
|
|
|
|
if [[ -d "$LOG_DIR" ]]; then
|
|
print_output "[!] Testing phase started on ""$(date)""\\n""$(indent "$NC""Firmware path: ""$FIRMWARE_PATH")" "main"
|
|
else
|
|
print_output "[!] Testing phase started on ""$(date)""\\n""$(indent "$NC""Firmware path: ""$FIRMWARE_PATH")" "no_log"
|
|
fi
|
|
write_grep_log "$(date)" "TIMESTAMP"
|
|
|
|
run_modules "S" "$THREADED" "$HTML"
|
|
|
|
if [[ $THREADED -eq 1 ]]; then
|
|
wait_for_pid "${WAIT_PIDS[@]}"
|
|
fi
|
|
|
|
echo
|
|
if [[ -d "$LOG_DIR" ]]; then
|
|
print_output "[!] Testing phase ended on ""$(date)"" and took about ""$(date -d@$SECONDS -u +%H:%M:%S)"" \\n" "main"
|
|
else
|
|
print_output "[!] Testing phase ended on ""$(date)"" and took about ""$(date -d@$SECONDS -u +%H:%M:%S)"" \\n" "no_log"
|
|
fi
|
|
|
|
TESTING_DONE=1
|
|
fi
|
|
|
|
#######################################################################################
|
|
# Reporting (F-modules)
|
|
#######################################################################################
|
|
if [[ -d "$LOG_DIR" ]]; then
|
|
print_output "[!] Reporting phase started on ""$(date)""\\n" "main"
|
|
else
|
|
print_output "[!] Reporting phase started on ""$(date)""\\n" "no_log"
|
|
fi
|
|
|
|
run_modules "F" "0" "$HTML"
|
|
|
|
if [[ "$TESTING_DONE" -eq 1 ]]; then
|
|
if [[ "$FINAL_FW_RM" -eq 1 && -d "$LOG_DIR"/firmware ]]; then
|
|
print_output "[*] Removing temp firmware directory\\n" "no_log"
|
|
rm -r "$LOG_DIR"/firmware 2>/dev/null
|
|
fi
|
|
echo
|
|
if [[ -d "$LOG_DIR" ]]; then
|
|
print_output "[!] Test ended on ""$(date)"" and took about ""$(date -d@$SECONDS -u +%H:%M:%S)"" \\n" "main"
|
|
rm -r "$TMP_DIR" 2>/dev/null
|
|
else
|
|
print_output "[!] Test ended on ""$(date)"" and took about ""$(date -d@$SECONDS -u +%H:%M:%S)"" \\n" "no_log"
|
|
fi
|
|
write_grep_log "$(date)" "TIMESTAMP"
|
|
write_grep_log "$(date -d@$SECONDS -u +%H:%M:%S)" "DURATION"
|
|
else
|
|
print_output "[!] No extracted firmware found" "no_log"
|
|
print_output "$(indent "Try using binwalk or something else to extract the Linux operating system")"
|
|
exit 1
|
|
fi
|
|
if [[ "$HTML" -eq 1 ]]; then
|
|
update_index
|
|
fi
|
|
if [[ -f "$HTML_PATH"/index.html ]]; then
|
|
print_output "[*] Web report created HTML report in $ORANGE$LOG_DIR/html-report$NC\\n" "main"
|
|
fi
|
|
}
|
|
|
|
main "$@"
|