mirror of
https://github.com/e-m-b-a/emba.git
synced 2026-10-12 02:13:21 +00:00
3224 lines
151 KiB
Bash
Executable File
3224 lines
151 KiB
Bash
Executable File
#!/bin/bash -p
|
|
|
|
# EMBA - EMBEDDED LINUX ANALYZER
|
|
#
|
|
# Copyright 2020-2026 Siemens Energy AG
|
|
# Copyright (c) 2017 - 2020, Mingeun Kim, Dongkwan Kim, Eunsoo Kim
|
|
# Copyright (c) 2015 - 2016, Daming Dominic Chen
|
|
#
|
|
# EMBA comes with ABSOLUTELY NO WARRANTY.
|
|
#
|
|
# This module is licensed under MIT
|
|
# See LICENSE file for usage of this software.
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
# Original firmadyne project can be found here: https://github.com/firmadyne/firmadyne
|
|
# Original firmAE project can be found here: https://github.com/pr0v3rbs/FirmAE
|
|
#
|
|
# Author(s): Michael Messner
|
|
|
|
# Description: Builds and emulates Linux firmware - this module is based on the great work of firmadyne and firmAE
|
|
# Check out the original firmadyne project at https://github.com/firmadyne
|
|
# Check out the original FirmAE project at https://github.com/pr0v3rbs/FirmAE
|
|
# Currently this is an experimental module and needs to be activated separately via the -Q switch.
|
|
# Warning: This module changes your network configuration and it could happen that your system looses
|
|
# network connectivity.
|
|
#
|
|
# shellcheck disable=SC2153
|
|
|
|
L10_system_emulation() {
|
|
module_log_init "${FUNCNAME[0]}"
|
|
module_title "System emulation of Linux based embedded devices."
|
|
|
|
# enable L10_DEBUG_MODE in scan profile or default config for further debugging capabilities:
|
|
# * create_emulation_archive for all attempts
|
|
# * do not stop after 2 detected network services
|
|
# * enable experimental tests
|
|
|
|
export SYS_ONLINE=0
|
|
export TCP=""
|
|
local lARCH_END=""
|
|
local lMODULE_END=0
|
|
local lUNSUPPORTED_ARCH=0
|
|
export STATE_CHECK_MECHANISM="PING"
|
|
|
|
if [[ "${FULL_EMULATION}" -eq 1 && "${RTOS}" -eq 0 ]]; then
|
|
pre_module_reporter "${FUNCNAME[0]}"
|
|
export MODULE_SUB_PATH="${MOD_DIR}"/"${FUNCNAME[0]}"
|
|
|
|
local lIMAGE_DIR=""
|
|
export IMAGE_NAME=""
|
|
export ARCHIVE_PATH=""
|
|
export HOSTNETDEV_ARR=()
|
|
local lEMULATION_ENTRY=""
|
|
export BINARY_DIR="${EXT_DIR}/EMBA_Live_bins"
|
|
# lFIRMWARE_PATH_orig="$(abs_path "${FIRMWARE_PATH_BAK}")"
|
|
LOG_PATH_MODULE=$(abs_path "${LOG_PATH_MODULE}")
|
|
local lR_PATH_CNT=1
|
|
local lIP_ADDRESS=""
|
|
export R_PATH=""
|
|
export MIN_TCP_SERV=2
|
|
### export IP_ADDRESS_=""
|
|
|
|
# if we have a supported arch we move on with out emulation attempt
|
|
if [[ "${ARCH}" == "MIPS"* || "${ARCH}" == "ARM"* || "${ARCH}" == "x86" ]]; then
|
|
|
|
check_bmc_supermicro
|
|
|
|
# WARNING: false was never tested ;)
|
|
# Could be interesting for future extensions
|
|
set_firmae_arbitration "true"
|
|
|
|
# just to ensure nothing has already put a run.sh into our log
|
|
find "${LOG_PATH_MODULE}" -name "run.sh" --delete 2>/dev/null || true
|
|
|
|
# handling restarted scans with old emulation processes:
|
|
if [[ -f "${L10_SYS_EMU_RESULTS}" ]] && grep -q "L10_system_emulation finished" "${LOG_DIR}"/emba.log; then
|
|
print_ln
|
|
print_output "[*] Found finished emulation process - trying to recover old emulation process"
|
|
|
|
lEMULATION_ENTRY="$(grep "TCP ok" "${L10_SYS_EMU_RESULTS}" | sort -k 7 -t ';' | tail -1)"
|
|
lIP_ADDRESS=$(grep "TCP ok" "${L10_SYS_EMU_RESULTS}" | sort -k 7 -t ';' | tail -1 | cut -d\; -f9 | awk '{print $3}')
|
|
lIMAGE_DIR="$(grep "TCP ok" "${L10_SYS_EMU_RESULTS}" | sort -k 7 -t ';' | tail -1 | cut -d\; -f11)"
|
|
ARCHIVE_PATH="${OLD_LOG_DIR}""/""${lIMAGE_DIR}"
|
|
|
|
print_output "[*] Recovered IP address: ${ORANGE}${lIP_ADDRESS}${NC}"
|
|
print_output "[*] Recovered IMAGE_DIR: ${ORANGE}${lIMAGE_DIR}${NC}"
|
|
print_output "[*] Recovered ARCHIVE_PATH: ${ORANGE}${ARCHIVE_PATH}${NC}"
|
|
|
|
if [[ -v ARCHIVE_PATH ]] && [[ -f "${ARCHIVE_PATH}"/run.sh ]]; then
|
|
IMAGE_NAME="$(tr ' ' '\n' <"${ARCHIVE_PATH}"/run.sh | grep -o "file=.*" | cut -d '/' -f2)"
|
|
print_output "[*] Identified IMAGE_NAME: ${ORANGE}${IMAGE_NAME}${NC}" "no_log"
|
|
print_output "[+] Startup script (run.sh) found in old logs ... restarting emulation process now"
|
|
mapfile -t HOSTNETDEV_ARR < <(grep "ip link set.*up" "${ARCHIVE_PATH}"/run.sh | awk '{print $4}' | sort -u)
|
|
|
|
if [[ "${lEMULATION_ENTRY}" == *"ICMP not ok"* ]]; then
|
|
print_output "[*] Testing system recovery with hping instead of ping" "no_log"
|
|
STATE_CHECK_MECHANISM="HPING"
|
|
fi
|
|
# we should get TCP="ok" and SYS_ONLINE=1 back
|
|
if restart_emulation "${lIP_ADDRESS}" "${IMAGE_NAME}" 1 "${STATE_CHECK_MECHANISM}"; then
|
|
print_output "[+] System recovery was successful. Further live analysis possible for IP ${lIP_ADDRESS}"
|
|
else
|
|
print_output "[-] System recovery went wrong. No further analysis possible"
|
|
fi
|
|
else
|
|
print_output "[-] No archive path found in old logs ... restarting emulation process not possible"
|
|
fi
|
|
fi
|
|
|
|
# this is our main emulation area:
|
|
if [[ "${SYS_ONLINE}" -ne 1 ]] && [[ "${TCP}" != "ok" ]]; then
|
|
# ROOT_PATH array is exported from the pre-checking phase
|
|
# shellcheck disable=SC2153
|
|
for R_PATH in "${ROOT_PATH[@]}"; do
|
|
print_output "[*] Testing root path (${ORANGE}${lR_PATH_CNT}${NC}/${ORANGE}${#ROOT_PATH[@]}${NC}): ${ORANGE}${R_PATH}${NC}"
|
|
if grep -q "P55_unblob_extractor nothing reported" "${P55_LOG}" 2>/dev/null; then
|
|
if ! grep -q "P60_deep_extractor nothing reported" "${P60_LOG}" 2>/dev/null; then
|
|
[[ -f "${P60_LOG}" ]] && write_link "p60"
|
|
fi
|
|
else
|
|
[[ -f "${P55_LOG}" ]] && write_link "p55"
|
|
fi
|
|
|
|
if [[ -n "${D_END}" ]]; then
|
|
export TAPDEV_0="tap0_0"
|
|
local lARCH_END=""
|
|
|
|
lARCH_END="${ARCH,,}"
|
|
lARCH_END+="${D_END,,}"
|
|
|
|
# default is ARM_SF -> we only need to check if it is HF
|
|
# The information is based on the results of architecture_check()
|
|
if [[ -n "${ARM_HF}" ]] && [[ "${ARM_HF}" -gt "${ARM_SF:-0}" ]]; then
|
|
print_output "[*] ARM hardware floating detected"
|
|
lARCH_END+="hf"
|
|
fi
|
|
|
|
if [[ "${lARCH_END}" == "armbe"* ]] || [[ "${lARCH_END}" == "mips64r2"* ]] || [[ "${lARCH_END}" == "mips64_3"* ]]; then
|
|
print_output "[-] Found NOT supported architecture ${ORANGE}${lARCH_END}${NC}"
|
|
[[ -f "${P99_LOG}" ]] && write_link "p99"
|
|
print_output "[-] Please open a new issue here: https://github.com/e-m-b-a/emba/issues"
|
|
lUNSUPPORTED_ARCH=1
|
|
return
|
|
fi
|
|
|
|
# just in case we remove the return in the unsupported arch checker for testing:
|
|
if [[ "${lUNSUPPORTED_ARCH}" -ne 1 ]]; then
|
|
print_output "[*] Found supported architecture ${ORANGE}${lARCH_END}${NC}"
|
|
write_link "p99"
|
|
fi
|
|
|
|
pre_cleanup_emulator
|
|
|
|
main_emulation "${R_PATH}" "${lARCH_END}"
|
|
|
|
if [[ -d "${MNT_POINT}" ]]; then
|
|
rm -r "${MNT_POINT}" || true
|
|
fi
|
|
|
|
if [[ "${SYS_ONLINE}" -eq 1 ]] && [[ "${TCP}" == "ok" ]]; then
|
|
# do not test other root paths if we are already online (some ports are available)
|
|
if [[ "${L10_DEBUG_MODE}" -eq 1 ]]; then
|
|
print_output "[!] Debug mode: We do not stop here ..."
|
|
else
|
|
break
|
|
fi
|
|
fi
|
|
else
|
|
print_output "[!] No supported architecture detected"
|
|
fi
|
|
((lR_PATH_CNT += 1))
|
|
done
|
|
print_system_emulation_results
|
|
fi
|
|
lMODULE_END=1
|
|
else
|
|
print_output "[!] No supported architecture found.\\n"
|
|
print_output "[!] Curently supported: ${ORANGE}ARM${NC}, ${ORANGE}MIPS${NC} and ${ORANGE}x86${NC}.\\n"
|
|
lMODULE_END=0
|
|
fi
|
|
fi
|
|
|
|
if [[ "${lMODULE_END}" -ne 0 ]] && [[ -f "${L10_SYS_EMU_RESULTS}" ]]; then
|
|
if [[ $(grep -c "TCP ok" "${L10_SYS_EMU_RESULTS}" || true) -gt 0 ]]; then
|
|
print_ln
|
|
print_output "[+] Identified the following system emulation results (with running network services):"
|
|
export HOSTNETDEV_ARR=()
|
|
local lIMAGE_DIR=""
|
|
local lSYS_EMUL_POS_ENTRY=""
|
|
lSYS_EMUL_POS_ENTRY="$(grep "TCP ok" "${L10_SYS_EMU_RESULTS}" | sort -t ';' -k7 -n -r | head -1 || true)"
|
|
print_output "$(indent "$(orange "${lSYS_EMUL_POS_ENTRY}")")"
|
|
|
|
lIP_ADDRESS=$(echo "${lSYS_EMUL_POS_ENTRY}" | grep "TCP ok" | sort -k 7 -t ';' | tail -1 | cut -d\; -f9 | awk '{print $3}')
|
|
lIMAGE_DIR="$(echo "${lSYS_EMUL_POS_ENTRY}" | grep "TCP ok" | sort -k 7 -t ';' | tail -1 | cut -d\; -f11)"
|
|
ARCHIVE_PATH="${LOG_PATH_MODULE}""/""${lIMAGE_DIR}"
|
|
|
|
print_ln
|
|
print_output "[*] Identified IP address: ${ORANGE}${lIP_ADDRESS}${NC}" "no_log"
|
|
print_output "[*] Identified IMAGE_DIR: ${ORANGE}${lIMAGE_DIR}${NC}" "no_log"
|
|
print_output "[*] Identified ARCHIVE_PATH: ${ORANGE}${ARCHIVE_PATH}${NC}" "no_log"
|
|
|
|
if [[ -v ARCHIVE_PATH ]] && [[ -f "${ARCHIVE_PATH}"/run.sh ]]; then
|
|
IMAGE_NAME="$(tr ' ' '\n' <"${ARCHIVE_PATH}"/run.sh | grep -o "file=.*" | cut -d '/' -f2)"
|
|
print_output "[*] Identified IMAGE_NAME: ${ORANGE}${IMAGE_NAME}${NC}" "no_log"
|
|
print_output "[+] Identified emulation startup script (run.sh) in ARCHIVE_PATH ... starting emulation process for further analysis" "no_log"
|
|
print_ln
|
|
mapfile -t HOSTNETDEV_ARR < <(grep "ip link set.*up" "${ARCHIVE_PATH}"/run.sh | awk '{print $4}' | sort -u)
|
|
if [[ "${lSYS_EMUL_POS_ENTRY}" == *"ICMP not ok"* ]]; then
|
|
print_output "[*] Testing system recovery with hping instead of ping" "no_log"
|
|
STATE_CHECK_MECHANISM="HPING"
|
|
fi
|
|
|
|
if [[ "${FINAL_FW_RM}" -ne 1 ]]; then
|
|
# we should get TCP="ok" and SYS_ONLINE=1 back
|
|
if restart_emulation "${lIP_ADDRESS}" "${IMAGE_NAME}" 1 "${STATE_CHECK_MECHANISM}"; then
|
|
print_output "[+] System recovery was successful. Further live analysis possible for IP ${lIP_ADDRESS}."
|
|
else
|
|
print_output "[-] System recovery went wrong. No further analysis possible."
|
|
fi
|
|
else
|
|
print_output "[*] System recovery not possible - FINAL_FW_RM option set! No further analysis possible."
|
|
fi
|
|
export IP_ADDRESS_="${lIP_ADDRESS}"
|
|
else
|
|
print_output "[-] ${ORANGE}WARNING:${NC} No archive path found in logs ... restarting emulation process for further analysis not possible" "no_log"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
module_end_log "${FUNCNAME[0]}" "${lMODULE_END}"
|
|
}
|
|
|
|
check_bmc_supermicro() {
|
|
if [[ -f "${S06_CSV_LOG}" ]]; then
|
|
if grep -q "supermicro:bmc" "${S06_CSV_LOG}"; then
|
|
print_output "[-] WARNING: Supermicro firmware found - Specific qemu emulation not supported"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
print_system_emulation_results() {
|
|
if [[ -f "${L10_SYS_EMU_RESULTS}" ]]; then
|
|
sub_module_title "System emulation results"
|
|
print_output "EMBA was able to identify the following system emulation results:"
|
|
print_ln
|
|
|
|
local lEMU_RES=""
|
|
|
|
while read -r lEMU_RES; do
|
|
lEMU_RES="${lEMU_RES#*;}" # field 2-
|
|
if [[ "${lEMU_RES}" == *"ICMP ok"* ]] || [[ "${lEMU_RES}" == *"TCP-0 ok"* ]] || [[ "${lEMU_RES}" == *"TCP ok"* ]]; then
|
|
print_output "[+] ${lEMU_RES}"
|
|
else
|
|
print_output "[*] ${lEMU_RES}"
|
|
fi
|
|
done <"${L10_SYS_EMU_RESULTS}"
|
|
fi
|
|
}
|
|
|
|
pre_cleanup_emulator() {
|
|
# this cleanup function is to ensure that we have no mounts from previous tests mounted
|
|
local lCHECK_MOUNTS_ARR=()
|
|
local lMOUNT=""
|
|
|
|
print_output "[*] Checking for not unmounted proc, sys and run in log directory" "no_log"
|
|
mapfile -t lCHECK_MOUNTS_ARR < <(mount | grep "${LOG_DIR}" | grep "proc\|sys\|run" || true)
|
|
for lMOUNT in "${lCHECK_MOUNTS_ARR[@]}"; do
|
|
print_output "[*] Unmounting ${lMOUNT}" "no_log"
|
|
lMOUNT="$(cut -d' ' -f3 <<<"${lMOUNT}")" # field 3
|
|
umount -l "${lMOUNT}" || true
|
|
done
|
|
}
|
|
|
|
cleanup_tap() {
|
|
local lTAP_CLEAN_ARR=()
|
|
local lTAP_TO_CLEAN=""
|
|
|
|
mapfile -t lTAP_CLEAN_ARR < <(ifconfig | grep tap | cut -d: -f1 || true)
|
|
for lTAP_TO_CLEAN in "${lTAP_CLEAN_ARR[@]}"; do
|
|
print_output "[*] Cleaning up TAP interface ${lTAP_TO_CLEAN}"
|
|
tunctl -d "${lTAP_TO_CLEAN}" || print_error "[-] Error in tap cleanup"
|
|
done
|
|
}
|
|
|
|
create_emulation_filesystem() {
|
|
# based on the original firmAE script:
|
|
# https://github.com/pr0v3rbs/FirmAE/blob/master/scripts/makeImage.sh
|
|
|
|
sub_module_title "Create Qemu filesystem for full system emulation"
|
|
local lROOT_PATH="${1:-}"
|
|
local lARCH_END="${2:-}"
|
|
local lIMAGE_SIZE=""
|
|
local lNVRAM_FILE_LIST=()
|
|
local lNVRAM_FILE=""
|
|
local lCURRENT_DIR=""
|
|
export DEVICE="NA"
|
|
export IMAGE_NAME=""
|
|
IMAGE_NAME="$(basename "${lROOT_PATH}")_${lARCH_END}-${RANDOM}"
|
|
|
|
export MNT_POINT="${LOG_PATH_MODULE}/emulation_tmp_fs_EMBA"
|
|
if [[ -d "${MNT_POINT}" ]]; then
|
|
MNT_POINT="${MNT_POINT}"-"${RANDOM}"
|
|
fi
|
|
mkdir "${MNT_POINT}" || true
|
|
|
|
print_output "[*] Create Qemu filesystem for emulation - ${lROOT_PATH}.\\n"
|
|
lIMAGE_SIZE="$(du -b --max-depth=0 "${lROOT_PATH}" | awk '{print $1}')"
|
|
lIMAGE_SIZE=$((lIMAGE_SIZE + 400 * 1024 * 1024))
|
|
|
|
print_output "[*] Size of filesystem for emulation - ${ORANGE}${lIMAGE_SIZE}${NC}.\\n"
|
|
print_output "[*] Name of filesystem for emulation - ${ORANGE}${IMAGE_NAME}${NC}.\\n"
|
|
qemu-img create -f raw "${LOG_PATH_MODULE}/${IMAGE_NAME}" "${lIMAGE_SIZE}"
|
|
chmod a+rw "${LOG_PATH_MODULE}/${IMAGE_NAME}"
|
|
|
|
print_output "[*] Creating Partition Table"
|
|
echo -e "o\nn\np\n1\n\n\nw" | /sbin/fdisk "${LOG_PATH_MODULE}/${IMAGE_NAME}"
|
|
|
|
print_output "[*] Identify Qemu Image device for ${ORANGE}${LOG_PATH_MODULE}/${IMAGE_NAME}${NC}"
|
|
local lCNT=0
|
|
while [[ "${DEVICE:-NA}" == "NA" ]]; do
|
|
DEVICE="$(add_partition_emulation "${LOG_PATH_MODULE}/${IMAGE_NAME}")"
|
|
lCNT=$((lCNT + 1))
|
|
if [[ "${DEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
|
|
print_output "[-] No Qemu Image device identified - return from ${FUNCNAME[0]}"
|
|
return
|
|
fi
|
|
if [[ "${DEVICE:-NA}" != "NA" ]]; then
|
|
break
|
|
fi
|
|
print_output "[*] Info: Initial identification for Qemu Image device for ${ORANGE}${LOG_PATH_MODULE}/${IMAGE_NAME}${NC} failed ... trying again"
|
|
losetup | tee -a "${LOG_FILE}"
|
|
losetup -D
|
|
sleep 5
|
|
losetup | tee -a "${LOG_FILE}"
|
|
done
|
|
|
|
print_output "[*] Qemu Image device: ${ORANGE}${DEVICE}${NC}"
|
|
sleep 1
|
|
print_output "[*] Device mapper created at ${ORANGE}${DEVICE}${NC}"
|
|
|
|
print_output "[*] Creating Filesystem"
|
|
sync
|
|
mkfs.ext2 "${DEVICE}" || (print_output "[-] Error in filesystem creation" && return)
|
|
|
|
print_output "[*] Mounting QEMU Image Partition 1 to ${ORANGE}${MNT_POINT}${NC}"
|
|
mount "${DEVICE}" "${MNT_POINT}" || (print_output "[-] Error in mounting the filesystem" && return)
|
|
|
|
if mount | grep -q "${MNT_POINT}"; then
|
|
print_output "[*] Copy extracted root filesystem to new QEMU image"
|
|
cp -prf "${lROOT_PATH}"/* "${MNT_POINT}"/ || (print_output "[-] Warning: Root filesystem not copied!" && return)
|
|
|
|
print_output "[*] Binwalk v3+ creates raw files on extraction. We remove these files from our emulation root directory"
|
|
find "${MNT_POINT}" -name "*.raw" -delete || true
|
|
|
|
# ensure that the needed permissions for exec files are set correctly
|
|
# This is needed at some firmwares have corrupted permissions on ELF or sh files
|
|
print_output "[*] Multiple firmwares have broken links and script and ELF permissions - We fix them now"
|
|
"${HELP_DIR}"/fix_bins_lnk_emulation.sh "${MNT_POINT}"
|
|
|
|
print_output "[*] Creating EMBA emulation helper directories within the firmware environment"
|
|
mkdir -p "${MNT_POINT}/firmadyne/libnvram/" || true
|
|
mkdir -p "${MNT_POINT}/firmadyne/libnvram.override/" || true
|
|
|
|
print_output "[*] Patching filesystem (chroot)"
|
|
cp "$(command -v busybox)" "${MNT_POINT}" || true
|
|
cp "$(command -v bash-static)" "${MNT_POINT}" || true
|
|
|
|
if [[ -f "${S24_CSV_LOG}" ]]; then
|
|
# kernelInit is getting the output of the init command line we get from s24
|
|
if grep -q ";rdinit=" "${S24_CSV_LOG}"; then
|
|
print_output "[*] Found ${ORANGE}rdinit${NC} entry for kernel - see ${ORANGE}${S24_LOG}${NC}:"
|
|
grep ";rdinit=/" "${S24_CSV_LOG}" | cut -d\; -f4 | sed -e 's/.*rdinit=/rdinit=/' | awk '{print $1}' | sort -u | tee -a "${MNT_POINT}"/kernelInit
|
|
tee -a "${LOG_FILE}" <"${MNT_POINT}"/kernelInit
|
|
elif grep -q ";init=" "${S24_CSV_LOG}"; then
|
|
print_output "[*] Found ${ORANGE}init${NC} entry for kernel - see ${ORANGE}${S24_LOG}${NC}:"
|
|
grep ";init=/" "${S24_CSV_LOG}" | cut -d\; -f4 | sed -e 's/.*init=/init=/' | awk '{print $1}' | sort -u | tee -a "${MNT_POINT}"/kernelInit
|
|
tee -a "${LOG_FILE}" <"${MNT_POINT}"/kernelInit
|
|
fi
|
|
else
|
|
print_output "[-] No results from S24 kernel module found"
|
|
fi
|
|
|
|
print_output "[*] fixImage.sh (chroot)"
|
|
cp "${MODULE_SUB_PATH}/fixImage.sh" "${MNT_POINT}" || true
|
|
EMBA_BOOT=${EMBA_BOOT} EMBA_ETC=${EMBA_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /busybox ash /fixImage.sh || true | tee -a "${LOG_FILE}"
|
|
|
|
print_output "[*] inferFile.sh (chroot)"
|
|
# -> this re-creates init file and builds up the service which is ued from run_service.sh
|
|
cp "${MODULE_SUB_PATH}/inferFile.sh" "${MNT_POINT}" || true
|
|
EMBA_BOOT=${EMBA_BOOT} EMBA_ETC=${EMBA_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /bash-static /inferFile.sh | tee -a "${LOG_FILE}"
|
|
|
|
print_output "[*] inferService.sh (chroot)"
|
|
cp "${MODULE_SUB_PATH}/inferService.sh" "${MNT_POINT}" || true
|
|
EMBA_BOOT=${EMBA_BOOT} EMBA_ETC=${EMBA_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /bash-static /inferService.sh | tee -a "${LOG_FILE}"
|
|
|
|
if [[ -f "${MODULE_SUB_PATH}/injection_check.sh" ]]; then
|
|
# injection checker - future extension
|
|
local lINJECTION_MARKER="${RANDOM}"
|
|
if [[ -d "${MNT_POINT}"/bin ]]; then
|
|
cp "${MODULE_SUB_PATH}/injection_check.sh" "${MNT_POINT}"/bin/a || true
|
|
chmod a+x "${MNT_POINT}/bin/a" || true
|
|
sed -i 's/asdfqwertz/'"d34d_${lINJECTION_MARKER}"'/' "${MNT_POINT}"/bin/a || true
|
|
fi
|
|
if [[ -d "${MNT_POINT}"/sbin ]]; then
|
|
cp "${MODULE_SUB_PATH}/injection_check.sh" "${MNT_POINT}"/sbin/a || true
|
|
chmod a+x "${MNT_POINT}/sbin/a" || true
|
|
sed -i 's/asdfqwertz/'"d34d_${lINJECTION_MARKER}"'/' "${MNT_POINT}"/sbin/a || true
|
|
fi
|
|
if [[ -f "${MNT_POINT}/sbin/a" ]] || [[ -f "${MNT_POINT}/bin/a" ]]; then
|
|
print_output "[*] Generated injection scripts with marker ${ORANGE}${lINJECTION_MARKER}${NC}."
|
|
cat "${MNT_POINT}"/bin/a
|
|
fi
|
|
fi
|
|
|
|
if [[ -e "${MNT_POINT}/kernelInit" ]]; then
|
|
print_output "[*] Backup ${MNT_POINT}/kernelInit:"
|
|
tee -a "${LOG_FILE}" <"${MNT_POINT}/kernelInit"
|
|
rm "${MNT_POINT}/kernelInit"
|
|
fi
|
|
|
|
rm "${MNT_POINT}/fixImage.sh" || true
|
|
rm "${MNT_POINT}/inferFile.sh" || true
|
|
rm "${MNT_POINT}/busybox" || true
|
|
rm "${MNT_POINT}/bash-static" || true
|
|
|
|
print_output "[*] Setting up system mode emulation environment on target filesystem"
|
|
# FirmAE/firmadyne recompiled binaries + addons
|
|
local lBINARIES_ARR=("busybox" "console" "libnvram_dbg.so" "libnvram_nondbg.so" "libnvram_ioctl_dbg.so" "libnvram_ioctl_nondbg.so" "strace" "netcat" "gdb" "gdbserver")
|
|
local lBINARY_NAME=""
|
|
local lBINARY_PATH=""
|
|
local lTMP_EXEC_64_CNT=0
|
|
# quick check if we use stat/time or stat64/time64 on the target os - needed for libnvram
|
|
lTMP_EXEC_64_CNT=$(find "${MNT_POINT}" -type f -name "*libc*" -not -path "*/firmadyne*" -exec objdump -t {} \; 2>/dev/null | grep -c " time64" || true)
|
|
# default state for libnvram
|
|
local lMUSL_VER="1.1.24"
|
|
if [[ "${lTMP_EXEC_64_CNT}" -gt 0 ]]; then
|
|
# we use the libnvram compiled with musl 1.2.x which moves all 32-bit archs to 64-bit time_t
|
|
lMUSL_VER="1.2.5"
|
|
fi
|
|
|
|
for lBINARY_NAME in "${lBINARIES_ARR[@]}"; do
|
|
lBINARY_PATH=$(get_binary "${lBINARY_NAME}" "${lARCH_END}" "${lMUSL_VER}")
|
|
if [[ ! -f "${lBINARY_PATH}" ]]; then
|
|
print_output "[-] Missing ${ORANGE}${lBINARY_NAME} / ${lBINARY_PATH:-NA} / ${lARCH_END}${NC} - no setup possible"
|
|
continue
|
|
fi
|
|
print_output "[*] Setting up ${ORANGE}${lBINARY_NAME}${NC} - ${ORANGE}${lARCH_END}${NC} (${ORANGE}${lBINARY_PATH}${NC})"
|
|
cp "${lBINARY_PATH}" "${MNT_POINT}/firmadyne/${lBINARY_NAME}"
|
|
chmod a+x "${MNT_POINT}/firmadyne/${lBINARY_NAME}"
|
|
done
|
|
|
|
mknod -m 666 "${MNT_POINT}/firmadyne/ttyS1" c 4 65
|
|
mknod -m 666 "${MNT_POINT}/firmadyne/ttyAMA1" c 4 65
|
|
|
|
print_output "[*] Setting up emulation scripts"
|
|
cp "${MODULE_SUB_PATH}/preInit.sh" "${MNT_POINT}/firmadyne/preInit.sh" || true
|
|
chmod a+x "${MNT_POINT}/firmadyne/preInit.sh"
|
|
|
|
# network.sh
|
|
cp "${MODULE_SUB_PATH}/network.sh" "${MNT_POINT}/firmadyne/network.sh" || true
|
|
chmod a+x "${MNT_POINT}/firmadyne/network.sh"
|
|
|
|
# init_service.sh
|
|
cp "${MODULE_SUB_PATH}/init_service.sh" "${MNT_POINT}/firmadyne/init_service.sh" || true
|
|
chmod a+x "${MNT_POINT}/firmadyne/init_service.sh"
|
|
|
|
# run_service.sh
|
|
cp "${MODULE_SUB_PATH}/run_service.sh" "${MNT_POINT}/firmadyne/run_service.sh" || true
|
|
chmod a+x "${MNT_POINT}/firmadyne/run_service.sh"
|
|
|
|
chmod a+x "${MNT_POINT}/firmadyne/init"
|
|
cp "${MNT_POINT}/firmadyne/init" "${LOG_PATH_MODULE}/firmadyne_init"
|
|
|
|
lCURRENT_DIR=$(pwd)
|
|
cd "${MNT_POINT}" || exit
|
|
mapfile -t lNVRAM_FILE_LIST < <(find . -xdev -type f -name "*nvram*")
|
|
for lNVRAM_FILE in "${lNVRAM_FILE_LIST[@]}"; do
|
|
if file "${lNVRAM_FILE}" | grep -q "ASCII text"; then
|
|
if ! [[ -d "${LOG_PATH_MODULE}"/nvram ]]; then
|
|
mkdir "${LOG_PATH_MODULE}"/nvram
|
|
fi
|
|
lNVRAM_FILE="${lNVRAM_FILE/\./}"
|
|
print_output "[*] Found possible NVRAM default file ${ORANGE}${lNVRAM_FILE}${NC} -> setup /firmadyne directory"
|
|
echo "${lNVRAM_FILE}" >>"${LOG_PATH_MODULE}"/nvram/nvram_files
|
|
cp ."${lNVRAM_FILE}" "${LOG_PATH_MODULE}"/nvram/
|
|
fi
|
|
done
|
|
cd "${lCURRENT_DIR}" || exit
|
|
|
|
else
|
|
print_output "[!] Filesystem mount failed"
|
|
fi
|
|
}
|
|
|
|
link_libnvram_so() {
|
|
# pre-requisite is the mounted filesytem
|
|
local lMNT_POINT="${1:-}"
|
|
# default to debug mode with a lot of output - usually in the finale emulation mode we use the nondbg mode
|
|
local lDBG_MODE="${2:-dbg}"
|
|
|
|
# ensure we have a dbg libnvram for the initial identification
|
|
if [[ -s "${lMNT_POINT}/firmadyne/libnvram.so" ]]; then
|
|
rm "${lMNT_POINT}/firmadyne/libnvram.so"
|
|
fi
|
|
if [[ -s "${lMNT_POINT}/firmadyne/libnvram_ioctl.so" ]]; then
|
|
rm "${lMNT_POINT}/firmadyne/libnvram_ioctl.so"
|
|
fi
|
|
if [[ -f "${lMNT_POINT}/firmadyne/libnvram_${lDBG_MODE}.so" ]]; then
|
|
print_output "[*] Linking to ${lDBG_MODE} libnvram.so"
|
|
ln -sr "${lMNT_POINT}/firmadyne/libnvram_${lDBG_MODE}.so" "${lMNT_POINT}/firmadyne/libnvram.so" || true
|
|
fi
|
|
if [[ -f "${lMNT_POINT}/firmadyne/libnvram_ioctl_${lDBG_MODE}.so" ]]; then
|
|
print_output "[*] Linking to ${lDBG_MODE} libnvram_ioctl.so"
|
|
ln -sr "${lMNT_POINT}/firmadyne/libnvram_ioctl_${lDBG_MODE}.so" "${lMNT_POINT}/firmadyne/libnvram_ioctl.so" || true
|
|
fi
|
|
}
|
|
|
|
main_emulation() {
|
|
R_PATH="${1:-}"
|
|
local lARCH_END="${2:-}"
|
|
export BOOTED="NONE"
|
|
local lINIT_FILES_ARR=()
|
|
|
|
create_emulation_filesystem "${R_PATH}" "${lARCH_END}"
|
|
# here we set the global DEVICE which will be later used as local lDEVICE
|
|
|
|
if [[ -f "${LOG_PATH_MODULE}"/firmadyne_init ]]; then
|
|
print_ln
|
|
print_output "[*] Processing init files:"
|
|
local lINIT_FILE=""
|
|
while read -r lINIT_FILE; do
|
|
# check the number of '/' in our possible init file
|
|
# if we are too deep (-gt 5) then we will skip this init entry
|
|
# usually this looks the following
|
|
# /bin/linuxrc
|
|
local lINIT_DEPTH="${lINIT_FILE//[^\/]/}"
|
|
if [[ "${#lINIT_DEPTH}" -gt 5 ]]; then
|
|
continue
|
|
fi
|
|
lINIT_FILES_ARR+=("${lINIT_FILE}")
|
|
echo "${lINIT_FILE}" | tee -a "${LOG_FILE}"
|
|
done <"${LOG_PATH_MODULE}"/firmadyne_init
|
|
else
|
|
print_output "[-] WARNING: init file not created! Processing backup dummy init"
|
|
lINIT_FILES_ARR+=("/dummy_init")
|
|
fi
|
|
|
|
local lINDEX=1
|
|
local lBAK_INIT_BACKUP=""
|
|
local lBAK_INIT_ORIG=""
|
|
local lINIT_OUT=""
|
|
local lINIT_FNAME=""
|
|
export IPS_INT_VLAN=()
|
|
export ICMP=""
|
|
export TCP_0=""
|
|
export TCP=""
|
|
local lSERVICE_NAME=""
|
|
local lINIT_FILE=""
|
|
|
|
for lINIT_FILE in "${lINIT_FILES_ARR[@]}"; do
|
|
local lDEVICE="NA"
|
|
lINIT_FNAME=$(basename "${lINIT_FILE}")
|
|
# this is the main init entry - we modify it later for special cases:
|
|
export KINIT="init=/firmadyne/preInit.sh"
|
|
lINIT_OUT="${MNT_POINT}/firmadyne/preInit.sh"
|
|
|
|
sub_module_title "[*] Processing init file ${ORANGE}${lINIT_FILE} (${lINDEX}/${#lINIT_FILES_ARR[@]})${NC}"
|
|
if ! mount | grep -q "${MNT_POINT}"; then
|
|
local lCNT=0
|
|
while [[ "${lDEVICE:-NA}" == "NA" ]]; do
|
|
lDEVICE="$(add_partition_emulation "${LOG_PATH_MODULE}/${IMAGE_NAME}")"
|
|
lCNT=$((lCNT + 1))
|
|
if [[ "${lDEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
|
|
print_output "[-] No Qemu Image device identified - continue now with next init entry"
|
|
continue 2
|
|
fi
|
|
sleep 5
|
|
done
|
|
print_output "[*] Device mapper created at ${ORANGE}${lDEVICE}${NC}"
|
|
print_output "[*] Mounting QEMU Image Partition 1 to ${ORANGE}${MNT_POINT}${NC}"
|
|
mount "${lDEVICE}" "${MNT_POINT}" || true
|
|
elif [[ -n "${DEVICE}" ]]; then
|
|
lDEVICE="${DEVICE}"
|
|
else
|
|
print_output "[-] No Qemu Image device identified"
|
|
break
|
|
fi
|
|
|
|
link_libnvram_so "${MNT_POINT}" "dbg"
|
|
|
|
if [[ -n "${lBAK_INIT_ORIG}" ]]; then
|
|
print_output "[*] Restoring old init file: ${lBAK_INIT_ORIG}"
|
|
cp -pr "${lBAK_INIT_BACKUP}" "${lBAK_INIT_ORIG}" || print_error "[-] Error restoring old init file ${lBAK_INIT_ORIG}"
|
|
lBAK_INIT_BACKUP=""
|
|
lBAK_INIT_ORIG=""
|
|
fi
|
|
|
|
print_ln
|
|
print_output "[*] Firmware Init file details:"
|
|
print_output "$(indent "$(orange "$(file "${MNT_POINT}""${lINIT_FILE}" || true)")")"
|
|
|
|
print_output "[*] EMBA Init starter file details:"
|
|
print_output "$(indent "$(orange "$(file "${lINIT_OUT}" || true)")")"
|
|
print_ln
|
|
|
|
# we deal with something which is not a script:
|
|
if file "${MNT_POINT}""${lINIT_FILE}" | grep -q "symbolic link\|ELF"; then
|
|
print_output "[*] Backup original init file ${ORANGE}${lINIT_OUT}${NC}"
|
|
lBAK_INIT_ORIG="${lINIT_OUT}"
|
|
lBAK_INIT_BACKUP="${LOG_PATH_MODULE}"/"$(basename "${lINIT_OUT}".init)"
|
|
|
|
# write the init ELF file or sym link to the EMBA preInit script:
|
|
# INIT_OUT="${MNT_POINT}""/firmadyne/preInit.sh"
|
|
cp -pr "${lINIT_OUT}" "${lBAK_INIT_BACKUP}" || true
|
|
|
|
print_output "[*] Add ${lINIT_FILE} entry to ${ORANGE}${lINIT_OUT}${NC}"
|
|
# we always add the identified init entry to the EMBA preInit script
|
|
if ! (grep -q "${lINIT_FILE}" "${lINIT_OUT}"); then
|
|
echo "${lINIT_FILE} &" >>"${lINIT_OUT}" || true
|
|
# ensure we give the system some time to boot via the original init file
|
|
echo "/firmadyne/busybox sleep 60" >>"${lINIT_OUT}" || true
|
|
fi
|
|
fi
|
|
|
|
local lFS_MOUNTS_INIT_ARR=()
|
|
# if we are dealing with a startup script we are going to use this as the init entry
|
|
# and add our starters at the end of the original script
|
|
if file "${MNT_POINT}""${lINIT_FILE}" | grep -q "text executable\|ASCII text"; then
|
|
# we deal with a startup script
|
|
lINIT_OUT="${MNT_POINT}""${lINIT_FILE}"
|
|
|
|
export KINIT="init=${lINIT_FILE}"
|
|
|
|
find "${lINIT_OUT}" -xdev -maxdepth 1 -ls || true
|
|
print_output "[*] Backup original init file ${ORANGE}${lINIT_OUT}${NC}"
|
|
lBAK_INIT_ORIG="${lINIT_OUT}"
|
|
lBAK_INIT_BACKUP="${LOG_PATH_MODULE}"/"$(basename "${lINIT_OUT}".init)"
|
|
cp -pr "${lINIT_OUT}" "${lBAK_INIT_BACKUP}"
|
|
|
|
# identify mount operations for later handling and disabling
|
|
mapfile -t lFS_MOUNTS_INIT_ARR < <(grep -E "^mount\ -t\ .*\ .*mtd.* /.*" "${MNT_POINT}""${lINIT_FILE}" | sort -u || true)
|
|
|
|
# just in case we have issues with permissions
|
|
chmod +x "${MNT_POINT}""${lINIT_FILE}"
|
|
|
|
# just in case there is an exit in the init -> comment it
|
|
sed -i -r 's/(.*exit\ [0-9])$/\#\ \1/' "${MNT_POINT}""${lINIT_FILE}"
|
|
fi
|
|
|
|
# Beside the check of init we also try to find other mounts for further filesystems
|
|
# probably we need to tweak this further to also find mounts in binaries - strings?!?
|
|
local lFS_MOUNTS_FS_ARR=()
|
|
if [[ -d "${FIRMWARE_PATH}" ]]; then
|
|
# TODO: fix the tr commands do escape_print or so
|
|
mapfile -t lFS_MOUNTS_FS_ARR < <(find "${FIRMWARE_PATH}" -xdev -type f -exec grep -a -h -E "^mount\ -t\ .*\ .*mtd.* /.*" {} \; 2>/dev/null | tr -d '"' | tr -d '$' | sort -u || true)
|
|
fi
|
|
|
|
local lFS_MOUNTS_ARR=()
|
|
lFS_MOUNTS_ARR=("${lFS_MOUNTS_INIT_ARR[@]}" "${lFS_MOUNTS_FS_ARR[@]}")
|
|
mapfile -t lFS_MOUNTS_ARR < <(printf "%s\n" "${lFS_MOUNTS_ARR[@]}" | sort -u)
|
|
|
|
handle_fs_mounts "${lINIT_FILE}" "${lFS_MOUNTS_ARR[@]}"
|
|
|
|
if (grep -q "preInit.sh" "${MNT_POINT}""${lINIT_FILE}"); then
|
|
# if have our own backup init script we need to remove our own entries now
|
|
sed -i -r 's%(.*preInit.sh.*)%\#\ \1%' "${MNT_POINT}""${lINIT_FILE}"
|
|
sed -i -r 's%(/firmadyne/init_service.sh.*)%\#\ \1%' "${MNT_POINT}""${lINIT_FILE}"
|
|
sed -i -r 's%(/firmadyne/network.sh.*)%\#\ \1%' "${MNT_POINT}""${lINIT_FILE}"
|
|
sed -i -r 's%(/firmadyne/run_service.sh.*)%\#\ \1%' "${MNT_POINT}""${lINIT_FILE}"
|
|
fi
|
|
|
|
if [[ "${lINIT_OUT}" != *"preInit.sh" ]]; then
|
|
if (grep -q "/firmadyne/preInit.sh" "${lINIT_OUT}"); then
|
|
print_output "[*] preInit.sh entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
|
|
sed -i '/\/firmadyne\/preInit\.sh\ &/d' "${lINIT_OUT}"
|
|
fi
|
|
echo "/firmadyne/preInit.sh &" >>"${lINIT_OUT}" || print_error "[-] Some error occured while adding the preInit.sh entry to ${lINIT_OUT}"
|
|
fi
|
|
|
|
if (grep -q "/firmadyne/init_service.sh" "${lINIT_OUT}"); then
|
|
print_output "[*] init_server.sh entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
|
|
sed -i '/\/firmadyne\/init_service\.sh\ &/d' "${lINIT_OUT}"
|
|
fi
|
|
if [[ -f "${MNT_POINT}/firmadyne/startup_service" ]]; then
|
|
while read -r lSERVICE_NAME; do
|
|
print_output "[*] Created init service entry for starting service ${ORANGE}${lSERVICE_NAME}${NC}"
|
|
done <"${MNT_POINT}/firmadyne/startup_service"
|
|
echo "/firmadyne/init_service.sh &" >>"${lINIT_OUT}" || print_error "[-] Some error occured while adding the init_service entry to ${lINIT_OUT}"
|
|
fi
|
|
|
|
if (grep -q "/firmadyne/network.sh" "${lINIT_OUT}"); then
|
|
print_output "[*] network.sh entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
|
|
sed -i '/\/firmadyne\/network\.sh\ &/d' "${lINIT_OUT}"
|
|
fi
|
|
|
|
print_output "[*] Add network.sh entry to ${ORANGE}${lINIT_OUT}${NC}"
|
|
echo "" >>"${lINIT_OUT}" || true
|
|
echo "/firmadyne/network.sh &" >>"${lINIT_OUT}" || print_error "[-] Some error occured while adding the network.sh entry to ${lINIT_OUT}"
|
|
|
|
if (grep -q "/firmadyne/run_service.sh" "${lINIT_OUT}"); then
|
|
print_output "[*] run_service.sh entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
|
|
sed -i '/\/firmadyne\/run_service\.sh\ &/d' "${lINIT_OUT}"
|
|
fi
|
|
if [[ -f "${MNT_POINT}/firmadyne/service" ]]; then
|
|
while read -r lSERVICE_NAME; do
|
|
print_output "[*] Created service entry for starting service ${ORANGE}${lSERVICE_NAME}${NC}"
|
|
done <"${MNT_POINT}/firmadyne/service"
|
|
echo "/firmadyne/run_service.sh &" >>"${lINIT_OUT}" || print_error "[-] Some error occured while adding the run_service entry to ${lINIT_OUT}"
|
|
fi
|
|
|
|
# ensure we have not sleep entry and it is not the EMBA backup init script
|
|
if (grep -q "/firmadyne/busybox sleep 36000" "${lINIT_OUT}"); then
|
|
print_output "[*] busybox sleep 36000 entry already available in init ${ORANGE}${lINIT_OUT}${NC} -> removing now"
|
|
sed -i '/\/firmadyne\/busybox\ sleep\ 36000/d' "${lINIT_OUT}"
|
|
fi
|
|
if ! (grep -q "/firmadyne/busybox sleep 36000" "${lINIT_OUT}") && ! (grep -q "Execute EMBA " "${lINIT_OUT}"); then
|
|
# trendnet TEW-828DRU_1.0.7.2, etc...
|
|
echo "/firmadyne/busybox sleep 36000" >>"${lINIT_OUT}" || print_error "[-] Some error occured while adding the busybox sleep entry to ${lINIT_OUT}"
|
|
fi
|
|
|
|
print_ln
|
|
print_output "[*] EMBA init starter file: ${ORANGE}${lINIT_OUT}${NC}"
|
|
tee -a "${LOG_FILE}" <"${lINIT_OUT}" || true
|
|
if file "${MNT_POINT}""${lINIT_FILE}" | grep -q "text executable\|ASCII text"; then
|
|
print_ln
|
|
print_output "[*] Firmware Init file details: ${ORANGE}${lINIT_FILE}${NC}"
|
|
tee -a "${LOG_FILE}" <"${MNT_POINT}""${lINIT_FILE}"
|
|
fi
|
|
|
|
print_ln
|
|
print_output "[*] EMBA Target filesytem:"
|
|
find "${MNT_POINT}" -xdev -maxdepth 1 -ls | tee -a "${LOG_FILE}" || true
|
|
|
|
print_ln
|
|
print_output "[*] EMBA emulation helpers directory:"
|
|
find "${MNT_POINT}"/firmadyne -xdev -ls | tee -a "${LOG_FILE}" || true
|
|
print_ln
|
|
|
|
### set default network values for network identification mode
|
|
local lIP_ADDRESS="192.168.0.1"
|
|
local lNETWORK_MODE="None"
|
|
local lNETWORK_DEVICE="br0"
|
|
local lETH_INT="eth0"
|
|
set_network_config "${lIP_ADDRESS}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${lETH_INT}"
|
|
|
|
print_output "[*] Unmounting QEMU Image" "no_log"
|
|
umount_qemu_image "${lDEVICE}"
|
|
delete_device_entry "${IMAGE_NAME}" "${lDEVICE}" "${MNT_POINT}"
|
|
|
|
check_qemu_instance_l10
|
|
|
|
identify_networking_emulation "${IMAGE_NAME}" "${lARCH_END}" "${lINIT_FILE}"
|
|
get_networking_details_emulation "${IMAGE_NAME}"
|
|
|
|
print_output "[*] Firmware ${ORANGE}${IMAGE_NAME}${NC} finished for identification of the network configuration"
|
|
|
|
local lF_STARTUP=0
|
|
if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
|
|
check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" "${#PANICS[@]}" "${SYS_ONLINE:-0}" "${TCP:-NA}"
|
|
cat "${LOG_PATH_MODULE}"/qemu.initial.serial.log >>"${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}".log
|
|
write_link "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}".log
|
|
|
|
###############################################################################################
|
|
# 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 EMBA - if not we try it with the other init
|
|
lF_STARTUP=$(grep -a -c "EMBA preInit script starting" "${LOG_PATH_MODULE}"/qemu.initial.serial.log || true)
|
|
lF_STARTUP=$(("${lF_STARTUP}" + "$(grep -a -c "Network configuration - ACTION" "${LOG_PATH_MODULE}"/qemu.initial.serial.log || true)"))
|
|
else
|
|
print_output "[-] No Qemu log file generated ... some weird error occured"
|
|
return
|
|
fi
|
|
# print_output "[*] Found $ORANGE$lF_STARTUP$NC EMBA startup entries."
|
|
print_ln
|
|
|
|
# the following condition is for switching and testing a different init= -> rdinit=
|
|
if [[ "${#PANICS[@]}" -gt 0 ]] || [[ "${lF_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)
|
|
print_output "[*] Info: lF_STARTUP: ${lF_STARTUP} / lNETWORK_MODE: ${lNETWORK_MODE} / DETECTED_IP: ${DETECTED_IP} / PANICS: ${#PANICS[@]}"
|
|
if [[ "${PANICS[*]}" == *"Kernel panic - not syncing: Attempted to kill init!"* || "${PANICS[*]}" == *"Kernel panic - not syncing: No working init found."* ]]; then
|
|
mv "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_base_init.log
|
|
print_output "[!] Identified Kernel panic ... switching init from ${KINIT}"
|
|
switch_inits "${KINIT}"
|
|
|
|
# re-identify the network via other init configuration
|
|
identify_networking_emulation "${IMAGE_NAME}" "${lARCH_END}" "${lINIT_FILE}"
|
|
get_networking_details_emulation "${IMAGE_NAME}"
|
|
|
|
print_output "[*] Firmware ${ORANGE}${IMAGE_NAME}${NC} finished for identification of the network configuration"
|
|
if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
|
|
check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" "${#PANICS[@]}" "${SYS_ONLINE:-0}" "${TCP:-NA}"
|
|
mv "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_new_init.log
|
|
write_link "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_new_init.log
|
|
else
|
|
print_output "[-] No Qemu log file generated ... some weird error occured"
|
|
fi
|
|
print_ln
|
|
|
|
elif [[ "${lF_STARTUP}" -eq 0 && "${lNETWORK_MODE}" == "None" ]] ||
|
|
[[ "${lF_STARTUP}" -eq 0 && "${lNETWORK_MODE}" == "default" ]] || [[ "${DETECTED_IP}" -eq 0 ]]; then
|
|
print_output "[!] Possible init issue ... switching init from ${KINIT}"
|
|
local lPORTS_1st=0
|
|
local lCOUNTING_1st=0
|
|
mv "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_base_init.log
|
|
lCOUNTING_1st=$(wc -l <"${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_base_init.log)
|
|
lPORTS_1st=$(grep -a "inet_bind" "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_base_init.log | sort -u | wc -l | awk '{print $1}' || true)
|
|
switch_inits "${KINIT}"
|
|
|
|
# re-identify the network via other init configuration
|
|
identify_networking_emulation "${IMAGE_NAME}" "${lARCH_END}" "${lINIT_FILE}"
|
|
get_networking_details_emulation "${IMAGE_NAME}"
|
|
|
|
local lPORTS_2nd=0
|
|
local lCOUNTING_2nd=0
|
|
local lF_STARTUP=0
|
|
if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
|
|
check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" "${#PANICS[@]}" "${SYS_ONLINE:-0}" "${TCP:-NA}"
|
|
print_output "[*] qemu.initial.serial.log detected and checking for STARTUP and Service data"
|
|
# now we need to check if something is better now or we should switch back to the original init
|
|
lF_STARTUP=$(grep -a -c "EMBA preInit script starting" "${LOG_PATH_MODULE}"/qemu.initial.serial.log || true)
|
|
lF_STARTUP=$(("${lF_STARTUP}" + "$(grep -a -c "Network configuration - ACTION" "${LOG_PATH_MODULE}"/qemu.initial.serial.log || true)"))
|
|
lCOUNTING_2nd=$(wc -l <"${LOG_PATH_MODULE}"/qemu.initial.serial.log)
|
|
lPORTS_2nd=$(grep -a "inet_bind" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | sort -u | wc -l | awk '{print $1}' || true)
|
|
# IPS_INT_VLAN is always at least 1 for the default configuration
|
|
else
|
|
print_output "[-] NO qemu.initial.serial.log detected and NO checking for STARTUP and Service data possible"
|
|
fi
|
|
|
|
print_output "[*] lPORTS_1st: ${lPORTS_1st} / lPORTS_2nd: ${lPORTS_2nd} / lF_STARTUP: ${lF_STARTUP}"
|
|
if [[ "${#PANICS[@]}" -gt 0 ]] || [[ "${lF_STARTUP}" -eq 0 && "${#IPS_INT_VLAN[@]}" -lt 2 ]] ||
|
|
[[ "${DETECTED_IP}" -eq 0 ]]; then
|
|
if [[ "${#PANICS[@]}" -gt 0 ]]; then
|
|
# on a Kernel panic we always switch back
|
|
print_output "[!] Identified Kernel panic ... switching init back from ${KINIT}"
|
|
switch_inits "${KINIT}"
|
|
elif [[ "${lPORTS_1st}" -gt "${lPORTS_2nd}" ]]; then
|
|
print_output "[!] Network services issue ... switching init back from ${KINIT}"
|
|
switch_inits "${KINIT}"
|
|
# we only switch back if the first check has more output generated
|
|
elif [[ "${lCOUNTING_1st}" -gt "${lCOUNTING_2nd}" ]] && [[ "${lPORTS_1st}" -ge "${lPORTS_2nd}" ]]; then
|
|
print_output "[!] Network services issue and log file size ... switching init back from ${KINIT}"
|
|
switch_inits "${KINIT}"
|
|
fi
|
|
fi
|
|
|
|
print_output "[*] Firmware ${ORANGE}${IMAGE_NAME}${NC} finished for identification of the network configuration"
|
|
if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
|
|
mv "${LOG_PATH_MODULE}"/qemu.initial.serial.log "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_new_init.log
|
|
write_link "${LOG_PATH_MODULE}"/qemu.initial.serial_"${IMAGE_NAME}"_"${lINIT_FNAME}"_new_init.log
|
|
else
|
|
print_output "[-] No Qemu log file generated ... some weird error occured"
|
|
fi
|
|
print_ln
|
|
|
|
export PANICS=()
|
|
fi
|
|
fi
|
|
###############################################################################################
|
|
|
|
if [[ "${#IPS_INT_VLAN[@]}" -gt 0 && "${#PANICS[@]}" -eq 0 ]]; then
|
|
nvram_check "${IMAGE_NAME}"
|
|
print_bar ""
|
|
print_output "[*] Identified the following network configuration options:"
|
|
local lIP_CFG=""
|
|
local lINTERFACE_CFG=""
|
|
local lNETWORK_INTERFACE_CFG=""
|
|
local lVLAN_CFG=""
|
|
local lCFG_CFG=""
|
|
local lIPS_INT_VLAN_CFG=""
|
|
local lNETWORK_MODE=""
|
|
local lNETWORK_DEVICE=""
|
|
local lNW_ENTRY_PRIO=0
|
|
local lIPS_INT_VLAN_TMP=()
|
|
local lMAX_NET_CFG=15
|
|
print_output "[*] Unsorted configuration"
|
|
for lIPS_INT_VLAN_CFG in "${IPS_INT_VLAN[@]}"; do
|
|
lNW_ENTRY_PRIO="${lIPS_INT_VLAN_CFG/\;*/}"
|
|
lIP_CFG="$(cut -d\; -f2 <<<"${lIPS_INT_VLAN_CFG}")" # field 2
|
|
lINTERFACE_CFG="$(cut -d\; -f3 <<<"${lIPS_INT_VLAN_CFG}")" # field 3
|
|
lNETWORK_INTERFACE_CFG="$(cut -d\; -f4 <<<"${lIPS_INT_VLAN_CFG}")" # field 4
|
|
lVLAN_CFG="$(cut -d\; -f5 <<<"${lIPS_INT_VLAN_CFG}")" # field 5
|
|
lCFG_CFG="$(cut -d\; -f6 <<<"${lIPS_INT_VLAN_CFG}")" # field 6
|
|
if [[ "${lIPS_INT_VLAN_TMP[*]}" == *"${lIP_CFG};${lINTERFACE_CFG};${lNETWORK_INTERFACE_CFG};${lVLAN_CFG};${lCFG_CFG}"* ]]; then
|
|
print_output "$(indent "Duplicate: ${lIP_CFG} - ${lINTERFACE_CFG} - ${lNETWORK_INTERFACE_CFG} - ${lVLAN_CFG} - ${lCFG_CFG} - ${lNW_ENTRY_PRIO}")"
|
|
fi
|
|
print_output "$(indent "$(orange "${lIP_CFG} - ${lINTERFACE_CFG} - ${lNETWORK_INTERFACE_CFG} - ${lVLAN_CFG} - ${lCFG_CFG} - ${lNW_ENTRY_PRIO}")")"
|
|
done
|
|
|
|
# sort it
|
|
mapfile -t IPS_INT_VLAN < <(printf "%s\n" "${IPS_INT_VLAN[@]}" | sort -t ';' -k 1,1r -k 5,5n)
|
|
# make it unique
|
|
mapfile -t IPS_INT_VLAN < <(printf "%s\n" "${IPS_INT_VLAN[@]}" | uniq)
|
|
|
|
print_output "[*] Sorted and unique configuration"
|
|
for lIPS_INT_VLAN_CFG in "${IPS_INT_VLAN[@]}"; do
|
|
lNW_ENTRY_PRIO="${lIPS_INT_VLAN_CFG/\;*/}"
|
|
lIP_CFG="$(cut -d\; -f2 <<<"${lIPS_INT_VLAN_CFG}")" # field 2
|
|
lINTERFACE_CFG="$(cut -d\; -f3 <<<"${lIPS_INT_VLAN_CFG}")" # field 3
|
|
lNETWORK_INTERFACE_CFG="$(cut -d\; -f4 <<<"${lIPS_INT_VLAN_CFG}")" # field 4
|
|
lVLAN_CFG="$(cut -d\; -f5 <<<"${lIPS_INT_VLAN_CFG}")" # field 5
|
|
lCFG_CFG="$(cut -d\; -f6 <<<"${lIPS_INT_VLAN_CFG}")" # field 6
|
|
if [[ "${lIPS_INT_VLAN_TMP[*]}" == *"${lIP_CFG};${lINTERFACE_CFG};${lNETWORK_INTERFACE_CFG};${lVLAN_CFG};${lCFG_CFG}"* ]]; then
|
|
print_output "$(indent "Duplicate: ${lIP_CFG} - ${lINTERFACE_CFG} - ${lNETWORK_INTERFACE_CFG} - ${lVLAN_CFG} - ${lCFG_CFG} - ${lNW_ENTRY_PRIO}")"
|
|
fi
|
|
print_output "$(indent "$(orange "${lIP_CFG} - ${lINTERFACE_CFG} - ${lNETWORK_INTERFACE_CFG} - ${lVLAN_CFG} - ${lCFG_CFG} - ${lNW_ENTRY_PRIO}")")"
|
|
done
|
|
|
|
print_output "[*] Final configuration"
|
|
for lIPS_INT_VLAN_CFG in "${IPS_INT_VLAN[@]}"; do
|
|
lNW_ENTRY_PRIO="${lIPS_INT_VLAN_CFG/\;*/}"
|
|
lIP_CFG="$(cut -d\; -f2 <<<"${lIPS_INT_VLAN_CFG}")" # field 2
|
|
lINTERFACE_CFG="$(cut -d\; -f3 <<<"${lIPS_INT_VLAN_CFG}")" # field 3
|
|
lNETWORK_INTERFACE_CFG="$(cut -d\; -f4 <<<"${lIPS_INT_VLAN_CFG}")" # field 4
|
|
lVLAN_CFG="$(cut -d\; -f5 <<<"${lIPS_INT_VLAN_CFG}")" # field 5
|
|
lCFG_CFG="$(cut -d\; -f6 <<<"${lIPS_INT_VLAN_CFG}")" # field 6
|
|
if [[ "${lIPS_INT_VLAN_TMP[*]}" == *"${lIP_CFG};${lINTERFACE_CFG};${lNETWORK_INTERFACE_CFG};${lVLAN_CFG};${lCFG_CFG}"* ]]; then
|
|
continue
|
|
fi
|
|
lIPS_INT_VLAN_TMP+=("${lNW_ENTRY_PRIO}"\;"${lIP_CFG}"\;"${lINTERFACE_CFG}"\;"${lNETWORK_INTERFACE_CFG}"\;"${lVLAN_CFG}"\;"${lCFG_CFG}")
|
|
print_output "$(indent "$(orange "${lIP_CFG}"" - ""${lINTERFACE_CFG}"" - ""${lNETWORK_INTERFACE_CFG}"" - ""${lVLAN_CFG}"" - ""${lCFG_CFG}"" - ""${lNW_ENTRY_PRIO}")")"
|
|
if [[ "${#lIPS_INT_VLAN_TMP[@]}" -ge "${lMAX_NET_CFG}" ]]; then
|
|
print_output "[*] INFO: More then ${lMAX_NET_CFG} detected -> adding a default backup config and testing only ${lMAX_NET_CFG} most relevant configuration options"
|
|
lIPS_INT_VLAN_TMP+=("1;192.168.0.1;br0;eth0;NONE;default")
|
|
print_output "$(indent "$(orange "192.168.0.1 - br0 - eth0 - NONE - default - 1")")"
|
|
break
|
|
fi
|
|
done
|
|
print_ln
|
|
|
|
IPS_INT_VLAN=("${lIPS_INT_VLAN_TMP[@]}")
|
|
|
|
for lIPS_INT_VLAN_CFG in "${IPS_INT_VLAN[@]}"; do
|
|
emulation_with_config "${lIPS_INT_VLAN_CFG}"
|
|
|
|
if [[ "${TCP}" != "ok" ]]; then
|
|
print_output "[*] We are in the emergency init switch mode now"
|
|
# just in case we have no running TCP service detected we try the other init mechanism (rdinit vs init)
|
|
# this is only done if we have already switched inits and our first detection run has also network services detected
|
|
switch_inits "${KINIT}"
|
|
emulation_with_config "${lIPS_INT_VLAN_CFG}"
|
|
# we do not care about the results and switch back to the original init
|
|
# later on we are running the same process again
|
|
switch_inits "${KINIT}"
|
|
fi
|
|
if [[ $(grep -h "\/tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | wc -l || true) -ge "${MIN_TCP_SERV}" ]]; then
|
|
break 2
|
|
fi
|
|
done
|
|
else
|
|
print_output "[!] No further emulation steps are performed"
|
|
fi
|
|
|
|
cleanup_emulator "${IMAGE_NAME}"
|
|
|
|
print_output "[*] Processing init file ${ORANGE}${lINIT_FILE}${NC} (${lINDEX}/${#lINIT_FILES_ARR[@]}) finished"
|
|
print_bar ""
|
|
((lINDEX += 1))
|
|
done
|
|
|
|
delete_device_entry "${IMAGE_NAME}" "${lDEVICE:-NA}" "${MNT_POINT}"
|
|
}
|
|
|
|
# Function to check the kernel log entries.
|
|
# We have seen multiple times that the kernel just stops responding and we do not get logs
|
|
# This prints a warning message and also a message to the error log for further processing.
|
|
# check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.final.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" "${#PANICS[@]}" "${SYS_ONLINE:-0}" "${TCP:-NA}"
|
|
check_qemu_kernel_output() {
|
|
local lQEMU_LOG_TO_CHECK="${1:-}"
|
|
local lARCHIVE_PATH="${2:-}"
|
|
local lIMAGE_NAME="${3:-}"
|
|
local lNETWORK_MODE="${4:-}"
|
|
local lETH_INT="${5:-}"
|
|
local lVLAN_ID="${6:-}"
|
|
local lINIT_FILE="${7:-}"
|
|
local lNETWORK_DEVICE="${8:-}"
|
|
local lPANIC_CNT="${9:-0}"
|
|
local lSYS_ONLINE="${10:-0}"
|
|
local lTCP="${11:-NA}"
|
|
|
|
# if we have a kernel panic we do not need to further analyze the logs
|
|
[[ "${lPANIC_CNT}" -gt 0 ]] && return
|
|
[[ "${lSYS_ONLINE}" -gt 0 ]] && return
|
|
[[ "${lTCP}" == "TCP ok" ]] && return
|
|
|
|
local lKERNEL_MIN_RUNTIME=300
|
|
local lQEMU_RUN_TIME_KERNEL=0
|
|
|
|
lQEMU_RUN_TIME_KERNEL=$(grep -a -o -E "^\[[[:space:]]+[0-9]+\.[0-9]+.*\] EMBA" "${lQEMU_LOG_TO_CHECK}" | tail -1 || true)
|
|
lQEMU_RUN_TIME_KERNEL=${lQEMU_RUN_TIME_KERNEL//\.*/}
|
|
lQEMU_RUN_TIME_KERNEL=${lQEMU_RUN_TIME_KERNEL//*\ /}
|
|
|
|
if [[ "${lQEMU_RUN_TIME_KERNEL}" -lt "${lKERNEL_MIN_RUNTIME}" ]]; then
|
|
print_output "[-] WARNING: QEMU log (${lQEMU_LOG_TO_CHECK}) has less then ${lKERNEL_MIN_RUNTIME} seconds of kernel runtime entries. Probably something is going wrong with your emulation environment:"
|
|
print_output "$(indent "$(orange "$(grep -a -E "^\[[[:space:]]+[0-9]+\.[0-9]+.*\] EMBA" "${lQEMU_LOG_TO_CHECK}" | tail -10 || true)")")"
|
|
print_output "$(indent "lARCHIVE_PATH: ${lARCHIVE_PATH} - lIMAGE_NAME: ${lIMAGE_NAME} - lNETWORK_MODE: ${lNETWORK_MODE}")"
|
|
print_output "$(indent "lETH_INT: ${lETH_INT} - lVLAN_ID: ${lVLAN_ID} - lINIT_FILE: ${lINIT_FILE} - lNETWORK_DEVICE: ${lNETWORK_DEVICE}")"
|
|
fi
|
|
}
|
|
|
|
emulation_with_config() {
|
|
lIPS_INT_VLAN_CFG="${1:-}"
|
|
local lRESTARTED_EMULATION="${2:-0}"
|
|
|
|
SYS_ONLINE=0
|
|
|
|
print_ln
|
|
print_output "[*] Testing system emulation with configuration: ${ORANGE}${lIPS_INT_VLAN_CFG//\;/-}${NC}."
|
|
|
|
cleanup_tap
|
|
check_qemu_instance_l10
|
|
|
|
local lENTRY_PRIO=""
|
|
local lVLAN_ID=""
|
|
lENTRY_PRIO="${lIPS_INT_VLAN_CFG/\;*/}"
|
|
IP_ADDRESS_="$(cut -d\; -f2 <<<"${lIPS_INT_VLAN_CFG}")" # field 2
|
|
lNETWORK_DEVICE="$(cut -d\; -f3 <<<"${lIPS_INT_VLAN_CFG}")" # field 3
|
|
lETH_INT="$(cut -d\; -f4 <<<"${lIPS_INT_VLAN_CFG}")" # field 4
|
|
lVLAN_ID="$(cut -d\; -f5 <<<"${lIPS_INT_VLAN_CFG}")" # field 5
|
|
lNETWORK_MODE="$(cut -d\; -f6 <<<"${lIPS_INT_VLAN_CFG}")" # field 6
|
|
export NMAP_LOG="nmap_emba_${lIPS_INT_VLAN_CFG//\;/-}.txt"
|
|
|
|
setup_network_emulation "${lIPS_INT_VLAN_CFG}"
|
|
run_emulated_system "${IP_ADDRESS_}" "${IMAGE_NAME}" "${lINIT_FILE}" "${lARCH_END}"
|
|
|
|
check_online_stat "${lIPS_INT_VLAN_CFG}" "${IMAGE_NAME}" &
|
|
local lCHECK_ONLINE_STAT_PID="$!"
|
|
|
|
print_keepalive "${LOG_PATH_MODULE}/qemu.final.serial.log" "${IMAGE_NAME}" &
|
|
local lALIVE_PID="$!"
|
|
disown "${lALIVE_PID}" 2>/dev/null || true
|
|
|
|
# we kill this process from "check_online_stat"
|
|
tail -F "${LOG_PATH_MODULE}/qemu.final.serial.log" 2>/dev/null | grep -a -v "klogd" || true
|
|
if [[ -e /proc/"${lCHECK_ONLINE_STAT_PID}" ]]; then
|
|
kill -9 "${lCHECK_ONLINE_STAT_PID}" || true
|
|
fi
|
|
|
|
kill "${lALIVE_PID}" || true
|
|
|
|
# set default state
|
|
ICMP="not ok"
|
|
TCP_0="not ok"
|
|
TCP="not ok"
|
|
if [[ -f "${TMP_DIR}"/online_stats.tmp ]]; then
|
|
if grep -q -E "Host with .* is reachable via ICMP." "${TMP_DIR}"/online_stats.tmp; then
|
|
ICMP="ok"
|
|
SYS_ONLINE=1
|
|
BOOTED="yes"
|
|
fi
|
|
if grep -q -E "Host with .* is reachable on TCP port 0 via hping." "${TMP_DIR}"/online_stats.tmp; then
|
|
TCP_0="ok"
|
|
SYS_ONLINE=1
|
|
BOOTED="yes"
|
|
fi
|
|
if grep -q "udp.*open\ \|tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null; then
|
|
TCP="ok"
|
|
SYS_ONLINE=1
|
|
BOOTED="yes"
|
|
fi
|
|
|
|
# remove tmp files for next round
|
|
rm "${TMP_DIR}"/online_stats.tmp || true
|
|
fi
|
|
|
|
# if our ip address has changed during analysis we restore this ip address now
|
|
if [[ -f "${TMP_DIR}/emulation_changed_ip_address.tmp" ]]; then
|
|
IP_ADDRESS_="$(cat "${TMP_DIR}/emulation_changed_ip_address.tmp")"
|
|
rm "${TMP_DIR}/emulation_changed_ip_address.tmp" || true
|
|
fi
|
|
|
|
write_results "${ARCHIVE_PATH}" "${R_PATH}" "${RESULT_SOURCE:-EMBA}" "${lNETWORK_MODE}" "${lETH_INT}" "${lVLAN_ID}" "${lINIT_FILE}" "${lNETWORK_DEVICE}"
|
|
print_output "[*] Call to stop emulation process - Source ${FUNCNAME[0]}" "no_log"
|
|
stopping_emulation_process "${IMAGE_NAME}"
|
|
cleanup_emulator "${IMAGE_NAME}"
|
|
|
|
if [[ -f "${LOG_PATH_MODULE}"/qemu.final.serial.log ]]; then
|
|
check_qemu_kernel_output "${LOG_PATH_MODULE}"/qemu.final.serial.log "${ARCHIVE_PATH:-NA}" "${IMAGE_NAME:-NA}" "${lNETWORK_MODE:-NA}" "${lETH_INT:-NA}" "${lVLAN_ID:-NA}" "${lINIT_FILE:-NA}" "${lNETWORK_DEVICE:-NA}" 0 "${SYS_ONLINE:-0}" "${TCP:-NA}"
|
|
mv "${LOG_PATH_MODULE}"/qemu.final.serial.log "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log
|
|
fi
|
|
|
|
if [[ "${SYS_ONLINE}" -eq 1 ]]; then
|
|
print_ln
|
|
print_output "[+] System emulation was successful."
|
|
if [[ -f "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log ]]; then
|
|
print_output "[+] System should be available via IP ${ORANGE}${IP_ADDRESS_}${GREEN}." "" "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log
|
|
else
|
|
print_output "[+] System should be available via IP ${ORANGE}${IP_ADDRESS_}${GREEN}."
|
|
fi
|
|
print_ln
|
|
|
|
if [[ "${TCP}" == "ok" ]]; then
|
|
if [[ $(grep -h "\/tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | wc -l || true) -ge "${MIN_TCP_SERV}" ]]; then
|
|
print_output "[+] More than ${MIN_TCP_SERV} TCP based Network services are available - no further emulation runs are needed" "" "${ARCHIVE_PATH}/${NMAP_LOG}"
|
|
else
|
|
print_output "[+] Less than ${MIN_TCP_SERV} TCP based Network services are available - further emulation runs are needed." "" "${ARCHIVE_PATH}/${NMAP_LOG}"
|
|
fi
|
|
print_ln
|
|
fi
|
|
|
|
create_emulation_archive "${KERNEL}" "${IMAGE}" "${ARCHIVE_PATH}" "${lIPS_INT_VLAN_CFG//\;/-}"
|
|
else
|
|
if [[ "${L10_DEBUG_MODE}" -eq 1 ]]; then
|
|
print_output "[-] ${ORANGE}Debug mode:${NC} No working emulation - ${ORANGE}creating${NC} emulation archive ${ORANGE}${ARCHIVE_PATH}${NC}."
|
|
create_emulation_archive "${KERNEL}" "${IMAGE}" "${ARCHIVE_PATH}" "${lIPS_INT_VLAN_CFG//\;/-}"
|
|
else
|
|
print_output "[-] No working emulation - removing emulation archive ${ORANGE}${ARCHIVE_PATH}${NC}."
|
|
if [[ -f "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log ]]; then
|
|
write_link "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log
|
|
fi
|
|
# print_output "[-] Emulation archive: $ARCHIVE_PATH."
|
|
# create_emulation_archive "$ARCHIVE_PATH"
|
|
rm -r "${ARCHIVE_PATH}" || true
|
|
fi
|
|
fi
|
|
|
|
if [[ -f "${LOG_PATH_MODULE}"/nvram/nvram_files_final_ ]]; then
|
|
mv "${LOG_PATH_MODULE}"/nvram/nvram_files_final_ "${LOG_PATH_MODULE}"/nvram/nvram_files_"${IMAGE_NAME}".bak
|
|
fi
|
|
if ! [[ -f "${LOG_PATH_MODULE}/qemu.final.serial_${IMAGE_NAME}-${lIPS_INT_VLAN_CFG//\;/-}-${lINIT_FNAME}.log" ]]; then
|
|
print_output "[!] Warning: No Qemu log file generated for ${ORANGE}${IMAGE_NAME}-${lIPS_INT_VLAN_CFG//\;/-}-${lINIT_FNAME}${NC}"
|
|
fi
|
|
|
|
# if we have created our qemu log file and TCP is not ok we check for additional IP addresses and
|
|
# rerun the emulation if a different IP address was found
|
|
if [[ -f "${LOG_PATH_MODULE}/qemu.final.serial_${IMAGE_NAME}-${lIPS_INT_VLAN_CFG//\;/-}-${lINIT_FNAME}.log" ]]; then
|
|
local lTEMP_RUN_IPs_ARR=()
|
|
local lTMP_IP=""
|
|
# lets check if the system has configured some different IP address then expected
|
|
# we use the output of ipconfig from the qemu logs for this check
|
|
# first: generate an array with the possible ip addresses (remove already local addresses like 127.0.0.)
|
|
mapfile -t lTEMP_RUN_IPs_ARR < <(grep -a -o -E "inet addr:[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" \
|
|
"${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log |
|
|
grep -v "127.0.0." | grep -v "${IP_ADDRESS_}" | cut -d ':' -f2 | sort -u || true)
|
|
for lTMP_IP in "${lTEMP_RUN_IPs_ARR[@]}"; do
|
|
# check every detected ip address against our real system ip address
|
|
# if we have some other ip address detected we move on:
|
|
if [[ "${lTMP_IP}" != "${IP_ADDRESS_}" ]]; then
|
|
# check every ip address for our used interfaces (ethX/brX)
|
|
# if we find a typical used interface with the changed IP address we will check it again
|
|
if (grep -a -B1 "inet addr:${lTMP_IP}" "${LOG_PATH_MODULE}"/qemu.final.serial_"${IMAGE_NAME}"-"${lIPS_INT_VLAN_CFG//\;/-}"-"${lINIT_FNAME}".log | grep -q "^eth\|^br"); then
|
|
print_output "[!] WARNING: Detected possible IP address change during emulation process from ${ORANGE}${IP_ADDRESS_}${MAGENTA} to address ${ORANGE}${lTMP_IP}${NC}"
|
|
# we restart the emulation with the identified IP address for a maximum of one time
|
|
if [[ $(grep -a -h "\/tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | wc -l || true) -lt "${MIN_TCP_SERV}" ]]; then
|
|
if [[ "${lRESTARTED_EMULATION:-1}" -eq 0 ]]; then
|
|
print_output "[!] Emulation re-run with IP ${ORANGE}${lTMP_IP}${MAGENTA} needed and executed"
|
|
lIPS_INT_VLAN_CFG="${lENTRY_PRIO}"\;"${lTMP_IP}"\;"${lNETWORK_DEVICE}"\;"${lETH_INT}"\;"${lVLAN_ID}"\;"${lNETWORK_MODE}"
|
|
IPS_INT_VLAN+=("${lIPS_INT_VLAN_CFG}")
|
|
emulation_with_config "${lIPS_INT_VLAN_CFG}" 1
|
|
else
|
|
print_output "[!] Emulation re-run with IP ${ORANGE}${lTMP_IP}${MAGENTA} needed but ${ORANGE}not executed${NC}"
|
|
fi
|
|
else
|
|
print_output "[!] Emulation re-run with IP ${ORANGE}${lTMP_IP}${MAGENTA} could be performed but ${ORANGE}network services already available${NC}"
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
switch_inits() {
|
|
# KINIT is global but for readability:
|
|
KINIT="${1:-}"
|
|
if [[ "${KINIT:0:2}" == "rd" ]]; then
|
|
print_output "[*] Note: Switching rdinit to init"
|
|
# strip rd from rdinit
|
|
KINIT="${KINIT:2}"
|
|
else
|
|
print_output "[*] Note: Switching init to rdinit"
|
|
# make rdinit from init
|
|
KINIT="rd""${KINIT}"
|
|
fi
|
|
}
|
|
|
|
umount_qemu_image() {
|
|
local lDEVICE=${1:-}
|
|
sync
|
|
disable_strict_mode "${STRICT_MODE}" 0
|
|
if ! umount "${lDEVICE}"; then
|
|
print_output "[*] Warning: Normal umount was not successful. Trying to enforce unmounting of ${ORANGE}${lDEVICE}${NC}."
|
|
umount -l "${lDEVICE}" || true
|
|
umount -f "${lDEVICE}" || true
|
|
sleep 5
|
|
fi
|
|
enable_strict_mode "${STRICT_MODE}" 0
|
|
}
|
|
|
|
handle_fs_mounts() {
|
|
# WARNING: This code needs to be adjusted and tested
|
|
# Currently it was created for the TP-Link camera set (at the end it was not working as expected!)
|
|
# Idea: we identify areas that are mounted during bootup process:
|
|
# mount -t jffs2 /dev/mtdblock5 /usr/local
|
|
# mount -t jffs2 /dev/mtdblock6 /usr/local/config/ipcamera
|
|
# Next we are trying to find them in the extracted data. If we identify something
|
|
# with jffs2 in the name we copy it to the original root filesystem
|
|
# This is very dirty but if it works ... it works ;)
|
|
local lINIT_FILE=${1:-}
|
|
shift 1
|
|
local lFS_MOUNTS_ARR=("$@")
|
|
local lFS_MOUNT=""
|
|
|
|
for lFS_MOUNT in "${lFS_MOUNTS_ARR[@]}"; do
|
|
if [[ -z "${lFS_MOUNT}" ]]; then
|
|
continue
|
|
fi
|
|
local lMOUNT_PT=""
|
|
local lMOUNT_FS=""
|
|
local lFS_FIND=""
|
|
|
|
local lINIT_FILE_PATH="${MNT_POINT}${lINIT_FILE}"
|
|
print_output "[*] Found filesystem mount and analysing it: ${ORANGE}${lFS_MOUNT}${NC}"
|
|
# as the original mount will not work, we need to remove it from the startup file:
|
|
if [[ -f "${lINIT_FILE_PATH}" ]]; then
|
|
sed -i 's|'"${lFS_MOUNT}"'|\#'"${lFS_MOUNT}"'|g' "${lINIT_FILE_PATH}"
|
|
else
|
|
print_error "[-] Init file ${lINIT_FILE_PATH} NOT available ... returning but this could result in further issues"
|
|
return
|
|
fi
|
|
|
|
lMOUNT_PT=$(awk '{print $5}' <<<"${lFS_MOUNT}") # field 5
|
|
lMOUNT_FS=$(echo "${lFS_MOUNT}" | grep " \-t " | sed 's/.*-t //g' | awk '{print $1}')
|
|
if [[ "${lMOUNT_FS}" != *"jffs"* ]] && [[ "${lMOUNT_FS}" != *"cramfs"* ]]; then
|
|
print_output "[-] Warning: ${ORANGE}${lMOUNT_FS}${NC} filesystem currently not supported"
|
|
print_output "[-] Warning: If further results are wrong please open a ticket"
|
|
fi
|
|
if [[ "${lMOUNT_PT}" != *"/"* ]]; then
|
|
lMOUNT_PT=$(awk '{print $NF}' <<<"${lFS_MOUNT}") # field NF
|
|
if [[ "${lMOUNT_PT}" != *"/"* ]]; then
|
|
print_output "[-] Warning: Mount point ${ORANGE}${lMOUNT_PT}${NC} currently not supported"
|
|
print_output "[-] Warning: If further results are wrong please open a ticket"
|
|
fi
|
|
fi
|
|
# we test for paths including the lMOUNT_FS part like "jffs2" in the path
|
|
lFS_FIND=$(find "${LOG_DIR}"/firmware -path "*/*${lMOUNT_FS}*_extract" | head -1 || true)
|
|
|
|
print_output "[*] Identified mount point: ${ORANGE}${lMOUNT_PT}${NC}"
|
|
print_output "[*] Identified mounted fs: ${ORANGE}${lMOUNT_FS}${NC}"
|
|
|
|
if [[ "${lFS_FIND}" =~ ${lMOUNT_FS} ]]; then
|
|
print_output "[*] Possible FS target found: ${ORANGE}${lFS_FIND}${NC}"
|
|
else
|
|
print_output "[-] No FS target found"
|
|
fi
|
|
print_output "[*] Root system mount point: ${ORANGE}${MNT_POINT}${NC}"
|
|
|
|
if [[ "${R_PATH}" == *"${lFS_FIND}"* ]]; then
|
|
print_output "[-] Found our own root directory ... skipping"
|
|
print_output "[*] R_PATH: ${R_PATH}"
|
|
print_output "[*] FS_FIND: ${lFS_FIND}"
|
|
continue
|
|
fi
|
|
|
|
find "${lFS_FIND}" -xdev -ls || true
|
|
|
|
print_output "[*] Identify system areas in the to-mount area:"
|
|
local lLINUX_PATHS_ARR=("bin" "boot" "dev" "etc" "home" "lib" "mnt" "opt" "proc" "root" "sbin" "srv" "tmp" "usr" "var")
|
|
local lL_PATH=""
|
|
local lN_PATH=""
|
|
local lX_PATH=""
|
|
local lNEWPATH_ARR=()
|
|
local lNEWPATH_tmp_ARR=()
|
|
local lNEWPATH_test_ARR=()
|
|
|
|
for lL_PATH in "${lLINUX_PATHS_ARR[@]}"; do
|
|
mapfile -t lNEWPATH_tmp_ARR < <(find "${lFS_FIND}" -path "*/${lL_PATH}" -type d | sed "s/\/${lL_PATH}\/*/\//g")
|
|
mapfile -t lNEWPATH_test_ARR < <(find "${lFS_FIND}" -path "*/${lL_PATH}" -type d)
|
|
lNEWPATH_ARR+=("${lNEWPATH_tmp_ARR[@]}")
|
|
if [[ -d "${MNT_POINT}"/"${lL_PATH}" ]]; then
|
|
for lX_PATH in "${lNEWPATH_test_ARR[@]}"; do
|
|
print_output "[*] Copy ${lX_PATH} to ${MNT_POINT}/${lL_PATH}/"
|
|
cp -pr --update=none "${lX_PATH}"/* "${MNT_POINT}"/"${lL_PATH}"/
|
|
done
|
|
fi
|
|
done
|
|
|
|
mapfile -t lNEWPATH_ARR < <(printf "%s\n" "${lNEWPATH_ARR[@]}" | sort -u)
|
|
|
|
for lN_PATH in "${lNEWPATH_ARR[@]}"; do
|
|
if [[ -z "${lN_PATH}" ]]; then
|
|
continue
|
|
fi
|
|
print_output "[*] PATH found: ${lN_PATH}"
|
|
find "${lN_PATH}" -xdev -ls || true
|
|
|
|
if ! [[ -d "${MNT_POINT}""${lMOUNT_PT}" ]]; then
|
|
print_output "[*] Creating target directory ${MNT_POINT}${lMOUNT_PT}"
|
|
mkdir -p "${MNT_POINT}""${lMOUNT_PT}"
|
|
fi
|
|
print_output "[*] Let's copy the identified area to the root filesystem - ${ORANGE}${lN_PATH}${NC} to ${ORANGE}${MNT_POINT}${lMOUNT_PT}${NC}"
|
|
cp -pr --update=none "${lN_PATH}"* "${MNT_POINT}""${lMOUNT_PT}"
|
|
find "${MNT_POINT}""${lMOUNT_PT}" -xdev -ls || true
|
|
done
|
|
|
|
print_output "[*] Final copy of ${ORANGE}${lFS_FIND}${NC} to ${ORANGE}${MNT_POINT}${lMOUNT_PT}${NC} ..."
|
|
cp -pr --update=none "${lFS_FIND}"/* "${MNT_POINT}""${lMOUNT_PT}" || true
|
|
# find "$MNT_POINT""$lMOUNT_PT" -xdev -ls || true
|
|
ls -lh "${MNT_POINT}""${lMOUNT_PT}" || true
|
|
done
|
|
|
|
# now we need to startup the inferFile/inferService script again
|
|
cp "$(command -v bash-static)" "${MNT_POINT}" || true
|
|
cp "$(command -v busybox)" "${MNT_POINT}" || true
|
|
cp "${MODULE_SUB_PATH}/inferService.sh" "${MNT_POINT}" || true
|
|
print_output "[*] inferService.sh (chroot)"
|
|
EMBA_BOOT=${EMBA_BOOT} EMBA_ETC=${EMBA_ETC} timeout --preserve-status --signal SIGINT 120 chroot "${MNT_POINT}" /bash-static /inferService.sh | tee -a "${LOG_FILE}"
|
|
rm "${MNT_POINT}"/inferService.sh || true
|
|
rm "${MNT_POINT}"/bash-static || true
|
|
rm "${MNT_POINT}"/busybox || true
|
|
|
|
if [[ -f "${MNT_POINT}"/firmadyne/service ]]; then
|
|
# tp-link camset fix (e.g. NC200_2.1.8_Build_171109_Rel.28679.bin):
|
|
if grep -q "lighttpd" "${MNT_POINT}"/firmadyne/service; then
|
|
if ! [[ -d "${MNT_POINT}"/var/run/lighttpd ]]; then
|
|
print_output "[*] Creating pid directory for lighttpd service"
|
|
mkdir -p "${MNT_POINT}"/var/run/lighttpd || true
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
cleanup_emulator() {
|
|
local lIMAGE_NAME="${1:-}"
|
|
if [[ -v ARCHIVE_PATH ]] && [[ -f "${ARCHIVE_PATH}"/run.sh ]]; then
|
|
reset_network_emulation "${lIMAGE_NAME}" 1
|
|
else
|
|
reset_network_emulation "${lIMAGE_NAME}" 2
|
|
fi
|
|
|
|
# ugly cleanup:
|
|
rm -rf /tmp/qemu."${lIMAGE_NAME}" 2>/dev/null || true
|
|
rm -rf /tmp/qemu."${lIMAGE_NAME}".S1 2>/dev/null || true
|
|
if [[ -f /tmp/do_not_create_run.sh ]]; then
|
|
rm /tmp/do_not_create_run.sh || true
|
|
fi
|
|
|
|
# losetup
|
|
losetup -D
|
|
}
|
|
|
|
delete_device_entry() {
|
|
local lIMAGE_NAME="${1:-}"
|
|
local lDEVICE="${2:-}"
|
|
local lMNT_POINT="${3:-}"
|
|
|
|
print_output "[*] Deleting device mapper for ${lIMAGE_NAME} / ${lDEVICE}" "no_log"
|
|
|
|
kpartx -v -d "${LOG_PATH_MODULE}/${lIMAGE_NAME}"
|
|
losetup -d "${lDEVICE}" &>/dev/null || true
|
|
# just in case we check the output and remove our device:
|
|
if losetup | grep -q "$(basename "${lIMAGE_NAME}")"; then
|
|
losetup -d "$(losetup | grep "$(basename "${lIMAGE_NAME}")" | awk '{print $1}' || true)"
|
|
fi
|
|
dmsetup remove "$(basename "${lDEVICE}")" &>/dev/null || true
|
|
rm -rf "${lMNT_POINT:?}/"* || true
|
|
sleep 1
|
|
}
|
|
|
|
identify_networking_emulation() {
|
|
# based on the original firmadyne and FirmAE script:
|
|
# https://github.com/firmadyne/firmadyne/blob/master/scripts/inferNetwork.sh
|
|
|
|
local lIMAGE_NAME="${1:-}"
|
|
export IMAGE=""
|
|
IMAGE=$(abs_path "${LOG_PATH_MODULE}/${lIMAGE_NAME}")
|
|
|
|
local lARCH_END="${2:-}"
|
|
local lINIT_FILE="${3:-}"
|
|
|
|
sub_module_title "Network identification ${lINIT_FILE} - ${KINIT} - ${lARCH_END} - ${lIMAGE_NAME}"
|
|
|
|
print_output "[*] Test basic emulation and identify network settings.\\n"
|
|
print_output "[*] Running firmware ${ORANGE}${lIMAGE_NAME}${NC}: Terminating after 660 secs..."
|
|
|
|
local lCPU=""
|
|
local lKERNEL=""
|
|
local lQEMU_BIN=""
|
|
local lQEMU_MACHINE=""
|
|
local lQEMU_DISK=""
|
|
local lQEMU_PARAMS=""
|
|
local lQEMU_NETWORK=""
|
|
local lQEMU_ROOTFS=""
|
|
local lCONSOLE="ttyS0"
|
|
|
|
lKERNEL="vmlinux"
|
|
lQEMU_ROOTFS="/dev/sda1"
|
|
lQEMU_DISK="-drive if=ide,format=raw,file=${IMAGE}"
|
|
# default network configuration with e1000 interface:
|
|
lQEMU_NETWORK="-netdev socket,id=net0,listen=:2000 -device e1000,netdev=net0"
|
|
lQEMU_NETWORK+=" -netdev socket,id=net1,listen=:2001 -device e1000,netdev=net1"
|
|
lQEMU_NETWORK+=" -netdev socket,id=net2,listen=:2002 -device e1000,netdev=net2"
|
|
lQEMU_NETWORK+=" -netdev socket,id=net3,listen=:2003 -device e1000,netdev=net3"
|
|
|
|
if [[ "${lARCH_END}" == "mipsel" ]]; then
|
|
lQEMU_BIN="qemu-system-${lARCH_END}"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64r2el" ]]; then
|
|
lQEMU_BIN="qemu-system-mips64el"
|
|
lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mipseb" ]]; then
|
|
lQEMU_BIN="qemu-system-mips"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64r2eb" ]]; then
|
|
lQEMU_BIN="qemu-system-mips64"
|
|
lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64v1eb" ]]; then
|
|
lQEMU_BIN="qemu-system-mips64"
|
|
# lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64v1el" ]]; then
|
|
lQEMU_BIN="qemu-system-mips64el"
|
|
# lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64n32eb" ]]; then
|
|
lQEMU_BIN="qemu-system-mips64"
|
|
lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "armel"* ]]; then
|
|
lKERNEL="zImage"
|
|
lQEMU_BIN="qemu-system-arm"
|
|
lQEMU_MACHINE="virt"
|
|
lQEMU_DISK="-drive if=none,file=${IMAGE},format=raw,id=rootfs -device virtio-blk-device,drive=rootfs"
|
|
lQEMU_ROOTFS="/dev/vda1"
|
|
lQEMU_NETWORK="-device virtio-net-device,netdev=net0 -netdev socket,listen=:2000,id=net0"
|
|
# lQEMU_NETWORK+=" -device virtio-net-device,netdev=net1 -netdev socket,listen=:2001,id=net1"
|
|
# lQEMU_NETWORK+=" -device virtio-net-device,netdev=net2 -netdev socket,listen=:2002,id=net2"
|
|
# lQEMU_NETWORK+=" -device virtio-net-device,netdev=net3 -netdev socket,listen=:2003,id=net3"
|
|
elif [[ "${lARCH_END}" == "arm64el"* ]]; then
|
|
lKERNEL="Image"
|
|
lQEMU_BIN="qemu-system-aarch64"
|
|
lQEMU_MACHINE="virt"
|
|
lCPU="-cpu cortex-a57"
|
|
# lCONSOLE="ttyAMA0"
|
|
lQEMU_DISK="-drive if=none,file=${IMAGE},format=raw,id=rootfs -device virtio-blk-device,drive=rootfs"
|
|
lQEMU_ROOTFS="/dev/vda1"
|
|
lQEMU_NETWORK="-device virtio-net-device,netdev=net0 -netdev socket,listen=:2000,id=net0"
|
|
# lQEMU_NETWORK+=" -device virtio-net-device,netdev=net1 -netdev socket,listen=:2001,id=net1"
|
|
# lQEMU_NETWORK+=" -device virtio-net-device,netdev=net2 -netdev socket,listen=:2002,id=net2"
|
|
# lQEMU_NETWORK+=" -device virtio-net-device,netdev=net3 -netdev socket,listen=:2003,id=net3"
|
|
elif [[ "${lARCH_END}" == "x86el"* ]]; then
|
|
lKERNEL="bzImage"
|
|
# lKERNEL="vmlinux"
|
|
lQEMU_BIN="qemu-system-x86_64"
|
|
# lQEMU_BIN="qemu-system-i386"
|
|
# lQEMU_MACHINE="pc-i440fx-3.1"
|
|
lQEMU_MACHINE="pc-i440fx-8.2"
|
|
elif [[ "${lARCH_END}" == "nios2el" ]]; then
|
|
# not implemented -> Future
|
|
lQEMU_BIN="qemu-system-nios2"
|
|
lQEMU_MACHINE="10m50-ghrd"
|
|
lQEMU_DISK="-drive file=${IMAGE},format=raw"
|
|
lQEMU_NETWORK=""
|
|
else
|
|
print_output "[-] WARNING: No supported configuration found for ${ORANGE}${lARCH_END}${NC}."
|
|
return
|
|
fi
|
|
|
|
run_network_id_emulation "${lCONSOLE}" "${lCPU}" "${lKERNEL}" "${lQEMU_BIN}" "${lQEMU_MACHINE}" "${lQEMU_DISK}" "${lQEMU_PARAMS}" "${lQEMU_NETWORK}" "${lQEMU_ROOTFS}" "${lIMAGE_NAME}" "${lINIT_FILE}" "${lARCH_END}" &
|
|
|
|
local lPID="$!"
|
|
disown "${lPID}" 2>/dev/null || true
|
|
|
|
print_keepalive "${LOG_PATH_MODULE}/qemu.initial.serial.log" "${lIMAGE_NAME}" &
|
|
local lALIVE_PID="$!"
|
|
disown "${lALIVE_PID}" 2>/dev/null || true
|
|
|
|
timeout --preserve-status --signal SIGINT 660 tail -F "${LOG_PATH_MODULE}/qemu.initial.serial.log" 2>/dev/null | grep -a -v "klogd" || true
|
|
local lPID="$!"
|
|
disown "${lPID}" 2>/dev/null || true
|
|
|
|
kill "${lALIVE_PID}" || true
|
|
print_output "[*] Call to stop emulation process - Source ${FUNCNAME[0]}" "no_log"
|
|
stopping_emulation_process "${lIMAGE_NAME}"
|
|
cleanup_emulator "${lIMAGE_NAME}"
|
|
|
|
if ! [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
|
|
print_output "[-] No ${ORANGE}${LOG_PATH_MODULE}/qemu.initial.serial.log${NC} log file generated."
|
|
fi
|
|
}
|
|
|
|
print_keepalive() {
|
|
# needed for run_kpanic_identification which we are calling from the keepalive printer
|
|
local lLOG_FILE="${1:-}"
|
|
local lIMAGE_NAME="${2:-}"
|
|
|
|
# we give the whole system a few seconds until we start printing the keepalives
|
|
# and also check for kernel panics
|
|
sleep 10
|
|
while (true); do
|
|
print_output "[*] $(date) - EMBA emulation engine is live" "no_log"
|
|
run_kpanic_identification_single "${lLOG_FILE}" "${lIMAGE_NAME}"
|
|
sleep 5
|
|
done
|
|
}
|
|
|
|
run_kpanic_identification_single() {
|
|
local lLOG_FILE="${1:-}"
|
|
local lIMAGE_NAME="${2:-}"
|
|
|
|
if ! [[ -f "${lLOG_FILE}" ]]; then
|
|
return
|
|
fi
|
|
|
|
lKPANIC=$(tail -n 20 "${lLOG_FILE}" | grep -a -c "Kernel panic - " || true)
|
|
if [[ "${lKPANIC}" -gt 0 ]]; then
|
|
print_output "[*] Kernel Panic detected - stopping emulation"
|
|
tail -n 20 "${lLOG_FILE}" | grep -a "Kernel panic - " | tee -a "${LOG_FILE}" || true
|
|
print_output "[*] Call to stop emulation process - Source ${FUNCNAME[0]}" "no_log"
|
|
stopping_emulation_process "${lIMAGE_NAME}"
|
|
pkill -9 -f tail.*-F.*"${lLOG_FILE}" &>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
# run_network_id_emulation "${lCONSOLE}" "${lCPU}" "${lKERNEL}" "${lQEMU_BIN}" "${lQEMU_MACHINE}" "${lQEMU_DISK}" "${lQEMU_PARAMS}" "${lQEMU_NETWORK}" "${lQEMU_ROOTFS}" "${lIMAGE_NAME}" &
|
|
run_network_id_emulation() {
|
|
local lCONSOLE="${1:-}"
|
|
local lCPU="${2:-}"
|
|
local lKERNEL="${3:-}"
|
|
local lQEMU_BIN="${4:-}"
|
|
local lQEMU_MACHINE="${5:-}"
|
|
local lQEMU_DISK="${6:-}"
|
|
local lQEMU_PARAMS="${7:-}"
|
|
local lQEMU_NETWORK="${8:-}"
|
|
local lQEMU_ROOTFS="${9:-}"
|
|
local lIMAGE_NAME="${10:-}"
|
|
local lINIT_FILE="${11:-}"
|
|
local lARCH_END="${12:-}"
|
|
|
|
print_output "[*] Qemu network identification run for ${ORANGE}${lARCH_END}${NC} - ${ORANGE}${lIMAGE_NAME}${NC}"
|
|
|
|
# temp code for future use - currently only kernel v4 is supported
|
|
if [[ "${lARCH_END}" == *"mips"* ]]; then
|
|
export KERNEL_V=""
|
|
get_kernel_version
|
|
if [[ -n "${KERNEL_V}" ]]; then
|
|
print_output "[*] Kernel ${KERNEL_V}.x detected -> Using Kernel v4.x"
|
|
KERNEL_V=".${KERNEL_V}"
|
|
else
|
|
KERNEL_V=".4"
|
|
fi
|
|
# hard code v4.x
|
|
KERNEL_V=".4"
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/${lKERNEL}.${lARCH_END}${KERNEL_V}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/${lKERNEL}.${lARCH_END}${KERNEL_V}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
elif [[ "${lARCH_END}" == *"x86el"* ]] && [[ "${L10_KERNEL_V_LONG}" == "4.1.52" ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v4.1.17/${lKERNEL}.${lARCH_END}" ]]; then
|
|
# x86el kernel has issues in version 4.1.52 - need further investigation
|
|
print_output "[!] Bypassing known issues with kernel v${L10_KERNEL_V_LONG} - switching to v4.1.17"
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v4.1.17/${lKERNEL}.${lARCH_END}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
else
|
|
# ARM/x86 architecture
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/${lKERNEL}.${lARCH_END}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/${lKERNEL}.${lARCH_END}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
check_qemu_instance_l10
|
|
|
|
print_output "[*] Qemu parameters used in network detection mode:"
|
|
print_output "$(indent "MACHINE: ${ORANGE}${lQEMU_MACHINE}${NC}")"
|
|
print_output "$(indent "KERNEL: ${ORANGE}${lKERNEL}${NC}")"
|
|
print_output "$(indent "DRIVE: ${ORANGE}${lQEMU_DISK}${NC}")"
|
|
print_output "$(indent "KINIT: ${ORANGE}${KINIT}${NC}")"
|
|
print_output "$(indent "ROOT_DEV: ${ORANGE}${lQEMU_ROOTFS}${NC}")"
|
|
print_output "$(indent "QEMU binary: ${ORANGE}${lQEMU_BIN}${NC}")"
|
|
print_output "$(indent "NETWORK: ${ORANGE}${lQEMU_NETWORK}${NC}")"
|
|
print_output "$(indent "Init file: ${ORANGE}${lINIT_FILE}${NC}")"
|
|
print_output "$(indent "Console interface: ${ORANGE}${lCONSOLE}${NC}")"
|
|
print_ln
|
|
print_output "[*] Starting firmware emulation for network identification - ${ORANGE}${lQEMU_BIN} / ${lARCH_END} / ${lIMAGE_NAME}${NC} ... use Ctrl-a + x to exit"
|
|
print_ln
|
|
|
|
# timeout ensures we are able to end this somewhere in the future - just in case something goes wrong
|
|
write_script_exec "timeout --preserve-status --signal SIGINT 2000 ${lQEMU_BIN} -m 2048 -M ${lQEMU_MACHINE} ${lCPU} -kernel ${lKERNEL} ${lQEMU_DISK} -append \"root=${lQEMU_ROOTFS} console=${lCONSOLE} nandsim.parts=64,64,64,64,64,64,64,64,64,64 ${KINIT} rw debug ignore_loglevel print-fatal-signals=1 EMBA_NET=${EMBA_NET} EMBA_NVRAM=${EMBA_NVRAM} EMBA_KERNEL=${EMBA_KERNEL} EMBA_ETC=${EMBA_ETC} user_debug=0 firmadyne.syscall=1\" -nographic ${lQEMU_NETWORK} ${lQEMU_PARAMS} -serial file:${LOG_PATH_MODULE}/qemu.initial.serial.log -serial telnet:localhost:4321,server,nowait -serial unix:/tmp/qemu.${lIMAGE_NAME}.S1,server,nowait -monitor unix:/tmp/qemu.${lIMAGE_NAME},server,nowait ; pkill -9 -f tail.*-F.*\"${LOG_PATH_MODULE}\"" /tmp/do_not_create_run.sh 2
|
|
}
|
|
|
|
get_networking_details_emulation() {
|
|
IMAGE_NAME="${1:-}"
|
|
|
|
sub_module_title "Network identification - ${IMAGE_NAME}"
|
|
export PANICS=()
|
|
export DETECTED_IP=0
|
|
export MISSING_FILES=()
|
|
|
|
if [[ -f "${LOG_PATH_MODULE}"/qemu.initial.serial.log ]]; then
|
|
local lETH_INT="NONE"
|
|
local lVLAN_ID="NONE"
|
|
local lNETWORK_MODE="bridge"
|
|
local lNETWORK_DEVICE=""
|
|
|
|
export NVRAMS=()
|
|
export TCP_SERVICES_STARTUP=()
|
|
export UDP_SERVICES_STARTUP=()
|
|
|
|
local lNVRAM_ARR=()
|
|
local lNVRAM_TMP=()
|
|
local lNVRAM_ENTRY=""
|
|
local lBRIDGE_INTERFACES=()
|
|
local lBRIDGE_INT=""
|
|
local lINTERFACE_CANDIDATES=()
|
|
local lINTERFACE_CAND=""
|
|
local lVLAN_INFOS=()
|
|
local lVLAN_INFO=""
|
|
local lVLAN_HW_INFO_DEV=()
|
|
local lPORTS_ARR=()
|
|
local lPORT=""
|
|
|
|
local lTCP_PORT=""
|
|
local lUDP_PORT=""
|
|
local lMISSING_FILES_TMP=()
|
|
local lMISSING_DIRS_TMP=()
|
|
local lSERVICE_NAME=""
|
|
local lADJUST_PRIO=0 # adjust priority for detected network configuration
|
|
local l_NW_ENTRY_PRIO=1
|
|
|
|
mapfile -t lINTERFACE_CANDIDATES < <(grep -a "__inet_insert_ifa" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | cut -d: -f2- | sed -E 's/.*__inet_insert_ifa\[PID:\ [0-9]+\ //' |
|
|
sort -u | grep -v "device:lo ifa:0x0100007f" | grep -v -E " = -[0-9][0-9]" | sed 's/\[.*\]\ EMBA.*//' || true)
|
|
mapfile -t lBRIDGE_INTERFACES < <(grep -a "br_add_if\|br_dev_ioctl" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | cut -d: -f4- | sort -u || true)
|
|
# br_add_if[PID: 246 (brctl)]: br:br0 dev:vlan1
|
|
mapfile -t lVLAN_INFOS < <(grep -a "register_vlan_dev" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | cut -d: -f2- | sort -u | grep -v -E " = -[0-9][0-9]" || true)
|
|
# mapfile -t PANICS < <(grep -a "Kernel panic - " "${LOG_PATH_MODULE}"/qemu.initial.serial.log | sort -u || true)
|
|
# # ensure we only stop if we have a panic near the end - otherwise the system probably has rebooted and recovered
|
|
mapfile -t PANICS < <(tail -n 50 "${LOG_PATH_MODULE}"/qemu.initial.serial.log | grep -a "Kernel panic - " | sort -u || true)
|
|
mapfile -t lNVRAM_ARR < <(grep -a "\[NVRAM\] " "${LOG_PATH_MODULE}"/qemu.initial.serial.log | awk '{print $3}' | grep -a -E '[[:alnum:]]{3,50}' | sort -u || true)
|
|
# we check all available qemu logs for services that are started:
|
|
mapfile -t lPORTS_ARR < <(grep -a "inet_bind" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | sed -E 's/.*inet_bind\[PID:\ [0-9]+\ //' | sort -u || true)
|
|
mapfile -t lVLAN_HW_INFO_DEV < <(grep -a -E "adding VLAN [0-9] to HW filter on device eth[0-9]" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | awk -F\ '{print $NF}' | sort -u || true)
|
|
|
|
# we handle missing files in setup_network_config -> there we already remount the filesystem and we can perform the changes
|
|
mapfile -t lMISSING_FILES_TMP < <(grep -a -E "No such file or directory" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | tr ' ' '\n' | grep -a "/" | grep -a -v proc | tr -d ':' | tr -d "'" | tr -d '`' | sort -u || true)
|
|
MISSING_FILES+=("${lMISSING_FILES_TMP[@]}")
|
|
mapfile -t lMISSING_DIRS_TMP < <(grep -a -E "nonexistent directory" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | tr ' ' '\n' | grep -a "/" | grep -a -v proc | tr -d ':' | tr -d "'" | tr -d '`' | grep -a "^/" | sort -u || true)
|
|
MISSING_FILES+=("${lMISSING_DIRS_TMP[@]}")
|
|
|
|
lNVRAM_TMP=("${lNVRAM_ARR[@]}")
|
|
|
|
if [[ "${#lINTERFACE_CANDIDATES[@]}" -gt 0 || "${#lBRIDGE_INTERFACES[@]}" -gt 0 || "${#lVLAN_INFOS[@]}" -gt 0 || "${#lPORTS_ARR[@]}" -gt 0 || "${#lNVRAM_TMP[@]}" -gt 0 ]]; then
|
|
print_output "[+] Booted system detected."
|
|
BOOTED="yes"
|
|
fi
|
|
|
|
if [[ -v lNVRAM_TMP[@] ]]; then
|
|
for lNVRAM_ENTRY in "${lNVRAM_TMP[@]}"; do
|
|
if [[ "${lNVRAM_ENTRY}" =~ [[:print:]] ]]; then
|
|
lNVRAM_ENTRY=${lNVRAM_ENTRY//[\'\"\`\[\]\{\}\;]/}
|
|
if [[ ! " ${NVRAMS[*]} " =~ ${lNVRAM_ENTRY} ]]; then
|
|
NVRAMS+=("${lNVRAM_ENTRY}")
|
|
fi
|
|
fi
|
|
done
|
|
print_output "[*] NVRAM access detected ${ORANGE}${#NVRAMS[@]}${NC} times."
|
|
print_ln
|
|
fi
|
|
|
|
if [[ -v lPORTS_ARR[@] ]]; then
|
|
for lPORT in "${lPORTS_ARR[@]}"; do
|
|
lSERVICE_NAME=$(strip_color_codes "$(echo "${lPORT}" | sed -e 's/.*\((.*)\).*/\1/g' | tr -d "(" | tr -d ")")")
|
|
lSERVICE_NAME="${lSERVICE_NAME//[![:print:]]/}"
|
|
lTCP_PORT=$(strip_color_codes "$(echo "${lPORT}" | grep "SOCK_STREAM" | sed 's/.*SOCK_STREAM,\ //' | sort -u | cut -d: -f2)" || true)
|
|
lTCP_PORT="${lTCP_PORT//[![:print:]]/}"
|
|
lUDP_PORT=$(strip_color_codes "$(echo "${lPORT}" | grep "SOCK_DGRAM" | sed 's/.*SOCK_DGRAM,\ //' | sort -u | cut -d: -f2)" || true)
|
|
lUDP_PORT="${lUDP_PORT//[![:print:]]/}"
|
|
|
|
if [[ "${lTCP_PORT}" =~ [0-9]+ ]]; then
|
|
print_output "[*] Detected TCP service startup: ${ORANGE}${lSERVICE_NAME}${NC} / ${ORANGE}${lTCP_PORT}${NC}"
|
|
TCP_SERVICES_STARTUP+=("${lTCP_PORT}")
|
|
fi
|
|
if [[ "${lUDP_PORT}" =~ [0-9]+ ]]; then
|
|
print_output "[*] Detected UDP service startup: ${ORANGE}${lSERVICE_NAME}${NC} / ${ORANGE}${lUDP_PORT}${NC}"
|
|
UDP_SERVICES_STARTUP+=("${lUDP_PORT}")
|
|
fi
|
|
|
|
SERVICES_STARTUP+=("${lSERVICE_NAME}")
|
|
done
|
|
fi
|
|
|
|
mapfile -t SERVICES_STARTUP < <(printf "%s\n" "${SERVICES_STARTUP[@]}" | sort -u)
|
|
mapfile -t UDP_SERVICES_STARTUP < <(printf "%s\n" "${UDP_SERVICES_STARTUP[@]}" | sort -u)
|
|
mapfile -t TCP_SERVICES_STARTUP < <(printf "%s\n" "${TCP_SERVICES_STARTUP[@]}" | sort -u)
|
|
|
|
for lVLAN_INFO in "${lVLAN_INFOS[@]}"; do
|
|
# register_vlan_dev[PID: 128 (vconfig)]: dev:eth1.1 vlan_id:1
|
|
print_output "[*] Possible VLAN details detected: ${ORANGE}${lVLAN_INFO}${NC}"
|
|
done
|
|
|
|
if [[ -v lBRIDGE_INTERFACES[@] ]]; then
|
|
mapfile -t lBRIDGE_INTERFACES < <(printf "%s\n" "${lBRIDGE_INTERFACES[@]}" | sort -u)
|
|
print_ln
|
|
fi
|
|
|
|
for lINTERFACE_CAND in "${lINTERFACE_CANDIDATES[@]}"; do
|
|
l_NW_ENTRY_PRIO=1
|
|
lADJUST_PRIO=0 # adjust priority for detected network configuration
|
|
|
|
lINTERFACE_CAND="${lINTERFACE_CAND//[![:print:]]/}"
|
|
print_output "[*] Possible interface candidate detected: ${ORANGE}${lINTERFACE_CAND}${NC}"
|
|
# lINTERFACE_CAND -> __inet_insert_ifa[PID: 139 (ifconfig)]: device:br0 ifa:0xc0a80001
|
|
local lIP_ADDRESS_HEX=()
|
|
local lIP_CAND=""
|
|
lIP_CAND=$(echo "${lINTERFACE_CAND}" | tr ' ' '\n' | grep ifa | cut -d: -f2 | sed 's/0x//')
|
|
# shellcheck disable=SC2001
|
|
mapfile -t lIP_ADDRESS_HEX < <(echo "${lIP_CAND:0:8}" | sed 's/../0x&\n/g')
|
|
# lIP_ADDRESS_HEX -> c0a80001
|
|
# as I don't get it to change the hex ip to dec with printf, we do it the poor way:
|
|
local lIP=""
|
|
local lCNT=0
|
|
for _IPs in "${lIP_ADDRESS_HEX[@]}"; do
|
|
lCNT=$((lCNT + 1))
|
|
if [[ "${_IPs}" == "0x"* ]]; then
|
|
# shellcheck disable=SC2004
|
|
lIP="${lIP}.$((${_IPs}))"
|
|
fi
|
|
# ensure we only check a valid ip address - this is needed if our IP address extraction gets mangled data:
|
|
[[ "${lCNT}" -ge 4 ]] && break
|
|
done
|
|
|
|
lIP="${lIP/\./}"
|
|
|
|
IP_ADDRESS_=""
|
|
if [[ "${D_END,,}" == "eb" ]]; then
|
|
IP_ADDRESS_="${lIP}"
|
|
elif [[ "${D_END,,}" == "el" ]]; then
|
|
IP_ADDRESS_=$(echo "${lIP}" | tr '.' '\n' | tac | tr '\n' '.' | sed 's/\.$//')
|
|
fi
|
|
|
|
# we try to extract a backup IP address from the nvram log
|
|
# afterwards we can use this ip if we have a bridge interface with "0.0.0.0"
|
|
local lNVRAM_BACKUP_IP=""
|
|
lNVRAM_BACKUP_IP=$(grep -E -h "nvram_get_buf.*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" "${LOG_PATH_MODULE}"/qemu.initial.serial.log |
|
|
grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | grep -v "0\.0\.0\.0\|127\.0\.\|255\." | sort -u | head -1 || true)
|
|
|
|
# handle IP addresses 0.0.0.0 somehow:
|
|
if [[ "${IP_ADDRESS_}" == "0.0.0.0" ]]; then
|
|
lADJUST_PRIO=$((lADJUST_PRIO - 2))
|
|
# we use one of the idenfied IP addresses. If no IP address available we switch to default 192.168.0.1
|
|
if [[ "${lNVRAM_BACKUP_IP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
IP_ADDRESS_="${lNVRAM_BACKUP_IP}"
|
|
print_output "[*] Originally identified IP 0.0.0.0 -> using backup IP ${IP_ADDRESS_}"
|
|
elif [[ -s "${L10_SYS_EMU_RESULTS}" ]]; then
|
|
IP_ADDRESS_=$(cut -d\; -f8 "${L10_SYS_EMU_RESULTS}" | sort -u | tail -n1)
|
|
IP_ADDRESS_="${IP_ADDRESS_/*\ /}"
|
|
print_output "[*] Originally identified IP 0.0.0.0 -> using backup IP ${IP_ADDRESS_}"
|
|
else
|
|
IP_ADDRESS_="192.168.0.1"
|
|
print_output "[*] Originally identified IP 0.0.0.0 -> using default IP ${IP_ADDRESS_}"
|
|
fi
|
|
fi
|
|
|
|
# filter for non usable IP addresses:
|
|
if [[ "${IP_ADDRESS_}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && ! [[ "${IP_ADDRESS_}" == "127.0.0."* ]]; then
|
|
print_output "[*] Identified IP address: ${ORANGE}${IP_ADDRESS_}${NC} / ${ORANGE}${lINTERFACE_CAND}${NC}"
|
|
DETECTED_IP=1
|
|
# get the network device from our interface candidate
|
|
lNETWORK_DEVICE="$(echo "${lINTERFACE_CAND}" | grep device | cut -d: -f2- | sed "s/^.*\]:\ //" | awk '{print $1}' | cut -d: -f2 || true)"
|
|
# lINTERFACE_CAND -> __inet_insert_ifa[PID: 139 (ifconfig)]: device:br0 ifa:0xc0a80001
|
|
# __inet_insert_ifa[PID: 899 (udhcpc)]: device:eth0 ifa:0xbea48f41
|
|
# lNETWORK_DEVICE -> eth0, eth1.1, br0 ...
|
|
|
|
if [[ -n "${lNETWORK_DEVICE}" ]]; then
|
|
# if the network device is not a eth it is a bridge interface
|
|
# if we have lBRIDGE_INTERFACES we also check it here (this way we can correct the br interface entry):
|
|
if [[ "${lNETWORK_DEVICE}" != *"eth"* ]] || [[ "${#lBRIDGE_INTERFACES[@]}" -gt 0 ]]; then
|
|
print_output "[*] Possible br interface detected: ${ORANGE}${lNETWORK_DEVICE}${NC} / IP: ${ORANGE}${IP_ADDRESS_}${NC}"
|
|
lNETWORK_MODE="bridge"
|
|
if [[ "${#lBRIDGE_INTERFACES[@]}" -gt 0 ]]; then
|
|
for lBRIDGE_INT in "${lBRIDGE_INTERFACES[@]}"; do
|
|
# lBRIDGE_INT -> br_add_if[PID: 494 (brctl)]: br:br0 dev:eth0.1
|
|
# br_add_if[PID: 246 (brctl)]: br:br0 dev:vlan1
|
|
# lNETWORK_DEVICE -> br0
|
|
lBRIDGE_INT="${lBRIDGE_INT//[![:print:]]/}"
|
|
print_output "[*] Testing bridge interface: ${ORANGE}${lBRIDGE_INT}${NC}" "no_log"
|
|
lVLAN_ID="NONE"
|
|
# the lBRIDGE_INT entry also includes our lNETWORK_DEVICE ... eg br:br0 dev:eth1.1
|
|
if [[ "${lBRIDGE_INT}" == *"${lNETWORK_DEVICE}"* ]]; then
|
|
# matching is quite good. This means that the bridge entry (br_add_if[PID: 494 (brctl)]: br:br0 dev:eth0)
|
|
# is matching our interface candidate entry (__inet_insert_ifa[PID: 139 (ifconfig)]: device:eth0 ifa:0xc0a80001)
|
|
# Nevertheless, we also need to process non matching results where we have network entries without a matching
|
|
# bridge interface
|
|
print_output "[+] Processing matching bridge interface: ${ORANGE}${lBRIDGE_INT}${GREEN} / network device: ${ORANGE}${lNETWORK_DEVICE}${NC}"
|
|
lADJUST_PRIO=$((lADJUST_PRIO + 1))
|
|
else
|
|
print_output "[*] Processing NON matching bridge interface: ${ORANGE}${lBRIDGE_INT}${NC} / network device: ${ORANGE}${lNETWORK_DEVICE}${NC}"
|
|
lADJUST_PRIO=$((lADJUST_PRIO - 1))
|
|
fi
|
|
# br_add_if[PID: 138 (brctl)]: br:br0 dev:eth1.1
|
|
# extract the eth1 from dev:eth1
|
|
lETH_INT="$(echo "${lBRIDGE_INT}" | grep -o "dev:.*" | cut -d. -f1 | cut -d: -f2)"
|
|
lETH_INT="${lETH_INT//[![:print:]]/}"
|
|
# do we have vlans?
|
|
if [[ -v lVLAN_INFOS[@] ]]; then
|
|
iterate_vlans "${lETH_INT}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${IP_ADDRESS_}" "${lADJUST_PRIO}" "${lVLAN_INFOS[@]}"
|
|
fi
|
|
if echo "${lBRIDGE_INT}" | awk '{print $2}' | cut -d: -f2 | grep -q -E "[0-9]\.[0-9]"; then
|
|
# we have a vlan entry in our lBRIDGE_INT entry br:br0 dev:eth1.1:
|
|
lVLAN_ID="$(echo "${lBRIDGE_INT}" | grep -o "dev:.*" | cut -d. -f2)"
|
|
lVLAN_ID="${lVLAN_ID//[![:print:]]/}"
|
|
fi
|
|
if [[ -v lVLAN_HW_INFO_DEV[@] ]]; then
|
|
# lets store the current details before we do this VLAN iteration
|
|
l_NW_ENTRY_PRIO=$((3 + lADJUST_PRIO))
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
# if we have found some entry "adding VLAN [0-9] to HW filter on device ethX" in our qemu logs
|
|
# we check all these entries now and generate additional configurations for further evaluation
|
|
for lETH_INT in "${lVLAN_HW_INFO_DEV[@]}"; do
|
|
# if we found multiple interfaces belonging to a vlan we need to store all of them:
|
|
lETH_INT="${lETH_INT//[![:print:]]/}"
|
|
lVLAN_ID=$(grep -a -o -E "adding VLAN [0-9] to HW filter on device ${lETH_INT}" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | awk '{print $3}' | sort -u)
|
|
# initial entry with possible vlan information
|
|
l_NW_ENTRY_PRIO=$((5 + lADJUST_PRIO))
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
|
|
# entry with vlan NONE (just in case as backup)
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "NONE" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
|
|
if ! [[ "${lNETWORK_DEVICE}" == *br[0-9]* ]] && ! [[ "${lNETWORK_DEVICE}" == *eth[0-9]* ]]; then
|
|
# entry with vlan NONE and interface br0 - just as another fallback solution
|
|
local lNETWORK_DEVICE="br0"
|
|
print_output "[*] Fallback bridge interface - #1 ${ORANGE}${lNETWORK_DEVICE}${NC}"
|
|
l_NW_ENTRY_PRIO=$((3 + lADJUST_PRIO))
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
done
|
|
fi
|
|
# now we set the orig. network_device with the new details (lVLAN_ID=NONE):
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
|
|
if ! [[ "${lNETWORK_DEVICE}" == *br[0-9]* ]] && ! [[ "${lNETWORK_DEVICE}" == *eth[0-9]* ]]; then
|
|
# if we have a bridge device like br-lan we ensure we also have an entry with a usual br0 interface
|
|
local lNETWORK_DEVICE="br0"
|
|
print_output "[*] Fallback bridge interface - #2 ${ORANGE}${lNETWORK_DEVICE}${NC}"
|
|
l_NW_ENTRY_PRIO=$((3 + lADJUST_PRIO))
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
# if we have found that the br entry has for eg an ethX interface, we now check for the real br interface entry -> lNETWORK_DEVICE
|
|
lNETWORK_DEVICE="$(echo "${lBRIDGE_INT}" | grep -o "br:.*" | cut -d\ -f1 | cut -d: -f2)"
|
|
lNETWORK_DEVICE="${lNETWORK_DEVICE//[![:print:]]/}"
|
|
l_NW_ENTRY_PRIO=$((4 + lADJUST_PRIO))
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE:-br0}" "${lETH_INT:-eth0}" "${lVLAN_ID:-0}" "${lNETWORK_MODE:-bridge}" "${l_NW_ENTRY_PRIO}"
|
|
done
|
|
else
|
|
# set typical default values - this is just in case we have not found br_add_if entries:
|
|
lVLAN_ID="NONE"
|
|
l_NW_ENTRY_PRIO=$((3 + lADJUST_PRIO))
|
|
if [[ "$(grep -ac "eth0" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
|
|
lETH_INT="eth0"
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
if [[ "$(grep -ac "eth1" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
|
|
lETH_INT="eth1"
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
fi
|
|
elif [[ "${lNETWORK_DEVICE}" == *"eth"* ]]; then
|
|
print_output "[*] Possible eth network interface detected: ${ORANGE}${lNETWORK_DEVICE}${GREEN} / IP: ${ORANGE}${IP_ADDRESS_}${NC}"
|
|
lNETWORK_MODE="normal"
|
|
if echo "${lNETWORK_DEVICE}" | grep -q -E "[0-9]\.[0-9]"; then
|
|
# now we know that there is a vlan number - extract the vlan number now:
|
|
l_NW_ENTRY_PRIO=$((4 + lADJUST_PRIO))
|
|
lVLAN_ID="$(echo "${lNETWORK_DEVICE}" | cut -d. -f2 | grep -E "[0-9]+")"
|
|
lVLAN_ID="${lVLAN_ID//[![:print:]]/}"
|
|
elif [[ -v lVLAN_INFOS[@] ]]; then
|
|
lETH_INT="${lNETWORK_DEVICE/\.*/}"
|
|
iterate_vlans "${lETH_INT}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${IP_ADDRESS_}" "${lADJUST_PRIO}" "${lVLAN_INFOS[@]}"
|
|
else
|
|
l_NW_ENTRY_PRIO=$((3 + lADJUST_PRIO))
|
|
lVLAN_ID="NONE"
|
|
fi
|
|
lNETWORK_DEVICE="${lNETWORK_DEVICE/\.*/}"
|
|
lETH_INT="${lNETWORK_DEVICE/\.*/}"
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
else
|
|
# could not happen - just for future extension
|
|
print_output "[+] Possible other interface detected: ${ORANGE}${lNETWORK_DEVICE}${NC}"
|
|
lVLAN_ID="NONE"
|
|
lNETWORK_MODE="normal"
|
|
lNETWORK_DEVICE="${lNETWORK_DEVICE/\.*/}"
|
|
lETH_INT="${lNETWORK_DEVICE}"
|
|
l_NW_ENTRY_PRIO=1
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
fi
|
|
# this is a default (fallback) entry with the correct ip address:
|
|
l_NW_ENTRY_PRIO=$((2 + lADJUST_PRIO))
|
|
store_interface_details "${IP_ADDRESS_}" "br0" "${lETH_INT:-eth0}" "${lVLAN_ID:-NONE}" "default" "${l_NW_ENTRY_PRIO}"
|
|
# this is a default (fallback) entry with the correct ip address:
|
|
l_NW_ENTRY_PRIO=$((1 + lADJUST_PRIO))
|
|
store_interface_details "${IP_ADDRESS_}" "${lETH_INT:-eth0}" "${lETH_INT:-eth0}" "${lVLAN_ID:-NONE}" "interface" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
done
|
|
|
|
# this is for testing. Probably we can improve it in the future to have a better fallback handling
|
|
if [[ "${L10_DEBUG_MODE}" -eq 2 ]]; then
|
|
if [[ "${#lINTERFACE_CANDIDATES[@]}" -eq 0 ]] || [[ "${L10_DEBUG_MODE}" -eq 2 ]]; then
|
|
# in this case we do not have valid ip addresses
|
|
# this mechanism is very alpha and just as fallback mechanism designed
|
|
# we need to further improve this mechanism to include VLAN detection, bridge vs interface vs normal ...
|
|
local lIP_ADDR_BACKUP_ARR=()
|
|
local lIP_ADDR_BACKUP=""
|
|
mapfile -t lIP_ADDR_BACKUP_ARR < <(grep -h "ip.*addr" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | grep -o -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" |
|
|
grep -E -v "\.255$" | grep -v -E "\.0$" | grep -v -E "^127\." | grep -v "^255\." | sort -u || true)
|
|
for lIP_ADDR_BACKUP in "${lIP_ADDR_BACKUP_ARR[@]}"; do
|
|
# if we have bridge interfaces found and we have some eth0 entries in our qemu log we guess a shiny configuration
|
|
if [[ -v lBRIDGE_INTERFACES[@] ]]; then
|
|
if [[ "$(grep -ac "eth0" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
|
|
l_NW_ENTRY_PRIO=$((2 + lADJUST_PRIO))
|
|
store_interface_details "${lIP_ADDR_BACKUP}" "br0" "eth0" "NONE" "bridge" "${l_NW_ENTRY_PRIO}"
|
|
store_interface_details "${lIP_ADDR_BACKUP}" "br0" "eth0" "0" "bridge" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
fi
|
|
l_NW_ENTRY_PRIO=1
|
|
if [[ "$(grep -ac "eth0" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
|
|
store_interface_details "${lIP_ADDR_BACKUP}" "eth0" "eth0" "NONE" "interface" "${l_NW_ENTRY_PRIO}"
|
|
store_interface_details "${lIP_ADDR_BACKUP}" "br0" "eth0" "NONE" "default" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
if [[ "$(grep -ac "eth1" "${LOG_PATH_MODULE}"/qemu.initial.serial.log)" -gt 0 ]]; then
|
|
store_interface_details "${lIP_ADDR_BACKUP}" "eth1" "eth1" "NONE" "interface" "${l_NW_ENTRY_PRIO}"
|
|
store_interface_details "${lIP_ADDR_BACKUP}" "br0" "eth1" "NONE" "default" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
|
|
if [[ "${#IPS_INT_VLAN[@]}" -eq 0 ]]; then
|
|
# this section is if we have a brctl entry but no IP address
|
|
for lBRIDGE_INT in "${lBRIDGE_INTERFACES[@]}"; do
|
|
# br_add_if[PID: 138 (brctl)]: br:br0 dev:eth1.1
|
|
# lBRIDGE_INT -> br_add_if[PID: 494 (brctl)]: br:br0 dev:eth0.1
|
|
# lNETWORK_DEVICE -> br0
|
|
print_output "[*] Possible bridge interface candidate detected: ${ORANGE}${lBRIDGE_INT}${NC}"
|
|
lETH_INT="$(echo "${lBRIDGE_INT}" | grep -o "dev:.*" | cut -d. -f1 | cut -d: -f2 || true)"
|
|
lETH_INT="${lETH_INT//[![:print:]]/}"
|
|
lNETWORK_DEVICE="$(echo "${lBRIDGE_INT}" | sed "s/^.*\]:\ //" | grep -o "br:.*" | cut -d\ -f1 | cut -d: -f2 || true)"
|
|
lNETWORK_DEVICE="${lNETWORK_DEVICE//[![:print:]]/}"
|
|
IP_ADDRESS_="192.168.0.1"
|
|
lNETWORK_MODE="bridge"
|
|
if echo "${lBRIDGE_INT}" | awk '{print $2}' | cut -d: -f2 | grep -q -E "[0-9]\.[0-9]"; then
|
|
# we have a vlan entry:
|
|
# lVLAN_ID="$(echo "${lBRIDGE_INT}" | sed "s/^.*\]:\ //" | grep -o "dev:.*" | cut -d. -f2 | tr -dc '[:print:]' || true)"
|
|
lVLAN_ID="$(echo "${lBRIDGE_INT}" | grep -o "dev:.*" | cut -d. -f2 || true)"
|
|
lVLAN_ID="${lVLAN_ID//[![:print:]]/}"
|
|
else
|
|
lVLAN_ID="NONE"
|
|
if [[ -v lVLAN_INFOS[@] ]]; then
|
|
iterate_vlans "${lETH_INT}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${IP_ADDRESS_}" "${lADJUST_PRIO}" "${lVLAN_INFOS[@]}"
|
|
fi
|
|
fi
|
|
l_NW_ENTRY_PRIO=$((2 + lADJUST_PRIO))
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
done
|
|
fi
|
|
|
|
# fallback - default network configuration:
|
|
# we always add this as the last resort - with this at least ICMP should be possible in most cases
|
|
if [[ ! " ${IPS_INT_VLAN[*]} " =~ "normal" ]]; then
|
|
# print_output "[*] No IP address - use default address: ${ORANGE}192.168.0.1${NC}."
|
|
# print_output "[*] No VLAN."
|
|
# print_output "[*] No Network interface - use ${ORANGE}eth0${NC} network."
|
|
IP_ADDRESS_="192.168.0.1"
|
|
lNETWORK_MODE="normal"
|
|
l_NW_ENTRY_PRIO=1
|
|
if [[ "${FW_VENDOR:-}" == "AVM" ]]; then
|
|
# for AVM fritzboxen the default IP is set to the correct one:
|
|
IP_ADDRESS_="192.168.178.1"
|
|
l_NW_ENTRY_PRIO=$((2 + lADJUST_PRIO))
|
|
fi
|
|
lVLAN_ID="NONE"
|
|
lETH_INT="eth0"
|
|
lNETWORK_DEVICE="br0"
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
|
|
# fallback - default network configuration:
|
|
# we always add this as the last resort - with this at least ICMP should be possible in most cases
|
|
if [[ ! " ${IPS_INT_VLAN[*]} " =~ "default" ]]; then
|
|
# print_output "[*] No IP address - use default address: ${ORANGE}192.168.0.1${NC}."
|
|
# print_output "[*] No VLAN."
|
|
# print_output "[*] No Network interface - use ${ORANGE}eth0${NC} network."
|
|
IP_ADDRESS_="192.168.0.1"
|
|
lNETWORK_MODE="default"
|
|
l_NW_ENTRY_PRIO=1
|
|
if [[ "${FW_VENDOR:-}" == "AVM" ]]; then
|
|
# for AVM fritzboxen the default IP is set to the correct one:
|
|
IP_ADDRESS_="192.168.178.1"
|
|
l_NW_ENTRY_PRIO=$((2 + lADJUST_PRIO))
|
|
fi
|
|
lVLAN_ID="NONE"
|
|
lETH_INT="eth0"
|
|
lNETWORK_DEVICE="br0"
|
|
store_interface_details "${IP_ADDRESS_}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
fi
|
|
|
|
for PANIC in "${PANICS[@]}"; do
|
|
print_output "[!] WARNING: Kernel Panic detected: ${ORANGE}${PANIC}${NC}"
|
|
print_output "${NC}"
|
|
PANICS=()
|
|
done
|
|
color_qemu_log "${LOG_PATH_MODULE}/qemu.initial.serial.log"
|
|
else
|
|
print_output "[-] No ${ORANGE}${LOG_PATH_MODULE}/qemu.initial.serial.log${NC} log file generated."
|
|
fi
|
|
print_ln
|
|
}
|
|
|
|
store_interface_details() {
|
|
local lIP_ADDRESS="${1:-192.168.0.1}"
|
|
local lNETWORK_DEVICE="${2:-br0}"
|
|
local lETH_INT="${3:-eth0}"
|
|
local lVLAN_ID="${4:-NONE}"
|
|
local lNETWORK_MODE="${5:-bridge}"
|
|
local lENTRY_PRIO="${6:-1}"
|
|
|
|
print_output "[+] Interface details detected: IP address: ${ORANGE}${lIP_ADDRESS}${GREEN} / bridge dev: ${ORANGE}${lNETWORK_DEVICE}${GREEN} / network device: ${ORANGE}${lETH_INT}${GREEN} / vlan id: ${ORANGE}${lVLAN_ID}${GREEN} / network mode: ${ORANGE}${lNETWORK_MODE}${GREEN} / priority: ${ORANGE}${lENTRY_PRIO}${NC}"
|
|
|
|
IPS_INT_VLAN+=("${lENTRY_PRIO}"\;"${lIP_ADDRESS}"\;"${lNETWORK_DEVICE}"\;"${lETH_INT}"\;"${lVLAN_ID}"\;"${lNETWORK_MODE}")
|
|
}
|
|
|
|
iterate_vlans() {
|
|
local lETH_INT="${1:-}"
|
|
local lNETWORK_MODE="${2:-}"
|
|
local lNETWORK_DEVICE="${3:-}"
|
|
local lIP_ADDRESS="${4:-}"
|
|
local lADJUST_PRIO="${5:-}"
|
|
shift 5
|
|
local lVLAN_INFOS_ARR=("$@")
|
|
|
|
local lETH_INT_=""
|
|
local lETH_INTS_ARR=()
|
|
local lVLAN_DEV=""
|
|
local lVLAN_ID="NONE"
|
|
local lVLAN_INFO=""
|
|
|
|
for lVLAN_INFO in "${lVLAN_INFOS_ARR[@]}"; do
|
|
print_output "[*] Analyzing VLAN details ${ORANGE}${lVLAN_INFO}${NC}"
|
|
if ! [[ "${lVLAN_INFO}" == *"register_vlan_dev"* ]]; then
|
|
continue
|
|
fi
|
|
# lVLAN_INFO -> register_vlan_dev[PID: 848 (vconfig)]: dev:eth2.1 vlan_id:1
|
|
# register_vlan_dev[PID: 213 (vconfig)]: dev:vlan1 vlan_id:1
|
|
lVLAN_DEV=$(echo "${lVLAN_INFO}" | sed "s/^.*\]:\ //" | awk '{print $1}' | cut -d: -f2 | cut -d\. -f1)
|
|
print_output "[*] VLAN details: ${ORANGE}${lVLAN_INFO}${NC}"
|
|
print_output "[*] Interface details: ${ORANGE}${lETH_INT}${NC}"
|
|
if [[ "${lVLAN_DEV}" == *"${lETH_INT}"* ]]; then
|
|
print_output "[*] Possible matching VLAN details detected: ${ORANGE}${lVLAN_INFO}${NC}"
|
|
l_NW_ENTRY_PRIO=$((5 + lADJUST_PRIO))
|
|
lVLAN_ID=$(echo "${lVLAN_INFO}" | sed "s/.*vlan_id://" | grep -E -o "[0-9]+")
|
|
lVLAN_ID="${lVLAN_ID//[![:print:]]/}"
|
|
else
|
|
l_NW_ENTRY_PRIO=$((2 + lADJUST_PRIO))
|
|
lVLAN_ID="NONE"
|
|
fi
|
|
store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "${lETH_INT}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
|
|
# check this later
|
|
# store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "eth0" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
# store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "eth0" "0" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
# store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "eth1" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
# store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "eth1" "0" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
|
|
# if we have entries without an interface name, we need to identify an interface name:
|
|
# register_vlan_dev[PID: 212 (vconfig)]: dev:vlan1 vlan_id:1
|
|
# for this we try to check the qemu output for vlan entries and generate the configuration entry
|
|
if grep -a -q "adding VLAN [0-9] to HW filter on device eth[0-9]" "${LOG_PATH_MODULE}"/qemu.initial.serial.log; then
|
|
mapfile -t lETH_INTS_ARR < <(grep -a -E "adding VLAN [0-9] to HW filter on device eth[0-9]" "${LOG_PATH_MODULE}"/qemu.initial.serial.log | awk -F\ '{print $NF}' | sort -u)
|
|
for lETH_INT_ in "${lETH_INTS_ARR[@]}"; do
|
|
# if we found multiple interfaces belonging to a vlan we need to store all of them:
|
|
lETH_INT_="${lETH_INT_//[![:print:]]/}"
|
|
l_NW_ENTRY_PRIO=$((4 + lADJUST_PRIO))
|
|
store_interface_details "${lIP_ADDRESS}" "${lNETWORK_DEVICE}" "${lETH_INT_}" "${lVLAN_ID}" "${lNETWORK_MODE}" "${l_NW_ENTRY_PRIO}"
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
setup_network_emulation() {
|
|
local lIPS_INT_VLAN_CFG="${1:-}"
|
|
|
|
local lIP_ADDRESS=""
|
|
local lNETWORK_DEVICE=""
|
|
local lETH_INT=""
|
|
local lNETWORK_MODE=""
|
|
local lTAP_ID=""
|
|
local lHOSTIP=""
|
|
local lVLAN_ID=""
|
|
export BR_NUM=0
|
|
export ETH_NUM=0
|
|
|
|
sub_module_title "Setup networking - ${lIPS_INT_VLAN_CFG//\;/-}"
|
|
|
|
# Source: IPS_INT_VLAN+=( "PRIO"-"${IP_ADDRESS_}"-"${lNETWORK_DEVICE}"-"${lETH_INT}"-"${lVLAN_ID}"-"${lNETWORK_MODE}" )
|
|
lIP_ADDRESS="$(cut -d\; -f2 <<<"${lIPS_INT_VLAN_CFG}")" # field 2
|
|
lNETWORK_DEVICE="$(cut -d\; -f3 <<<"${lIPS_INT_VLAN_CFG}")" # field 3
|
|
lETH_INT="$(cut -d\; -f4 <<<"${lIPS_INT_VLAN_CFG}")" # field 4
|
|
lVLAN_ID="$(cut -d\; -f5 <<<"${lIPS_INT_VLAN_CFG}")" # field 5
|
|
lNETWORK_MODE="$(cut -d\; -f6 <<<"${lIPS_INT_VLAN_CFG}")" # field 6
|
|
|
|
# a br interface with a number ... eg br0, br1 ... but no br-lan interface
|
|
if [[ "${lNETWORK_DEVICE}" == *"br"* ]] && [[ "${lNETWORK_DEVICE}" == *[0-9]* ]]; then
|
|
BR_NUM="${lNETWORK_DEVICE/br/}"
|
|
BR_NUM="${BR_NUM//[![:print:]]/}"
|
|
fi
|
|
if [[ "${lETH_INT}" =~ .*eth[0-9]+.* ]]; then
|
|
ETH_NUM="${lETH_INT/eth/}"
|
|
ETH_NUM="${ETH_NUM//[![:print:]]/}"
|
|
fi
|
|
|
|
# used for generating startup scripts for offline analysis
|
|
export ARCHIVE_PATH="${LOG_PATH_MODULE}"/archive-"${IMAGE_NAME}"-"${RANDOM}"
|
|
|
|
if ! [[ -d "${ARCHIVE_PATH}" ]]; then
|
|
mkdir "${ARCHIVE_PATH}"
|
|
fi
|
|
|
|
lTAP_ID=$(shuf -i 1-1000 -n 1)
|
|
|
|
# bridge, no vlan, ip address
|
|
export TAPDEV_0="tap${lTAP_ID}_0"
|
|
if ifconfig | grep -q "${TAPDEV_0}"; then
|
|
lTAP_ID=$(shuf -i 1-1000 -n 1)
|
|
TAPDEV_0="tap${lTAP_ID}_0"
|
|
fi
|
|
export HOSTNETDEV_0="${TAPDEV_0}"
|
|
print_output "[*] Creating TAP device ${ORANGE}${TAPDEV_0}${NC} ..."
|
|
write_script_exec "echo -e \"Creating TAP device ${TAPDEV_0}\n\"" "${ARCHIVE_PATH}"/run.sh 0
|
|
write_script_exec "command -v tunctl > /dev/null || (echo \"Missing tunctl ... check your installation - install uml-utilities package\" && exit 1)" "${ARCHIVE_PATH}"/run.sh 0
|
|
write_script_exec "tunctl -t ${TAPDEV_0}" "${ARCHIVE_PATH}"/run.sh 1
|
|
|
|
if [[ "${lVLAN_ID}" != "NONE" ]]; then
|
|
HOSTNETDEV_0="${TAPDEV_0}"."${lVLAN_ID}"
|
|
print_output "[*] Bringing up HOSTNETDEV ${ORANGE}${HOSTNETDEV_0}${NC} / VLAN ID ${ORANGE}${lVLAN_ID}${NC} / TAPDEV ${ORANGE}${TAPDEV_0}${NC}."
|
|
write_script_exec "echo -e \"Bringing up HOSTNETDEV ${ORANGE}${HOSTNETDEV_0}${NC} / VLAN ID ${ORANGE}${lVLAN_ID}${NC} / TAPDEV ${ORANGE}${TAPDEV_0}${NC}.\n\"" "${ARCHIVE_PATH}"/run.sh 0
|
|
write_script_exec "ip link add link ${TAPDEV_0} name ${HOSTNETDEV_0} type vlan id ${lVLAN_ID}" "${ARCHIVE_PATH}"/run.sh 1
|
|
write_script_exec "ip link set ${TAPDEV_0} up" "${ARCHIVE_PATH}"/run.sh 1
|
|
fi
|
|
|
|
if [[ "${lIP_ADDRESS}" != "NONE" ]]; then
|
|
# we change the host IP based on the identified IP address:
|
|
if [[ "$(echo "${lIP_ADDRESS}" | sed 's/\./&\n/g' | grep -v -E "[0-9]+\.$")" -ne 2 ]]; then
|
|
lHOSTIP="$(echo "${lIP_ADDRESS}" | sed 's/\./&\n/g' | sed -E 's/^[0-9]+$/2/' | tr -d '\n')"
|
|
else
|
|
lHOSTIP="$(echo "${lIP_ADDRESS}" | sed 's/\./&\n/g' | sed -E 's/^[0-9]+$/3/' | tr -d '\n')"
|
|
fi
|
|
print_output "[*] Bringing up HOSTIP ${ORANGE}${lHOSTIP}${NC} / IP address ${ORANGE}${lIP_ADDRESS}${NC} / TAPDEV ${ORANGE}${TAPDEV_0}${NC}."
|
|
write_script_exec "echo -e \"Bringing up HOSTIP ${ORANGE}${lHOSTIP}${NC} / IP address ${ORANGE}${lIP_ADDRESS}${NC} / TAPDEV ${ORANGE}${TAPDEV_0}${NC}.\n\"" "${ARCHIVE_PATH}"/run.sh 0
|
|
|
|
write_script_exec "ip link set ${HOSTNETDEV_0} up" "${ARCHIVE_PATH}"/run.sh 1
|
|
|
|
write_script_exec "ip addr add ${lHOSTIP}/8 dev ${HOSTNETDEV_0}" "${ARCHIVE_PATH}"/run.sh 1
|
|
|
|
write_script_exec "ifconfig -a" "${ARCHIVE_PATH}"/run.sh 1
|
|
write_script_exec "route -n" "${ARCHIVE_PATH}"/run.sh 1
|
|
fi
|
|
|
|
print_ln
|
|
write_network_config_to_filesystem "${IMAGE_NAME}" "${lETH_INT}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${lIP_ADDRESS}"
|
|
}
|
|
|
|
write_network_config_to_filesystem() {
|
|
local lIMAGE_NAME="${1:-}"
|
|
local lETH_INT="${2:-}"
|
|
local lNETWORK_MODE="${3:-}"
|
|
local lNETWORK_DEVICE="${4:-}"
|
|
local lIP_ADDRESS="${5:-}"
|
|
|
|
local lDEVICE="NA"
|
|
local lFILE_PATH_MISSING=""
|
|
local lFILENAME_MISSING=""
|
|
local lDIR_NAME_MISSING=""
|
|
local lFOUND_MISSING=""
|
|
|
|
# mount filesystem again for network config:
|
|
print_output "[*] Identify Qemu Image device for ${ORANGE}${LOG_PATH_MODULE}/${lIMAGE_NAME}${NC}"
|
|
local lCNT=0
|
|
while [[ "${lDEVICE:-NA}" == "NA" ]]; do
|
|
lDEVICE="$(add_partition_emulation "${LOG_PATH_MODULE}/${lIMAGE_NAME}")"
|
|
lCNT=$((lCNT + 1))
|
|
if [[ "${lDEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
|
|
print_output "[-] No Qemu Image device identified - return from ${FUNCNAME[0]}"
|
|
return
|
|
fi
|
|
sleep 5
|
|
done
|
|
sleep 1
|
|
print_output "[*] Device mapper created at ${ORANGE}${lDEVICE}${NC}"
|
|
print_output "[*] Mounting QEMU Image Partition 1 to ${ORANGE}${MNT_POINT}${NC}"
|
|
mount "${lDEVICE}" "${MNT_POINT}" || true
|
|
if mount | grep -q "${MNT_POINT}"; then
|
|
print_output "[*] Setting network configuration in target filesystem:"
|
|
print_output "$(indent "Network interface: ${ORANGE}${lETH_INT}${NC}")"
|
|
print_output "$(indent "Network mode: ${ORANGE}${lNETWORK_MODE}${NC}")"
|
|
print_output "$(indent "Bridge interface: ${ORANGE}${lNETWORK_DEVICE}${NC}")"
|
|
print_output "$(indent "IP address: ${ORANGE}${lIP_ADDRESS}${NC}")"
|
|
|
|
set_network_config "${lIP_ADDRESS}" "${lNETWORK_MODE}" "${lNETWORK_DEVICE}" "${lETH_INT}"
|
|
|
|
# if there were missing files found -> we try to fix this now
|
|
if [[ -v MISSING_FILES[@] ]]; then
|
|
mapfile -t MISSING_FILES < <(printf "%s\n" "${MISSING_FILES[@]}" | sort -u)
|
|
|
|
for lFILE_PATH_MISSING in "${MISSING_FILES[@]}"; do
|
|
lFILE_PATH_MISSING="${lFILE_PATH_MISSING//[![:print:]]/}"
|
|
print_output "[*] Checking for missing area ${ORANGE}${lFILE_PATH_MISSING}${NC} in filesystem ..."
|
|
[[ "${lFILE_PATH_MISSING}" == *"firmadyne"* ]] && continue
|
|
[[ "${lFILE_PATH_MISSING}" == *"/proc/"* ]] && continue
|
|
[[ "${lFILE_PATH_MISSING}" == *"/sys/"* ]] && continue
|
|
[[ "${lFILE_PATH_MISSING}" == *"/dev/"* ]] && continue
|
|
[[ "${lFILE_PATH_MISSING}" == *"reboot"* ]] && continue
|
|
# ugly false positive cleanup
|
|
[[ "${lFILE_PATH_MISSING}" == *"EMBA_"* ]] && continue
|
|
|
|
lFILENAME_MISSING=$(basename "${lFILE_PATH_MISSING}")
|
|
# ensure the found path is nothing with a '*' in it:
|
|
[[ "${lFILENAME_MISSING}" =~ \* ]] && continue
|
|
print_output "[*] Found missing area ${ORANGE}${lFILE_PATH_MISSING}${NC} in filesystem ... trying to fix this now"
|
|
lDIR_NAME_MISSING=$(dirname "${lFILE_PATH_MISSING}")
|
|
if ! [[ -d "${MNT_POINT}/${lDIR_NAME_MISSING#/}" ]]; then
|
|
print_output "[*] Create missing directory ${ORANGE}/${lDIR_NAME_MISSING#/}${NC} in filesystem ... trying to fix this now"
|
|
mkdir -p "${MNT_POINT}/${lDIR_NAME_MISSING#/}" 2>/dev/null || true
|
|
fi
|
|
lFOUND_MISSING=$(find "${MNT_POINT}" -type f -name "${lFILENAME_MISSING}" | head -1 || true)
|
|
if [[ -f ${lFOUND_MISSING} ]] && ! [[ -f "${MNT_POINT}/${lDIR_NAME_MISSING#/}/${lFILENAME_MISSING}" ]]; then
|
|
print_output "[*] Recover missing file ${ORANGE}${lFILENAME_MISSING}${NC} in filesystem (${ORANGE}${MNT_POINT}/${lDIR_NAME_MISSING#/}/${lFILENAME_MISSING}${NC}) ... trying to fix this now"
|
|
cp --update=none "${lFOUND_MISSING}" "${MNT_POINT}/${lDIR_NAME_MISSING#/}"/ || true
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# as we have the filesytem mounted right before the final run we can link libnvram now
|
|
link_libnvram_so "${MNT_POINT}" "dbg"
|
|
|
|
# if we have a /tmp/EMBA_config_state from a previous emulation run we need to remove it
|
|
# before the next emulation testrun
|
|
# This file is an indiator that the initial network config was done and we can start checking
|
|
# the network config during emulation
|
|
rm "${MNT_POINT}"/tmp/EMBA_config_state 2>/dev/null || true
|
|
|
|
# umount filesystem:
|
|
umount_qemu_image "${lDEVICE}"
|
|
delete_device_entry "${lIMAGE_NAME}" "${lDEVICE}" "${MNT_POINT}"
|
|
fi
|
|
}
|
|
|
|
nvram_check() {
|
|
local lIMAGE_NAME="${1:-}"
|
|
local lMAX_THREADS_NVRAM=$((4 * "$(nproc || echo 1)"))
|
|
local lDEVICE=""
|
|
local lWAIT_PIDS_AE=()
|
|
local lCURRENT_DIR=""
|
|
local lNVRAM_FILE_LIST=()
|
|
local lNVRAM_FILE=""
|
|
|
|
# mount filesystem again for network config:
|
|
print_output "[*] Identify Qemu Image device for ${ORANGE}${LOG_PATH_MODULE}/${lIMAGE_NAME}${NC}"
|
|
local lCNT=0
|
|
while [[ "${lDEVICE:-NA}" == "NA" ]]; do
|
|
lDEVICE="$(add_partition_emulation "${LOG_PATH_MODULE}/${lIMAGE_NAME}")"
|
|
lCNT=$((lCNT + 1))
|
|
if [[ "${lDEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
|
|
print_output "[-] No Qemu Image device identified - return from ${FUNCNAME[0]}"
|
|
return
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
print_output "[*] Device mapper created at ${ORANGE}${lDEVICE}${NC}"
|
|
print_output "[*] Mounting QEMU Image Partition 1 to ${ORANGE}${MNT_POINT}${NC}"
|
|
mount "${lDEVICE}" "${MNT_POINT}" || true
|
|
|
|
if mount | grep -q "${MNT_POINT}"; then
|
|
# we check for NVRAM access. Threshold value is a random 5
|
|
if [[ -v NVRAMS[@] ]] && [[ "${#NVRAMS[@]}" -gt 5 ]]; then
|
|
print_output "[*] NVRAM access detected ${ORANGE}${#NVRAMS[@]}${NC} times. Testing NVRAM access now."
|
|
lCURRENT_DIR=$(pwd)
|
|
cd "${MNT_POINT}" || exit
|
|
# generate a file list of the firmware
|
|
mapfile -t lNVRAM_FILE_LIST < <(find . -xdev -type f -not -path "*/firmadyne*" -exec file {} \; | grep "ASCII text" || true)
|
|
|
|
if ! [[ -d "${LOG_PATH_MODULE}"/nvram ]]; then
|
|
mkdir "${LOG_PATH_MODULE}"/nvram
|
|
fi
|
|
|
|
# need to check for firmadyne string in path
|
|
for lNVRAM_FILE in "${lNVRAM_FILE_LIST[@]}"; do
|
|
nvram_searcher_emulation "${lNVRAM_FILE/:*/}" &
|
|
lWAIT_PIDS_AE+=("$!")
|
|
max_pids_protection "${lMAX_THREADS_NVRAM}" lWAIT_PIDS_AE
|
|
done
|
|
wait_for_pid "${lWAIT_PIDS_AE[@]}"
|
|
cd "${lCURRENT_DIR}" || exit
|
|
fi
|
|
|
|
if [[ -f "${LOG_PATH_MODULE}"/nvram/nvram_files_final ]]; then
|
|
if [[ "$(wc -l <"${LOG_PATH_MODULE}"/nvram/nvram_files_final)" -gt 0 ]]; then
|
|
# print_output "[*] Identified the following NVRAM files:"
|
|
# tee -a "${LOG_FILE}" < "${LOG_PATH_MODULE}"/nvram/nvram_files_final
|
|
|
|
sort -u -r -h -k2 "${LOG_PATH_MODULE}"/nvram/nvram_files_final | sort -u -k1,1 | sort -r -h -k2 | head -10 >"${MNT_POINT}"/firmadyne/nvram_files || true
|
|
# store a copy in the log dir
|
|
cp "${MNT_POINT}"/firmadyne/nvram_files "${LOG_PATH_MODULE}"/nvram/nvram_files_final_ || true
|
|
|
|
print_ln
|
|
print_output "[*] Setting up ${ORANGE}nvram_files${NC} in target filesystem:"
|
|
tee -a "${LOG_FILE}" <"${LOG_PATH_MODULE}"/nvram/nvram_files_final_
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# umount filesystem:
|
|
umount_qemu_image "${lDEVICE}"
|
|
delete_device_entry "${lIMAGE_NAME}" "${lDEVICE}" "${MNT_POINT}"
|
|
}
|
|
|
|
nvram_searcher_emulation() {
|
|
local lNVRAM_FILE="${1:-}"
|
|
|
|
# lets store it in tmp var for supporting binary files in the future
|
|
local lNVRAM_FILE_TMP="${lNVRAM_FILE}"
|
|
local lMAX_VALUES=""
|
|
local lCOUNT=0
|
|
|
|
if [[ "${#NVRAMS[@]}" -gt 1000 ]]; then
|
|
lMAX_VALUES=1000
|
|
else
|
|
lMAX_VALUES="${#NVRAMS[@]}"
|
|
fi
|
|
|
|
for ((j = 0; j < "${lMAX_VALUES}"; j++)); do
|
|
lNVRAM_ENTRY="${NVRAMS[${j}]}"
|
|
lNVRAM_KEY=""
|
|
# check https://github.com/pr0v3rbs/FirmAE/blob/master/scripts/inferDefault.py
|
|
echo "${lNVRAM_ENTRY}" >>"${LOG_PATH_MODULE}"/nvram/nvram_keys.tmp
|
|
lNVRAM_KEY=$(echo "${lNVRAM_ENTRY}" | tr -s '[:blank:]')
|
|
lNVRAM_KEY="${lNVRAM_KEY//[![:print:]]/}"
|
|
if [[ "${lNVRAM_KEY}" =~ [a-zA-Z0-9_] && "${#lNVRAM_KEY}" -gt 3 ]]; then
|
|
# print_output "[*] NVRAM access detected: $ORANGE$NVRAM_KEY$NC"
|
|
if grep -q "${lNVRAM_KEY}" "${lNVRAM_FILE_TMP}" 2>/dev/null; then
|
|
# print_output "[*] Possible NVRAM access via key ${ORANGE}${lNVRAM_KEY}${NC} found in NVRAM file ${ORANGE}${lNVRAM_FILE}${NC}."
|
|
lCOUNT=$((lCOUNT + 1))
|
|
fi
|
|
echo "${lNVRAM_KEY}" >>"${LOG_PATH_MODULE}"/nvram/nvram_keys.log
|
|
fi
|
|
done
|
|
|
|
if [[ "${lCOUNT}" -gt 5 ]]; then
|
|
print_output "[*] ${lNVRAM_FILE/\./} ${lCOUNT} ASCII_text"
|
|
echo "${lNVRAM_FILE/\./} ${lCOUNT} ASCII_text" >>"${LOG_PATH_MODULE}"/nvram/nvram_files_final
|
|
fi
|
|
}
|
|
|
|
run_emulated_system() {
|
|
local lIP_ADDRESS="${1:-}"
|
|
local lIMAGE_NAME="${2:-}"
|
|
local lINIT_FILE="${3:-}"
|
|
local lARCH_END="${4:-}"
|
|
|
|
sub_module_title "Final system emulation for ${lIP_ADDRESS} - ${lINIT_FILE} - ${KINIT} - ${lARCH_END} - ${lIMAGE_NAME}"
|
|
|
|
local IMAGE="${LOG_PATH_MODULE}/${lIMAGE_NAME}"
|
|
|
|
export KERNEL_V=".4"
|
|
get_kernel_version
|
|
if [[ -n "${KERNEL_V:-}" ]]; then
|
|
print_output "[*] Kernel ${KERNEL_V}.x detected -> Using Kernel v4.x"
|
|
# KERNEL_V=".$KERNEL_V"
|
|
KERNEL_V=".4"
|
|
fi
|
|
|
|
local lNET_NUM=0
|
|
local lNET_ID=0
|
|
local lCPU=""
|
|
local lKERNEL=""
|
|
local lQEMU_BIN=""
|
|
local lQEMU_MACHINE=""
|
|
local lQEMU_DISK=""
|
|
local lQEMU_PARAMS=""
|
|
local lQEMU_NETWORK=""
|
|
local lQEMU_ROOTFS=""
|
|
local lCONSOLE="ttyS0"
|
|
local lQEMU_NET_DEVICE=""
|
|
|
|
if [[ "${lARCH_END}" == "mipsel" ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-${lARCH_END}"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64r2el" ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-${lARCH_END}"
|
|
lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mipseb" ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-mips"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64r2eb" ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-mips64"
|
|
lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64v1eb" ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-mips64"
|
|
# lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64v1el" ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-mips64el"
|
|
# lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "mips64n32eb" ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}${KERNEL_V}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-mips64"
|
|
lCPU="-cpu MIPS64R2-generic"
|
|
lQEMU_MACHINE="malta"
|
|
elif [[ "${lARCH_END}" == "armel"* ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/zImage.${lARCH_END}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/zImage.${lARCH_END}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-arm"
|
|
lQEMU_MACHINE="virt"
|
|
elif [[ "${lARCH_END}" == "arm64el"* ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/Image.${lARCH_END}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/Image.${lARCH_END}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-aarch64"
|
|
# lCONSOLE="ttyAMA0"
|
|
lCPU="-cpu cortex-a57"
|
|
lQEMU_MACHINE="virt"
|
|
elif [[ "${lARCH_END}" == "x86el"* ]]; then
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/bzImage.${lARCH_END}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/bzImage.${lARCH_END}"
|
|
else
|
|
print_output "[-] Missing kernel for ${L10_KERNEL_V_LONG} / ${lARCH_END}"
|
|
return
|
|
fi
|
|
lQEMU_BIN="qemu-system-x86_64"
|
|
lQEMU_MACHINE="pc-i440fx-8.2"
|
|
elif [[ "${lARCH_END}" == "nios2el" ]]; then
|
|
# not implemented -> Future
|
|
if [[ -f "${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}" ]]; then
|
|
lKERNEL="${BINARY_DIR}/Linux-Kernel-v${L10_KERNEL_V_LONG}/vmlinux.${lARCH_END}"
|
|
else
|
|
lKERNEL="${BINARY_DIR}/vmlinux.${lARCH_END}"
|
|
fi
|
|
lQEMU_BIN="qemu-system-nios2"
|
|
lQEMU_MACHINE="10m50-ghrd"
|
|
else
|
|
lQEMU_BIN="NA"
|
|
fi
|
|
|
|
if [[ "${ARCH}" == "ARM"* ]]; then
|
|
lQEMU_DISK="-drive if=none,file=${IMAGE},format=raw,id=rootfs -device virtio-blk-device,drive=rootfs"
|
|
lQEMU_PARAMS="-audiodev driver=none,id=none"
|
|
lQEMU_ROOTFS="/dev/vda1"
|
|
# newer kernels use virtio only
|
|
lQEMU_NET_DEVICE="virtio-net-device"
|
|
elif [[ "${ARCH}" == "NIOS2" ]]; then
|
|
lQEMU_PARAMS="-monitor none"
|
|
lQEMU_DISK="-drive file=${IMAGE},format=raw"
|
|
lQEMU_NET_DEVICE="virtio-net-device"
|
|
elif [[ "${ARCH}" == "MIPS" ]] || [[ "${lARCH_END}" == "x86el" ]] || [[ "${lARCH_END}" == "mips64"* ]]; then
|
|
lQEMU_DISK="-drive if=ide,format=raw,file=${IMAGE}"
|
|
lQEMU_PARAMS=""
|
|
lQEMU_ROOTFS="/dev/sda1"
|
|
lQEMU_NET_DEVICE="e1000"
|
|
fi
|
|
|
|
if [[ "${ARCH}" == "MIPS" ]] || [[ "${lARCH_END}" == "x86el" ]] || [[ "${lARCH_END}" == "mips64"* ]] || [[ "${ARCH}" == "ARM"* ]]; then
|
|
if [[ -n "${ETH_NUM}" ]]; then
|
|
# if we found an eth interface we use this
|
|
lNET_NUM="${ETH_NUM}"
|
|
elif [[ -n "${BR_NUM}" ]]; then
|
|
# if we found no eth interface but a br interface we use this
|
|
lNET_NUM="${BR_NUM}"
|
|
else
|
|
# fallback - we connect id 0
|
|
lNET_NUM=0
|
|
fi
|
|
if [[ "${lNET_NUM}" -gt 5 ]]; then
|
|
print_output "[*] NET_NUM ${lNET_NUM} issues -> setting default NET_NUM to 0"
|
|
lNET_NUM=0
|
|
fi
|
|
|
|
# 6 Interfaces -> 0-5
|
|
for lNET_ID in {0..5}; do
|
|
print_output "[*] Network ID ${lNET_ID} connector / lNET_NUM: ${lNET_NUM}"
|
|
if [[ "${lNET_ID}" == "${lNET_NUM}" ]]; then
|
|
# if MATCH in IPS_INT -> connect this interface to host
|
|
print_output "[*] Connect interface: ${ORANGE}${lNET_ID}${NC} to host"
|
|
lQEMU_NETWORK+=" -device ${lQEMU_NET_DEVICE},netdev=net${lNET_ID}"
|
|
lQEMU_NETWORK+=" -netdev tap,id=net${lNET_ID},ifname=${TAPDEV_0},script=no"
|
|
else
|
|
# only 0-3 are handled via placeholder interfaces
|
|
if [[ "${lNET_ID}" -gt 3 ]]; then
|
|
print_output "[*] Network ID ${lNET_ID} bypass"
|
|
continue
|
|
fi
|
|
# on ARM we have currently only one interface and we need to connect this to the host
|
|
# This means we do not place placeholder interfaces for ARM architecture
|
|
if [[ "${ARCH}" != "ARM"* ]]; then
|
|
print_output "[*] Create socket placeholder interface: ${ORANGE}${lNET_ID}${NC}"
|
|
# place a socket connection placeholder:
|
|
lQEMU_NETWORK+=" -device ${lQEMU_NET_DEVICE},netdev=net${lNET_ID}"
|
|
lQEMU_NETWORK+=" -netdev socket,id=net${lNET_ID},listen=:200${lNET_ID}"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [[ -z "${lQEMU_NETWORK}" ]]; then
|
|
print_output "[!] No network interface config created ... creating backup configuration"
|
|
lNET_ID=0
|
|
print_output "[*] Connect interface: ${ORANGE}${lNET_ID}${NC} to host"
|
|
lQEMU_NETWORK+=" -device ${lQEMU_NET_DEVICE},netdev=net${lNET_ID}"
|
|
lQEMU_NETWORK+=" -netdev tap,id=net${lNET_ID},ifname=${TAPDEV_0},script=no"
|
|
fi
|
|
|
|
# dirty workaround to fill the KERNEL which is used later on
|
|
export KERNEL="${lKERNEL}"
|
|
|
|
if [[ "${lQEMU_BIN}" != "NA" ]]; then
|
|
run_qemu_final_emulation "${lCONSOLE}" "${lCPU}" "${lKERNEL}" "${lQEMU_BIN}" "${lQEMU_MACHINE}" "${lQEMU_DISK}" "${lQEMU_PARAMS}" "${lQEMU_NETWORK}" "${lQEMU_ROOTFS}" "${lIP_ADDRESS}" "${lIMAGE_NAME}" "${lINIT_FILE}" "${lARCH_END}" &
|
|
else
|
|
print_output "[-] No firmware emulation ${ORANGE}${ARCH}${NC} / ${ORANGE}${lIMAGE_NAME}${NC} possible"
|
|
fi
|
|
}
|
|
|
|
run_qemu_final_emulation() {
|
|
local lCONSOLE="${1:-}"
|
|
local lCPU="${2:-}"
|
|
local lKERNEL="${3:-}"
|
|
local lQEMU_BIN="${4:-}"
|
|
local lQEMU_MACHINE="${5:-}"
|
|
local lQEMU_DISK="${6:-}"
|
|
local lQEMU_PARAMS="${7:-}"
|
|
local lQEMU_NETWORK="${8:-}"
|
|
local lQEMU_ROOTFS="${9:-}"
|
|
local lIP_ADDRESS="${10:-}"
|
|
local lIMAGE_NAME="${11:-}"
|
|
local lINIT_FILE="${12:-}"
|
|
local lARCH_END="${13:-}"
|
|
|
|
check_qemu_instance_l10
|
|
|
|
print_output "[*] Qemu parameters used in run mode:"
|
|
print_output "$(indent "MACHINE: ${ORANGE}${lQEMU_MACHINE}${NC}")"
|
|
print_output "$(indent "KERNEL: ${ORANGE}${lKERNEL}${NC}")"
|
|
print_output "$(indent "DISK: ${ORANGE}${lQEMU_DISK}${NC}")"
|
|
print_output "$(indent "KINIT: ${ORANGE}${KINIT}${NC}")"
|
|
print_output "$(indent "ROOT_DEV: ${ORANGE}${lQEMU_ROOTFS}${NC}")"
|
|
print_output "$(indent "QEMU: ${ORANGE}${lQEMU_BIN}${NC}")"
|
|
print_output "$(indent "NETWORK: ${ORANGE}${lQEMU_NETWORK}${NC}")"
|
|
print_output "$(indent "Init file: ${ORANGE}${lINIT_FILE}${NC}")"
|
|
print_output "$(indent "Console interface: ${ORANGE}${lCONSOLE}${NC}")"
|
|
print_ln
|
|
print_output "[*] Starting firmware emulation ${ORANGE}${lQEMU_BIN} / ${lARCH_END} / ${lIMAGE_NAME} / ${lIP_ADDRESS}${NC} ... use Ctrl-a + x to exit"
|
|
print_ln
|
|
|
|
write_script_exec "echo -e \"[*] Starting firmware emulation ${ORANGE}${lQEMU_BIN} / ${lARCH_END} / ${lIMAGE_NAME} / ${lIP_ADDRESS}${NC} ... use Ctrl-a + x to exit\n\"" "${ARCHIVE_PATH}"/run.sh 0
|
|
write_script_exec "echo -e \"[*] For emulation state please monitor the ${ORANGE}qemu.serial.log${NC} file\n\"" "${ARCHIVE_PATH}"/run.sh 0
|
|
write_script_exec "echo -e \"[*] For shell access check localhost port ${ORANGE}4321${NC} via telnet\n\"" "${ARCHIVE_PATH}"/run.sh 0
|
|
|
|
date +%s >"${TMP_DIR}/emu_starter.log"
|
|
write_script_exec "timeout --preserve-status --signal SIGINT 2000 ${lQEMU_BIN} -m 2048 -M ${lQEMU_MACHINE} ${lCPU} -kernel ${lKERNEL} ${lQEMU_DISK} -append \"root=${lQEMU_ROOTFS} console=${lCONSOLE} nandsim.parts=64,64,64,64,64,64,64,64,64,64 ${KINIT} rw debug ignore_loglevel print-fatal-signals=1 EMBA_NET=${EMBA_NET} EMBA_NVRAM=${EMBA_NVRAM} EMBA_KERNEL=${EMBA_KERNEL} EMBA_ETC=${EMBA_ETC} user_debug=0 firmadyne.syscall=1\" -nographic ${lQEMU_NETWORK} ${lQEMU_PARAMS} -serial file:${LOG_PATH_MODULE}/qemu.final.serial.log -serial telnet:localhost:4321,server,nowait -serial unix:/tmp/qemu.${lIMAGE_NAME}.S1,server,nowait -monitor unix:/tmp/qemu.${lIMAGE_NAME},server,nowait ; pkill -9 -f tail.*-F.*\"${LOG_PATH_MODULE}\"" "${ARCHIVE_PATH}"/run.sh 1
|
|
}
|
|
|
|
get_emu_runtime() {
|
|
local lEMU_START_DATE=""
|
|
local lCURRENT_DATE=""
|
|
local lRUN_TIME=""
|
|
|
|
if [[ -f "${TMP_DIR}/emu_starter.log" ]]; then
|
|
lEMU_START_DATE=$(cat "${TMP_DIR}/emu_starter.log")
|
|
lCURRENT_DATE="$(date +%s)"
|
|
lRUN_TIME=$((lCURRENT_DATE - lEMU_START_DATE))
|
|
else
|
|
lRUN_TIME="NA"
|
|
fi
|
|
echo "${lRUN_TIME}"
|
|
}
|
|
|
|
check_online_stat() {
|
|
local lIPS_INT_VLAN_CFG="${1:-}"
|
|
local lIMAGE_NAME="${3:-}"
|
|
|
|
local lIP_ADDRESS=""
|
|
lIP_ADDRESS="$(cut -d\; -f2 <<<"${lIPS_INT_VLAN_CFG}")" # field 2
|
|
|
|
local lNMAP_LOG="nmap_emba_${lIPS_INT_VLAN_CFG//\;/-}.txt"
|
|
|
|
local lPING_CNT=0
|
|
local lSYS_ONLINE=0
|
|
local lTCP_SERV_NETSTAT_ARR=()
|
|
local lUDP_SERV_NETSTAT_ARR=()
|
|
local lNMAP_SERV_UDP_ARR=()
|
|
local lNMAP_SERV_TCP_ARR=()
|
|
|
|
# wait 20 secs after boot before starting pinging
|
|
sleep 20
|
|
|
|
# lMAX_PING_CNT is a backup to get out in case something goes weird
|
|
local lMAX_PING_CNT=240
|
|
local lMAX_RUN_TIME=900
|
|
local lRUN_TIME=""
|
|
lRUN_TIME=$(get_emu_runtime)
|
|
# we write the results to a tmp file. This is needed to only have the results of the current emulation round
|
|
# for further processing available
|
|
# we try pinging the system for 10mins with 5 secs sleeptime in between
|
|
# if the system is reachable we go ahead
|
|
while [[ "${lRUN_TIME}" -lt "${lMAX_RUN_TIME}" && "${lSYS_ONLINE}" -eq 0 ]]; do
|
|
# lets use the default ping command first
|
|
if ping -c 1 "${lIP_ADDRESS}" &>/dev/null; then
|
|
print_output "[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable via ICMP."
|
|
ping -c 1 "${lIP_ADDRESS}" | tee -a "${LOG_FILE}" || true
|
|
print_ln
|
|
write_log "${GREEN}[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable via ICMP." "${TMP_DIR}"/online_stats.tmp
|
|
lSYS_ONLINE=1
|
|
fi
|
|
|
|
# we check for alternative ip addresses found in our Qemu logs
|
|
# Usually these are extracted from the output of ifconfig in qemu logs
|
|
# we check for these ip addresses via ping/hping and if such an IP address is working
|
|
# we can use this address for further analysis
|
|
if [[ "${lSYS_ONLINE}" -ne 1 ]]; then
|
|
local lIP_ADDRESS_TMP_ARR=()
|
|
mapfile -t lIP_ADDRESS_TMP_ARR < <(grep -a -o -E "inet addr:[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" "${LOG_PATH_MODULE}/qemu.final.serial.log" |
|
|
grep -v "127.0.0." | grep -v "${lIP_ADDRESS}" | cut -d ':' -f2 | sort -u || true)
|
|
for lIP_ADDRESS_TMP in "${lIP_ADDRESS_TMP_ARR[@]}"; do
|
|
if [[ "${lIP_ADDRESS_TMP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
print_output "[*] Testing for changed IP address ${lIP_ADDRESS_TMP}" "no_log"
|
|
if ping -c 1 "${lIP_ADDRESS_TMP}" &>/dev/null; then
|
|
print_output "[+] Host with changed ip address ${ORANGE}${lIP_ADDRESS_TMP}${GREEN} is reachable via ICMP."
|
|
print_output "[*] Changing testing ip address to ${ORANGE}${lIP_ADDRESS_TMP}${NC}."
|
|
ping -c 1 "${lIP_ADDRESS_TMP}" | tee -a "${LOG_FILE}" || true
|
|
print_ln
|
|
write_log "${GREEN}[+] Host with changed ip address ${ORANGE}${lIP_ADDRESS_TMP}${GREEN} is reachable via ICMP." "${TMP_DIR}"/online_stats.tmp
|
|
lSYS_ONLINE=1
|
|
lIP_ADDRESS="${lIP_ADDRESS_TMP}"
|
|
# let us store the information of a changed ip address for later
|
|
write_log "${lIP_ADDRESS}" "${TMP_DIR}/emulation_changed_ip_address.tmp"
|
|
break
|
|
fi
|
|
if [[ "$(hping3 -n -c 1 "${lIP_ADDRESS_TMP}" 2>/dev/null | grep -c "^len=")" -gt 0 ]]; then
|
|
print_output "[+] Host with changed ip address ${ORANGE}${lIP_ADDRESS_TMP}${GREEN} is reachable via hping."
|
|
print_output "[!] NOT further handled"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# and as second check we can use hping
|
|
if [[ "$(hping3 -n -c 1 "${lIP_ADDRESS}" 2>/dev/null | grep -c "^len=")" -gt 0 ]]; then
|
|
print_output "[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable on TCP port 0 via hping."
|
|
hping3 -n -c 1 "${lIP_ADDRESS}" | tee -a "${LOG_FILE}" || true
|
|
print_ln
|
|
if [[ "${lSYS_ONLINE}" -ne 1 ]]; then
|
|
if ping -c 1 "${lIP_ADDRESS}" &>/dev/null; then
|
|
print_output "[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable via ICMP."
|
|
ping -c 1 "${lIP_ADDRESS}" | tee -a "${LOG_FILE}" || true
|
|
print_ln
|
|
write_log "${GREEN}[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable via ICMP." "${TMP_DIR}"/online_stats.tmp
|
|
fi
|
|
fi
|
|
print_ln
|
|
write_log "${GREEN}[+] Host with ${ORANGE}${lIP_ADDRESS}${GREEN} is reachable on TCP port 0 via hping." "${TMP_DIR}"/online_stats.tmp
|
|
lSYS_ONLINE=1
|
|
fi
|
|
|
|
lPING_CNT=$((lPING_CNT + 1))
|
|
if [[ "${lSYS_ONLINE}" -eq 0 ]]; then
|
|
print_output "[*] Host with ${ORANGE}${lIP_ADDRESS}${NC} is not reachable for ${lPING_CNT} time(s) - runtime $(date -ud@"${lRUN_TIME}" +%H:%M:%S)." "no_log"
|
|
lSYS_ONLINE=0
|
|
sleep 5
|
|
fi
|
|
if [[ "${lPING_CNT}" -gt "${lMAX_PING_CNT}" ]]; then
|
|
print_output "[!] Max ping count reached after runtime $(date -ud@"${lRUN_TIME}" +%H:%M:%S) - proceeding now"
|
|
break
|
|
fi
|
|
lRUN_TIME=$(get_emu_runtime)
|
|
done
|
|
|
|
# looks as we can ping the system. Now, we wait some time before doing our Nmap portscan
|
|
if [[ "${lSYS_ONLINE}" -ne 1 ]]; then
|
|
print_output "[*] Host with ${ORANGE}${lIP_ADDRESS}${NC} is not reachable."
|
|
else
|
|
print_output "[*] Give the system another 30 seconds to ensure the boot process is finished.\n" "no_log"
|
|
sleep 30
|
|
print_output "[*] Default Nmap portscan for ${ORANGE}${lIP_ADDRESS}${NC}"
|
|
# write_link "${ARCHIVE_PATH}"/"${lNMAP_LOG}"
|
|
print_ln
|
|
|
|
# this is just for the logfile
|
|
if ! ping -c 1 "${lIP_ADDRESS}" | tee -a "${LOG_FILE}"; then
|
|
print_output "[-] Warning: System was already available but it does not respond to ping anymore."
|
|
print_output "[-] Probably the IP address of the system has changed."
|
|
local lIP_ADDRESS_TMP_ARR=()
|
|
mapfile -t lIP_ADDRESS_TMP_ARR < <(grep -a -o -E "inet addr:[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" "${LOG_PATH_MODULE}/qemu.final.serial.log" |
|
|
grep -v "127.0.0." | grep -v "${lIP_ADDRESS}" | cut -d ':' -f2 | sort -u || true)
|
|
for lIP_ADDRESS_TMP in "${lIP_ADDRESS_TMP_ARR[@]}"; do
|
|
if [[ "${lIP_ADDRESS_TMP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
print_output "[*] Testing for changed IP address ${lIP_ADDRESS_TMP}"
|
|
if ping -c 1 "${lIP_ADDRESS_TMP}" &>/dev/null; then
|
|
print_output "[*] System available via changed IP address ${lIP_ADDRESS_TMP}"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
|
|
print_ln
|
|
local lCNT=1
|
|
local lMAX_NMAP_RETRIES=15
|
|
nmap -Pn -n -A -sSV --host-timeout 10m -oA "${ARCHIVE_PATH}/${lCNT}_$(basename "${lNMAP_LOG}")" "${lIP_ADDRESS}" | tee -a "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" || true
|
|
# lets also so a quick udp scan on common ports
|
|
nmap -Pn -n -sUV -p 111,123,137,161,1434 --host-timeout 10m -oA "${ARCHIVE_PATH}/${lCNT}_$(basename "${lNMAP_LOG}")_udp" "${lIP_ADDRESS}" | tee -a "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" || true
|
|
if grep -q "open" "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"; then
|
|
tee -a "${LOG_FILE}" <"${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"
|
|
fi
|
|
|
|
lMAX_NMAP_RETRIES=40
|
|
lRUN_TIME=$(get_emu_runtime)
|
|
# at the end we are primarly interested in TCP based network services. This means we stop after reaching
|
|
# our MIN_TCP_SERV threshold
|
|
while [[ "$(grep -c "\/tcp.*open\ " "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}")" -lt "${MIN_TCP_SERV}" ]]; do
|
|
# just to ensure we also detect udp services we can check them here and print a nice message that we have something:
|
|
if [[ "$(grep -c "udp.*open\ \|/tcp.*open\ " "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}")" -gt 0 ]]; then
|
|
print_ln
|
|
print_output "[+] Already detected running network services via Nmap ... further detection active - CNT: ${lCNT}"
|
|
# grep -c "/udp.*open\ \|/tcp.*open\ " "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" >> "${LOG_FILE}"
|
|
write_link "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"
|
|
print_ln
|
|
fi
|
|
lCNT=$((lCNT + 1))
|
|
print_output "[*] Give the system another 60 seconds to ensure the boot process is finished - ${lCNT}/${lMAX_NMAP_RETRIES}.\n" "no_log"
|
|
sleep 60
|
|
# we store our Nmap logs in dedicated files (${lCNT}_nmap_log_file):
|
|
nmap -Pn -n -A -sSV --host-timeout 10m -oA "${ARCHIVE_PATH}/${lCNT}_$(basename "${lNMAP_LOG}")" "${lIP_ADDRESS}" | tee -a "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" || true
|
|
# lets also so a quick udp scan on common ports
|
|
nmap -Pn -n -sUV -p 111,123,137,161,1434 --host-timeout 10m -oA "${ARCHIVE_PATH}/${lCNT}_$(basename "${lNMAP_LOG}")_udp" "${lIP_ADDRESS}" | tee -a "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" || true
|
|
# ensure we have the last results also in our main Nmap log file:
|
|
# cp "${ARCHIVE_PATH}"/"${lCNT}_${lNMAP_LOG}" "${ARCHIVE_PATH}"/"${lNMAP_LOG}"
|
|
if grep -q "/open\ " "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"; then
|
|
tee -a "${LOG_FILE}" <"${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}"
|
|
fi
|
|
# lMAX_NMAP_RETRIES is as backup to exit somehow from this loop
|
|
[[ "${lCNT}" -ge "${lMAX_NMAP_RETRIES}" ]] && break
|
|
|
|
# runtime checks is the prefered way to exit now
|
|
lRUN_TIME=$(get_emu_runtime)
|
|
if [[ "${lRUN_TIME}" -gt "${lMAX_RUN_TIME}" ]]; then
|
|
break
|
|
fi
|
|
done
|
|
# get a backup of our current results and add the later nmap scans to this file for the web report
|
|
cp "${ARCHIVE_PATH}/${lCNT}_${lNMAP_LOG}" "${ARCHIVE_PATH}/${lNMAP_LOG}"
|
|
|
|
mapfile -t lTCP_SERV_NETSTAT_ARR < <(grep -a "^tcp.*LISTEN" "${LOG_PATH_MODULE}"/qemu*.log | grep -v "127.0.0.1" | awk '{print $4}' | rev | cut -d: -f1 | rev | sort -u || true)
|
|
mapfile -t lUDP_SERV_NETSTAT_ARR < <(grep -a "^udp.*" "${LOG_PATH_MODULE}"/qemu*.log | grep -v "127.0.0.1" | awk '{print $4}' | rev | cut -d: -f1 | rev | sort -u || true)
|
|
# check the already created nmap log for open services to include these services in the final scan
|
|
mapfile -t lNMAP_SERV_TCP_ARR < <(grep -o -E "[0-9]+/open/tcp" "${ARCHIVE_PATH}/${lNMAP_LOG}" | cut -d '/' -f1 | sort -u || true)
|
|
mapfile -t lNMAP_SERV_UDP_ARR < <(grep -o -E "[0-9]+/open/udp" "${ARCHIVE_PATH}/${lNMAP_LOG}" | cut -d '/' -f1 | sort -u || true)
|
|
|
|
if [[ "${#SERVICES_STARTUP[@]}" -gt 0 ]] || [[ "${#lTCP_SERV_NETSTAT_ARR[@]}" -gt 0 ]] ||
|
|
[[ "${#lUDP_SERV_NETSTAT_ARR[@]}" -gt 0 ]] || [[ "${#lNMAP_SERV_TCP_ARR[@]}" -gt 0 ]] ||
|
|
[[ "${#lNMAP_SERV_UDP_ARR[@]}" -gt 0 ]]; then
|
|
local lUDP_SERV_NETSTAT=""
|
|
local lUDP_SERV_STARTUP=""
|
|
local lUDP_SERV=""
|
|
local lTCP_SERV_NETSTAT=""
|
|
local lTCP_SERV_STARTUP=""
|
|
local lTCP_SERV=""
|
|
local lTCP_SERV_ARR=()
|
|
local lUDP_SERV_ARR=()
|
|
local lPORTS_TO_SCAN=""
|
|
|
|
# write all services into a one liner for output:
|
|
print_ln
|
|
shopt -s extglob
|
|
# rewrite our array into a nice string for printing it
|
|
if [[ "${#TCP_SERVICES_STARTUP[@]}" -gt 0 ]]; then
|
|
printf -v lTCP_SERV "%s " "${TCP_SERVICES_STARTUP[@]}"
|
|
# # replace \n and ' ' with ,
|
|
lTCP_SERV_STARTUP=${lTCP_SERV//+([$'\n'\ ])/,}
|
|
[[ "${lTCP_SERV_STARTUP}" != "," ]] && print_output "[*] TCP Services detected via startup: ${ORANGE}${lTCP_SERV_STARTUP}${NC}"
|
|
fi
|
|
# rewrite our array into a nice string for printing it
|
|
if [[ "${#UDP_SERVICES_STARTUP[@]}" -gt 0 ]]; then
|
|
printf -v lUDP_SERV "%s " "${UDP_SERVICES_STARTUP[@]}"
|
|
lUDP_SERV_STARTUP=${lUDP_SERV//+([$'\n'\ ])/,}
|
|
[[ "${lUDP_SERV_STARTUP}" != "," ]] && print_output "[*] UDP Services detected via startup: ${ORANGE}${lUDP_SERV_STARTUP}${NC}"
|
|
fi
|
|
|
|
# rewrite our array into a nice string for printing it
|
|
if [[ "${#lTCP_SERV_NETSTAT_ARR[@]}" -gt 0 ]]; then
|
|
printf -v lTCP_SERV "%s " "${lTCP_SERV_NETSTAT_ARR[@]}"
|
|
lTCP_SERV_NETSTAT=${lTCP_SERV//+([$'\n'\ ])/,}
|
|
[[ "${lTCP_SERV_NETSTAT}" != "," ]] && print_output "[*] TCP Services detected via netstat: ${ORANGE}${lTCP_SERV_NETSTAT}${NC}"
|
|
fi
|
|
# rewrite our array into a nice string for printing it
|
|
if [[ "${#lUDP_SERV_NETSTAT_ARR[@]}" -gt 0 ]]; then
|
|
printf -v lUDP_SERV "%s " "${lUDP_SERV_NETSTAT_ARR[@]}"
|
|
lUDP_SERV_NETSTAT=${lUDP_SERV//+([$'\n'\ ])/,}
|
|
[[ "${lUDP_SERV_NETSTAT}" != "," ]] && print_output "[*] UDP Services detected via netstat: ${ORANGE}${lUDP_SERV_NETSTAT}${NC}"
|
|
fi
|
|
if [[ "${#lNMAP_SERV_TCP_ARR[@]}" -gt 0 ]]; then
|
|
printf -v lTCP_SERV "%s " "${lNMAP_SERV_TCP_ARR[@]}"
|
|
lTCP_SERV_NMAP=${lTCP_SERV//+([$'\n'\ ])/,}
|
|
[[ "${lTCP_SERV_NMAP}" != "," ]] && print_output "[*] TCP Services detected via Nmap: ${ORANGE}${lTCP_SERV_NMAP}${NC}"
|
|
fi
|
|
if [[ "${#lNMAP_SERV_UDP_ARR[@]}" -gt 0 ]]; then
|
|
printf -v lUDP_SERV "%s " "${lNMAP_SERV_UDP_ARR[@]}"
|
|
lUDP_SERV_NMAP=${lUDP_SERV//+([$'\n'\ ])/,}
|
|
[[ "${lUDP_SERV_NMAP}" != "," ]] && print_output "[*] UDP Services detected via Nmap: ${ORANGE}${lUDP_SERV_NMAP}${NC}"
|
|
fi
|
|
|
|
print_ln
|
|
|
|
# work with this:
|
|
lUDP_SERV_ARR=("${UDP_SERVICES_STARTUP[@]}" "${lUDP_SERV_NETSTAT_ARR[@]}" "${#lNMAP_SERV_UDP_ARR[@]}")
|
|
lTCP_SERV_ARR=("${TCP_SERVICES_STARTUP[@]}" "${lTCP_SERV_NETSTAT_ARR[@]}" "${#lNMAP_SERV_TCP_ARR[@]}")
|
|
# we add some default services that we always check in our final Nmap scan
|
|
lTCP_SERV_ARR+=(21)
|
|
lTCP_SERV_ARR+=(22)
|
|
lTCP_SERV_ARR+=(80)
|
|
lTCP_SERV_ARR+=(443)
|
|
lTCP_SERV_ARR+=(8080)
|
|
|
|
mapfile -t lTCP_SERV_ARR < <(printf "%s\n" "${lTCP_SERV_ARR[@]}" | sort -u)
|
|
mapfile -t lUDP_SERV_ARR < <(printf "%s\n" "${lUDP_SERV_ARR[@]}" | sort -u)
|
|
if [[ "${#lTCP_SERV_ARR[@]}" -gt 0 ]]; then
|
|
printf -v lTCP_SERV "%s " "${lTCP_SERV_ARR[@]}"
|
|
lTCP_SERV="${lTCP_SERV//+([$'\n'\ ])/,}"
|
|
# print_output "[*] TCP Services detected: ${ORANGE}${lTCP_SERV}${NC}"
|
|
fi
|
|
if [[ "${#lUDP_SERV_ARR[@]}" -gt 0 ]]; then
|
|
printf -v lUDP_SERV "%s " "${lUDP_SERV_ARR[@]}"
|
|
lUDP_SERV="${lUDP_SERV//+([$'\n'\ ])/,}"
|
|
# print_output "[*] UDP Services detected: ${ORANGE}${lUDP_SERV}${NC}"
|
|
fi
|
|
|
|
lUDP_SERV="U:${lUDP_SERV#,}"
|
|
lTCP_SERV="T:${lTCP_SERV#,}"
|
|
# remove the last ',' ... 123,234,345, -> 123,234,345
|
|
lTCP_SERV="${lTCP_SERV%,}"
|
|
lUDP_SERV="${lUDP_SERV%,}"
|
|
shopt -u extglob
|
|
|
|
if [[ "${lTCP_SERV}" =~ ^T:[0-9].* ]]; then
|
|
print_output "[*] Checking TCP services ${ORANGE}${lTCP_SERV}${NC}"
|
|
lPORTS_TO_SCAN="${lTCP_SERV}"
|
|
fi
|
|
if [[ "${lUDP_SERV}" =~ ^U:[0-9].* ]]; then
|
|
print_output "[*] Checking UDP services ${ORANGE}${lUDP_SERV}${NC}"
|
|
if [[ "${lPORTS_TO_SCAN}" =~ ^T:[0-9].* ]]; then
|
|
lPORTS_TO_SCAN+=",${lUDP_SERV}"
|
|
else
|
|
lPORTS_TO_SCAN="${lUDP_SERV}"
|
|
fi
|
|
fi
|
|
|
|
if [[ "${lTCP_SERV}" =~ ^T:[0-9].* ]] || [[ "${lUDP_SERV}" =~ ^U:[0-9].* ]]; then
|
|
print_ln
|
|
print_output "[*] Nmap portscan for network services (${ORANGE}${lPORTS_TO_SCAN}${NC}) started during system init on ${ORANGE}${lIP_ADDRESS}${NC}"
|
|
# link is for the next Nmap results:
|
|
write_link "${ARCHIVE_PATH}/${lNMAP_LOG}"
|
|
print_ln
|
|
nmap -Pn -n -sSUV --host-timeout 30m -p "${lPORTS_TO_SCAN}" -oA "${ARCHIVE_PATH}/nmap_emba_${lIPS_INT_VLAN_CFG//\;/-}"_dedicated "${lIP_ADDRESS}" | tee -a "${ARCHIVE_PATH}/${lNMAP_LOG}" "${LOG_FILE}" || true
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
stopping_emulation_process "${lIMAGE_NAME}"
|
|
cleanup_emulator "${lIMAGE_NAME}"
|
|
|
|
color_qemu_log "${LOG_PATH_MODULE}/qemu.final.serial.log"
|
|
|
|
pkill -9 -f "tail -F ${LOG_PATH_MODULE}/qemu.final.serial.log" || true &>/dev/null
|
|
}
|
|
|
|
stopping_emulation_process() {
|
|
local lIMAGE_NAME="${1:-}"
|
|
|
|
print_output "[*] Stopping emulation process" "no_log"
|
|
pkill -9 -f "qemu-system-.*${lIMAGE_NAME}.*" &>/dev/null || true
|
|
sleep 1
|
|
}
|
|
|
|
create_emulation_archive() {
|
|
sub_module_title "Archive to re-run emulated environment"
|
|
print_output "With the following archive it is possible to rebuild the created emulation environment fully automated."
|
|
|
|
local lKERNEL="${1:-}"
|
|
local lIMAGE="${2:-}"
|
|
local lARCHIVE_PATH="${3:-}"
|
|
local lIPS_INT_VLAN_CFG_mod="${4:-}"
|
|
local lARCH_NAME=""
|
|
local lDEVICE="NA"
|
|
|
|
if [[ "${FINAL_FW_RM}" -ne 1 ]]; then
|
|
# we only copy the kernel and the firmware image to the archive if FINAL_FW_RM is not set
|
|
cp "${lKERNEL}" "${lARCHIVE_PATH}" || print_error "[-] Error in kernel copy procedure"
|
|
|
|
# we need to ensure that the EMBA_config_state file gets removed
|
|
local lCNT=0
|
|
while [[ "${lDEVICE:-NA}" == "NA" ]]; do
|
|
lDEVICE="$(add_partition_emulation "${lIMAGE}")"
|
|
lCNT=$((lCNT + 1))
|
|
if [[ "${lDEVICE:-NA}" == "NA" ]] && [[ "${lCNT}" -gt 10 ]]; then
|
|
print_output "[-] No Qemu Image device identified - return now from ${FUNCNAME[0]}"
|
|
return
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
mount "${lDEVICE}" "${MNT_POINT}" || true
|
|
rm "${MNT_POINT}"/tmp/EMBA_config_state 2>/dev/null || true
|
|
umount_qemu_image "${lDEVICE}"
|
|
delete_device_entry "$(basename "${lIMAGE}")" "${lDEVICE}" "${MNT_POINT}"
|
|
|
|
cp "${lIMAGE}" "${lARCHIVE_PATH}" || print_error "[-] Error in image copy procedure"
|
|
fi
|
|
|
|
if [[ -f "${LOG_PATH_MODULE}"/"${NMAP_LOG}" ]]; then
|
|
mv "${LOG_PATH_MODULE}"/"${NMAP_LOG}" "${lARCHIVE_PATH}" || print_error "[-] Error in Nmap results copy procedure"
|
|
mv "${LOG_PATH_MODULE}"/nmap_emba_"${lIPS_INT_VLAN_CFG_mod}"* "${lARCHIVE_PATH}" || print_error "[-] Error in Nmap results copy procedure"
|
|
fi
|
|
|
|
echo "${lIPS_INT_VLAN_CFG_mod}" >>"${lARCHIVE_PATH}"/emulation_config.txt || true
|
|
cat "${L10_SYS_EMU_RESULTS}" >>"${lARCHIVE_PATH}"/emulation_config.txt || true
|
|
|
|
if [[ -v ARCHIVE_PATH ]] && [[ -f "${lARCHIVE_PATH}"/run.sh ]]; then
|
|
chmod +x "${lARCHIVE_PATH}"/run.sh
|
|
sed -i 's/-serial\ file:.*\/l10_system_emulation\/qemu\.final\.serial\.log/-serial\ file:\.\/qemu\.serial\.log/g' "${lARCHIVE_PATH}"/run.sh
|
|
# fix the path for the kernel which is currently something like ./Linux-Kernel/vmlinux.mipsel.4
|
|
# and should be ./vmlinux.mipsel.4
|
|
local lL10_KERNEL_V_LONG_TMP="${L10_KERNEL_V_LONG}"
|
|
if [[ "${lARCH_END}" == *"x86el"* ]] && [[ "${L10_KERNEL_V_LONG}" == "4.1.52" ]]; then
|
|
# for x86el we currently have kernel issues
|
|
lL10_KERNEL_V_LONG_TMP="4.1.17"
|
|
fi
|
|
sed -i "s/\.\/Linux-Kernel-v${lL10_KERNEL_V_LONG_TMP}\//\.\//g" "${lARCHIVE_PATH}"/run.sh
|
|
|
|
if [[ "${FINAL_FW_RM}" -ne 1 ]]; then
|
|
# create archive
|
|
lARCH_NAME="$(basename "${lARCHIVE_PATH}")".tar.gz
|
|
tar -czvf "${LOG_PATH_MODULE}"/"${lARCH_NAME}" "${lARCHIVE_PATH}"
|
|
if [[ -f "${LOG_PATH_MODULE}"/"${lARCH_NAME}" ]]; then
|
|
print_ln
|
|
print_output "[*] Qemu emulation archive created in log directory: ${ORANGE}${lARCH_NAME}${NC}" "" "${LOG_PATH_MODULE}/${lARCH_NAME}"
|
|
print_ln
|
|
fi
|
|
else
|
|
print_output "[*] NO Qemu emulation archive created - FINAL_FW_RM was set or \'-r\' parameter was used."
|
|
fi
|
|
else
|
|
print_output "[-] No run script created ..."
|
|
fi
|
|
}
|
|
|
|
get_binary() {
|
|
local lBINARY_NAME="${1:-}"
|
|
local lARCH_END="${2:-}"
|
|
local lMUSL_VER="${3:-}"
|
|
|
|
# '${lBINARY_NAME/\.*}' -> strip the .so from libnvram.so and libnvram_ioctl.so
|
|
if [[ "${lBINARY_NAME}" == *"busybox"* ]] && [[ -f "${BINARY_DIR}/${lBINARY_NAME}-v${L10_BB_VER}/${lBINARY_NAME}.${lARCH_END}" ]]; then
|
|
echo "${BINARY_DIR}/${lBINARY_NAME}-v${L10_BB_VER}/${lBINARY_NAME}.${lARCH_END}"
|
|
elif [[ -f "${BINARY_DIR}/${lBINARY_NAME/_dbg*/}/${lBINARY_NAME}.${lARCH_END}_musl_${lMUSL_VER}" ]]; then
|
|
# use sub-directories for the different binaries:
|
|
# will be used in the future
|
|
echo "${BINARY_DIR}/${lBINARY_NAME/_dbg*/}/${lBINARY_NAME}.${lARCH_END}_musl_${lMUSL_VER}"
|
|
elif [[ -f "${BINARY_DIR}/${lBINARY_NAME/_nondbg*/}/${lBINARY_NAME}.${lARCH_END}_musl_${lMUSL_VER}" ]]; then
|
|
# use sub-directories for the different binaries:
|
|
# will be used in the future
|
|
echo "${BINARY_DIR}/${lBINARY_NAME/_nondbg*/}/${lBINARY_NAME}.${lARCH_END}_musl_${lMUSL_VER}"
|
|
elif [[ -f "${BINARY_DIR}/${lBINARY_NAME}/${lBINARY_NAME}.${lARCH_END}" ]]; then
|
|
echo "${BINARY_DIR}/${lBINARY_NAME}/${lBINARY_NAME}.${lARCH_END}"
|
|
else
|
|
echo "NA"
|
|
fi
|
|
}
|
|
|
|
add_partition_emulation() {
|
|
local lIMAGE_PATH=""
|
|
local lDEV_PATH="NA"
|
|
local lFOUND=false
|
|
local lCNT=0
|
|
local lDEV_NR=0
|
|
|
|
while (losetup | grep -q "${1}"); do
|
|
local lLOOP=""
|
|
((lCNT += 1))
|
|
lLOOP=$(losetup -a | grep "${1}" | sort -u)
|
|
# we try to get rid of the entry nicely
|
|
losetup -d "${lLOOP/:*/}"
|
|
if losetup -a | grep -q "${1}"; then
|
|
# and now we go the brutal way
|
|
losetup -D
|
|
dmsetup remove_all -f &>/dev/null || true
|
|
fi
|
|
if [[ "${lCNT}" -gt 10 ]]; then
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
local lCNT=0
|
|
while (! losetup -Pf "${1}"); do
|
|
((lCNT += 1))
|
|
if [[ "${lCNT}" -gt 10 ]]; then
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
local lCNT=0
|
|
while (! "${lFOUND}"); do
|
|
sleep 1
|
|
((lCNT += 1))
|
|
local lLOSETUP_OUT_ARR=()
|
|
mapfile -t lLOSETUP_OUT_ARR < <(losetup | grep -v "BACK-FILE" || true)
|
|
local lLINE=""
|
|
for lLINE in "${lLOSETUP_OUT_ARR[@]}"; do
|
|
lIMAGE_PATH=$(awk '{print $6}' <<<"${lLINE}") # field 6
|
|
if [[ "${lIMAGE_PATH}" == "${1}" ]]; then
|
|
lDEV_PATH=$(awk '{print $1}' <<<"${lLINE}") # field 1
|
|
if [[ "$(dirname "${lDEV_PATH}")" == "/dev/loop" ]]; then
|
|
# if we have the new naming like /dev/loop/0 -> dirname results in /dev/loop
|
|
lDEV_NR="${lDEV_PATH##*/}" # basename
|
|
lDEV_PATH="/dev/loop${lDEV_NR}p1"
|
|
else
|
|
# old naming like /dev/loop0 -> dirname results in /dev/
|
|
lDEV_PATH=$(awk '{print $1}' <<<"${lLINE}")p1 # field 1
|
|
fi
|
|
if [[ -b "${lDEV_PATH}" ]]; then
|
|
lFOUND=true
|
|
fi
|
|
fi
|
|
done
|
|
if [[ "${lCNT}" -gt 600 ]]; then
|
|
# get an exit if nothing happens
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ "${lDEV_PATH}" != "NA" ]]; then
|
|
local lCNT=0
|
|
while (! find "${lDEV_PATH}" -ls 2>/dev/null | grep -q "disk"); do
|
|
sleep 1
|
|
((lCNT += 1))
|
|
if [[ "${lCNT}" -gt 600 ]]; then
|
|
# get an exit if nothing happens
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
echo "${lDEV_PATH}"
|
|
}
|
|
|
|
get_kernel_version() {
|
|
local lKV=""
|
|
local lKERNELV_ARR=()
|
|
|
|
if [[ -f "${S25_LOG}" ]]; then
|
|
mapfile -t lKERNELV_ARR < <(grep "Statistics:" "${S25_LOG}" | cut -d: -f2 | sort -u || true)
|
|
if [[ -v lKERNELV_ARR[@] ]]; then
|
|
# if we have found a kernel it is a Linux system:$
|
|
for lKV in "${lKERNELV_ARR[@]}"; do
|
|
if [[ "${lKV}" == "2"* ]]; then
|
|
KERNEL_V=2
|
|
break
|
|
elif [[ "${lKV}" == "4"* ]]; then
|
|
KERNEL_V=4
|
|
break
|
|
else
|
|
# just to have some fallback solution
|
|
KERNEL_V=4
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
else
|
|
# just to have some fallback solution
|
|
KERNEL_V=4
|
|
fi
|
|
}
|
|
|
|
set_network_config() {
|
|
local lIP_ADDRESS="${1:-192.168.0.1}"
|
|
local lNETWORK_MODE="${2:-bridge}"
|
|
local lNETWORK_DEVICE="${3:-br0}"
|
|
local lETH_INT="${4:-eth0}"
|
|
|
|
echo "${lNETWORK_MODE}" >"${MNT_POINT}/firmadyne/network_type"
|
|
echo "${lNETWORK_DEVICE}" >"${MNT_POINT}/firmadyne/net_bridge"
|
|
echo "${lETH_INT}" >"${MNT_POINT}/firmadyne/net_interface"
|
|
if [[ -z "${lIP_ADDRESS}" ]]; then
|
|
lIP_ADDRESS="192.168.0.1"
|
|
fi
|
|
echo "${lIP_ADDRESS}" >"${MNT_POINT}/firmadyne/ip_default"
|
|
}
|
|
|
|
write_results() {
|
|
if [[ "${IN_DOCKER}" -eq 1 ]] && [[ -f "${BASIC_DATA_LOG_DIR}"/fw_name.log ]]; then
|
|
local lFIRMWARE_PATH_orig=""
|
|
lFIRMWARE_PATH_orig="$(cat "${BASIC_DATA_LOG_DIR}"/fw_name.log)"
|
|
fi
|
|
|
|
local lARCHIVE_PATH="${1:-}"
|
|
local lR_PATH="${2:-}"
|
|
local lRESULT_SOURCE="${3:-}"
|
|
local lNETWORK_MODE="${4:-}"
|
|
local lETH_INT="${5:-}"
|
|
local lVLAN_ID="${6:-}"
|
|
local lINIT_FILE="${7:-}"
|
|
local lNETWORK_DEVICE="${8:-}"
|
|
|
|
local lR_PATH_mod=""
|
|
lR_PATH_mod="${lR_PATH/${LOG_DIR}/}"
|
|
local lTCP_SERV_CNT=0
|
|
local lSERVICES=""
|
|
|
|
lTCP_SERV_CNT="$(grep -h "udp.*open\ \|tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | wc -l || true)"
|
|
# to get an overview of which services are available
|
|
lSERVICES="$(grep -h "\/udp.*open\ \|\/tcp.*open\ " "${ARCHIVE_PATH}"/*"${NMAP_LOG}" 2>/dev/null | awk '{print $1}' | sort -u | tr '\n' ',' || true)"
|
|
|
|
[[ "${lTCP_SERV_CNT}" -gt 0 ]] && TCP="ok"
|
|
lARCHIVE_PATH="${lARCHIVE_PATH##*/}" # basename
|
|
if ! [[ -f "${L10_SYS_EMU_RESULTS}" ]]; then
|
|
write_log "FIRMWARE_PATH;RESULT_SOURCE;Booted state;ICMP state;TCP-0 state;TCP state;online services cnt;available network services;IP address;Network mode (NETWORK_DEVICE|ETH_INT|VLAN_ID|INIT_FILE|INIT_MECHANISM);ARCHIVE_PATH_;R_PATH" "${L10_SYS_EMU_RESULTS}"
|
|
fi
|
|
write_log "${lFIRMWARE_PATH_orig:-NA};${lRESULT_SOURCE};Booted ${BOOTED};ICMP ${ICMP};TCP-0 ${TCP_0};TCP ${TCP};${lTCP_SERV_CNT};${lSERVICES%,};IP address: ${IP_ADDRESS_};Network mode: ${lNETWORK_MODE} (${lNETWORK_DEVICE}|${lETH_INT}|${lVLAN_ID}|${lINIT_FILE}|${KINIT/=*/});${lARCHIVE_PATH};${lR_PATH_mod}" "${L10_SYS_EMU_RESULTS}"
|
|
print_bar ""
|
|
}
|
|
|
|
set_firmae_arbitration() {
|
|
local lFIRMAE_STATE="${1:-true}"
|
|
# FirmAE arbitration - enable all mechanisms
|
|
export EMBA_BOOT="${lFIRMAE_STATE}"
|
|
export EMBA_NET="${lFIRMAE_STATE}"
|
|
export EMBA_NVRAM="${lFIRMAE_STATE}"
|
|
export EMBA_KERNEL="${lFIRMAE_STATE}"
|
|
export EMBA_ETC="${lFIRMAE_STATE}"
|
|
}
|
|
|
|
color_qemu_log() {
|
|
local lQEMU_LOG_FILE="${1:-}"
|
|
if ! [[ -f "${lQEMU_LOG_FILE:-}" ]]; then
|
|
return
|
|
fi
|
|
|
|
# GREEN: keywords for network identification:
|
|
sed -i -r "s/.*br_add_if.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*br_dev_ioctl.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*__inet_insert_ifa.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*ioctl_SIOCSIFHWADDR.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*register_vlan_dev.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*\[NVRAM\]\ .*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*inet_bind.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*adding VLAN [0-9] to HW filter on device eth[0-9].*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
|
|
# Green: other interesting areas:
|
|
sed -i -r "s/.*Kernel\ command\ line:\ .*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*Starting\ services\ in\ emulated\ environment.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*Network configuration - ACTION.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*starting\ network\ configuration.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*Current\ network\ configuration.*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*Netstat\ output\ .*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
sed -i -r "s/.*Starting\ .*\ service\ .*/\x1b[32m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
|
|
# RED:
|
|
sed -i -r "s/.*Kernel\ panic\ -\ .*/\x1b[31m&\x1b[0m/" "${lQEMU_LOG_FILE}"
|
|
}
|