Repository navigation
Expand file tree
/
Copy pathS27_perl_check.sh
More file actions
executable file
·175 lines (153 loc) · 7.79 KB
/
Copy pathS27_perl_check.sh
File metadata and controls
executable file
·175 lines (153 loc) · 7.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/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
}