mirror of
https://github.com/e-m-b-a/emba.git
synced 2026-10-12 02:13:21 +00:00
176 lines
7.8 KiB
Bash
Executable File
176 lines
7.8 KiB
Bash
Executable File
#!/bin/bash -p
|
|
|
|
# EMBA - EMBEDDED LINUX ANALYZER
|
|
#
|
|
# Copyright 2024-2026 Siemens Energy AG
|
|
#
|
|
# EMBA comes with ABSOLUTELY NO WARRANTY. This is free software, and you are
|
|
# welcome to redistribute it under the terms of the GNU General Public License.
|
|
# See LICENSE file for usage of this software.
|
|
#
|
|
# EMBA is licensed under GPLv3
|
|
# SPDX-License-Identifier: GPL-3.0-only
|
|
#
|
|
# Author(s): Michael Messner
|
|
|
|
# Description: Checks for bugs and possible vulnerabilities in perl scripts with zarn - https://github.com/htrgouvea/zarn
|
|
# See also https://heitorgouvea.me/2023/03/19/static-security-analysis-tool-perl
|
|
|
|
S27_perl_check() {
|
|
module_log_init "${FUNCNAME[0]}"
|
|
module_title "Check perl scripts for security issues"
|
|
pre_module_reporter "${FUNCNAME[0]}"
|
|
|
|
local lS27_PL_VULNS=0
|
|
|
|
if ! [[ -f "${EXT_DIR}"/zarn/zarn.pl ]]; then
|
|
print_output "[-] Zarn installation not available - please check your installation/docker image"
|
|
module_end_log "${FUNCNAME[0]}" "${lS27_PL_VULNS}"
|
|
return
|
|
fi
|
|
|
|
local lS27_PL_SCRIPTS=0
|
|
local lPL_SCRIPT=""
|
|
local lPERL_SCRIPTS_ARR=()
|
|
local lNAME=""
|
|
local lWAIT_PIDS_S27=()
|
|
|
|
export PERL5LIB="${EXT_DIR}"/zarn/lib
|
|
|
|
write_csv_log "Script path" "Perl issues detected" "common linux file" "vuln title" "vuln line nr" "vuln note"
|
|
mapfile -t lPERL_SCRIPTS_ARR < <(grep "Perl script.*executable" "${P99_CSV_LOG}" | sort -u || true)
|
|
for lPL_SCRIPT in "${lPERL_SCRIPTS_ARR[@]}"; do
|
|
if [[ -f "${BASE_LINUX_FILES}" && "${FULL_TEST}" -eq 0 ]]; then
|
|
# if we have the base linux config file we only test non known Linux binaries
|
|
# with this we do not waste too much time on open source Linux stuff
|
|
lNAME=$(basename "$(cut -d ';' -f2 <<<"${lPL_SCRIPT}")" 2>/dev/null) # field 2
|
|
if grep -E -q "^${lNAME}$" "${BASE_LINUX_FILES}" 2>/dev/null; then
|
|
continue
|
|
fi
|
|
fi
|
|
((lS27_PL_SCRIPTS += 1))
|
|
s27_zarn_perl_checks "$(cut -d ';' -f2 <<<"${lPL_SCRIPT}")" & # field 2
|
|
local lTMP_PID="$!"
|
|
lWAIT_PIDS_S27+=("${lTMP_PID}")
|
|
max_pids_protection "${MAX_MOD_THREADS}" lWAIT_PIDS_S27
|
|
done
|
|
|
|
wait_for_pid "${lWAIT_PIDS_S27[@]}"
|
|
[[ -d "${TMP_DIR}/s27" ]] && (rm -r "${TMP_DIR}"/s27 || true)
|
|
|
|
if [[ -f "${TMP_DIR}/S27_VULNS.tmp" ]]; then
|
|
lS27_PL_VULNS=$(awk '{sum += $1 } END { print sum }' "${TMP_DIR}"/S27_VULNS.tmp)
|
|
fi
|
|
|
|
write_log ""
|
|
write_log "[*] Statistics:${lS27_PL_VULNS}:${lS27_PL_SCRIPTS}"
|
|
module_end_log "${FUNCNAME[0]}" "${lS27_PL_VULNS}"
|
|
}
|
|
|
|
s27_zarn_perl_checks() {
|
|
local lPL_SCRIPT="${1:-}"
|
|
local lNAME=""
|
|
local lPL_LOG="" # text log with original output from zarn analysis
|
|
local lVULNS=""
|
|
local lGPT_PRIO=2
|
|
local lAI_ANCHOR=""
|
|
local lZARN_SARIF_RESULTS_ARR=()
|
|
local lSARIF_RESULT=""
|
|
local lZARN_VULN_TITLE=""
|
|
local lZARN_VULN_MESSAGE=""
|
|
local lZARN_VULN_LINE=""
|
|
local lCODE_LINE=""
|
|
local lPL_LOG_LINKED="" # 2nd stage log which is linked from the main log
|
|
|
|
local lS27_SOURCE_DIR="${LOG_PATH_MODULE}/pl_sources"
|
|
|
|
lNAME=$(basename "${lPL_SCRIPT}" 2>/dev/null | sed -e 's/:/_/g')
|
|
print_output "[*] Testing perl script ${ORANGE}${lPL_SCRIPT}${NC}" "no_log"
|
|
lPL_LOG="${LOG_PATH_MODULE}/zarn_${lNAME}.txt"
|
|
if [[ "${lPL_SCRIPT: -4}" == ".cgi" ]]; then
|
|
if ! [[ -d "${TMP_DIR}"/s27 ]]; then
|
|
mkdir "${TMP_DIR}"/s27
|
|
fi
|
|
# as zarn does not like cgi's, we need to temp rename these files now
|
|
cp "${lPL_SCRIPT}" "${TMP_DIR}"/s27/"${lNAME/.cgi/.pl}"
|
|
if [[ -f "${TMP_DIR}/s27/${lNAME/.cgi/.pl}" ]]; then
|
|
perl "${EXT_DIR}"/zarn/zarn.pl -r "${EXT_DIR}"/zarn/rules/default.yml --source "${TMP_DIR}/s27/${lNAME/.cgi/.pl}" --sarif "${LOG_PATH_MODULE}/zarn_${lNAME}.sarif" | tee -a "${lPL_LOG}" || print_error "[-] Analysis of ${lNAME} failed"
|
|
rm "${TMP_DIR}/s27/${lNAME/.cgi/.pl}" || true
|
|
fi
|
|
else
|
|
perl "${EXT_DIR}"/zarn/zarn.pl -r "${EXT_DIR}"/zarn/rules/default.yml --source "${lPL_SCRIPT}" --sarif "${LOG_PATH_MODULE}/zarn_${lNAME}.sarif" | tee -a "${lPL_LOG}" || print_error "[-] Analysis of ${lNAME} failed"
|
|
fi
|
|
|
|
## reporting starts here
|
|
lVULNS=$(grep -c "\[vuln\]" "${lPL_LOG}" 2>/dev/null || true)
|
|
if [[ "${lVULNS}" -gt 0 ]]; then
|
|
[[ ! -d "${lS27_SOURCE_DIR}" ]] && mkdir -p "${lS27_SOURCE_DIR}"
|
|
# check if this is common linux file:
|
|
local lCOMMON_FILES_FOUND=""
|
|
local lCFF=""
|
|
if [[ -f "${BASE_LINUX_FILES}" ]]; then
|
|
lCOMMON_FILES_FOUND="(${RED}common linux file: no${GREEN})"
|
|
lCFF="no"
|
|
if grep -q "^${lNAME}\$" "${BASE_LINUX_FILES}" 2>/dev/null; then
|
|
lCOMMON_FILES_FOUND="(${CYAN}common linux file: yes${GREEN})"
|
|
lCFF="yes"
|
|
fi
|
|
else
|
|
lCOMMON_FILES_FOUND=""
|
|
lCFF="NA"
|
|
fi
|
|
lPL_LOG_LINKED="${LOG_PATH_MODULE}/zarn_${lNAME}_details.txt"
|
|
print_output "[+] Found ${RED}${lVULNS} possible issue(s)${GREEN} in perl script ${lCOMMON_FILES_FOUND}:${ORANGE} $(print_path "${lPL_SCRIPT}")" "" "${lPL_LOG_LINKED}"
|
|
if [[ "${lVULNS}" -gt 20 ]]; then
|
|
lGPT_PRIO=$((lGPT_PRIO + 1))
|
|
fi
|
|
|
|
mapfile -t lZARN_SARIF_RESULTS_ARR < <(jq -rc '.runs[].results[]' "${LOG_PATH_MODULE}/zarn_${lNAME}.sarif")
|
|
|
|
write_log "[+] Found ${ORANGE}${lVULNS} possible issue(s)${GREEN} in perl script ${lCOMMON_FILES_FOUND}:${ORANGE} $(print_path "${lPL_SCRIPT}")" "${lPL_LOG_LINKED}"
|
|
copy_and_link_file "${lPL_SCRIPT}" "${lS27_SOURCE_DIR}/${lNAME}.log" "${lPL_LOG_LINKED}"
|
|
write_log "$(indent "$(orange "$(file "${lPL_SCRIPT}")")")" "${lPL_LOG_LINKED}"
|
|
write_log "\n" "${lPL_LOG_LINKED}"
|
|
|
|
for lSARIF_RESULT in "${lZARN_SARIF_RESULTS_ARR[@]}"; do
|
|
lZARN_VULN_TITLE="$(jq -rc '.properties.title' <<<"${lSARIF_RESULT}" || true)"
|
|
lZARN_VULN_MESSAGE="$(jq -rc '.message.text' <<<"${lSARIF_RESULT}" || true)"
|
|
lZARN_VULN_LINE="$(jq -rc '.locations[].physicalLocation.region.startLine' <<<"${lSARIF_RESULT}" || true)"
|
|
|
|
write_csv_log "$(print_path "${lPL_SCRIPT}")" "${lVULNS}" "${lCFF}" "${lZARN_VULN_TITLE}" "${lZARN_VULN_LINE}" "${lZARN_VULN_MESSAGE}"
|
|
write_log "$(indent "$(indent "Vulnerability title: ${ORANGE}${lZARN_VULN_TITLE}${NC}")")" "${lPL_LOG_LINKED}"
|
|
write_log "$(indent "$(indent "Vulnerability description: ${ORANGE}${lZARN_VULN_MESSAGE}${NC}")")" "${lPL_LOG_LINKED}"
|
|
write_log "" "${lPL_LOG_LINKED}"
|
|
|
|
# we need the original perl script to link to it and to highlight the affected lines of code
|
|
if ! [[ -f "${lS27_SOURCE_DIR}/${lNAME}.log" ]]; then
|
|
cp "${lPL_SCRIPT}" "${lS27_SOURCE_DIR}/${lNAME}.log" || print_error "[-] Copy of ${lPL_SCRIPT} to log directory failed"
|
|
fi
|
|
|
|
lCODE_LINE="$(strip_color_codes "$(sed -n "${lZARN_VULN_LINE}"p "${lS27_SOURCE_DIR}/${lNAME}.log" 2>/dev/null)")"
|
|
sed -i -r "${lZARN_VULN_LINE}s/.*/\x1b[32m&\x1b[0m/" "${lS27_SOURCE_DIR}/${lNAME}.log" || true
|
|
write_log "$(indent "$(indent "${GREEN}${lZARN_VULN_LINE}${NC} - ${ORANGE}${lCODE_LINE}${NC}")")" "${lPL_LOG_LINKED}"
|
|
write_log "\\n-----------------------------------------------------------------\\n" "${lPL_LOG_LINKED}"
|
|
done
|
|
|
|
# writing gpt details:
|
|
if [[ "${AI_OPTION}" -gt 0 ]]; then
|
|
lAI_ANCHOR="$(openssl rand -hex 8)"
|
|
if [[ -f "${BASE_LINUX_FILES}" ]]; then
|
|
# if we have the base linux config file we are checking it:
|
|
if ! grep -E -q "^$(basename "${lPL_SCRIPT}")$" "${BASE_LINUX_FILES}" 2>/dev/null; then
|
|
lGPT_PRIO=$((lGPT_PRIO + 1))
|
|
fi
|
|
fi
|
|
# "${GPT_INPUT_FILE_}" "${GPT_ANCHOR_}" "${GPT_PRIO_}" "${GPT_QUESTION_}" "${GPT_OUTPUT_FILE_}" "cost=$GPT_TOKENS_" "${GPT_RESPONSE_}"
|
|
write_csv_AI_tmp "${lS27_SOURCE_DIR}/${lNAME}.log" "${lAI_ANCHOR}" "${lGPT_PRIO}" "${GPT_QUESTION}" "${lPL_LOG}" "" ""
|
|
# add ChatGPT link to output file
|
|
printf '%s\n\n' "" >>"${lPL_LOG}"
|
|
write_anchor_AI "${lAI_ANCHOR}" "${lPL_LOG}"
|
|
printf '%s\n\n' "" >>"${lS27_SOURCE_DIR}/${lNAME}.log"
|
|
write_anchor_AI "${lAI_ANCHOR}" "${lS27_SOURCE_DIR}/${lNAME}.log"
|
|
fi
|
|
echo "${lVULNS}" >>"${TMP_DIR}"/S27_VULNS.tmp
|
|
fi
|
|
}
|