-
Notifications
You must be signed in to change notification settings - Fork 1
/
honey_harvester_exim_cve-2019-10149.sh
311 lines (247 loc) · 13.3 KB
/
honey_harvester_exim_cve-2019-10149.sh
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
#!/usr/bin/env bash
## Author: Bret.S
## Creation: 06/24/19
## Last Update: 07/6/19
## Built For Debian 9 OS
## Purpose: Parse Exim Logs for CVE-2019-10149 exploit attempts.
## Usage: Run as cron job. Use the install script to properly set up the cronjob. It will, by default, run every 15 minutes.
##
## Notes: Exim must be have the proper config changes made to it config for the scripts to work correctly.
##
##
## Change Log:
## - 6/24/19 - Main code done. Version 1.0 done and working.
## - 7/25/19 - Remove dup emails from send TO and CC Fields.
## - Remove dup IPs from attacker found list.
##
##
## START Declare Variables ##
#
str_this_scripts_name=${0}
#
# This is the email that will appear on abuse reports that are sent. So this need to be a valid email address.
# You may be contracted back by the people who get these reports.
# Example: [email protected]
str_my_abuse_email_address_to_use_in_from_field=''
#
# This email address must be different from the "str_my_abuse_email_address_to_use_in_from_field".
# This email is use to send a copy of a abuse report to you so you are aware that an attack was found.
# Since the "str_my_abuse_email_address_to_use_in_from_field" domain will be local to this honeypot
# system, it will not try to send to a remote. Suggest adding a subdomain.
# Example: [email protected]
str_my_abuse_email_address_to_send_copy_of_abuse_report=''
#
str_exim_log_dir="/var/log/exim4"
str_exim_main_log_file="${str_exim_log_dir}/mainlog"
str_exim_reject_log_file="${str_exim_log_dir}/rejectlog"
str_exploit_attempt_confirmation_string="Restricted characters in address"
bln_attack_detected=0
##
str_type_of_attack="The IP in question is attempting to exploit the Exim Vulnerability CVE-2019-10149 by injecting remote command execution into email headers."
#
## END Declare Variables ##
##
# START Test to check for all needed Data ##
##
# Confirm the log file settings are correct.
if [ ! -s ${str_exim_main_log_file} ] ; then
echo "Exim MainLog file not found or emtpy. Check script config."
echo "" >> ${str_exim_main_log_file}
fi
#
if [ ! -s ${str_exim_reject_log_file} ] ; then
echo "Exim Reject file not found or emtpy. Check script config."
echo "" >> ${str_exim_reject_log_file}
fi
#
if [ -z ${str_my_abuse_email_address_to_use_in_from_field} ] ; then
echo "Exim setting not done."
exit 1
fi
#
if [ -z ${str_my_abuse_email_address_to_send_copy_of_abuse_report} ] ; then
echo "Exim setting not done."
exit 1
fi
#
##
# END Test to check for all needed Data ##
##
## Start of Functions Code ##
##
#
function fun_create_evidence_log() {
# Get Attackers IP that have been passed to this function.
local str_tmp_attackers_ip=${1}
# Start evidence log of event.
local str_log_time=$(date)
local int_log_unix_time=$(date -d "${str_log_time}" +%s)
# Get the Whois Data of the attacking IP.
local str_whois_data=$(fun_get_ip_whois_details "${str_tmp_attackers_ip}")
# Extract the IP Owners Name
local str_attacker_ip_owner=$(awk -F" " '{print $1}' <<< ${str_whois_data})
# Extract the IP Owners registered Country
local str_attacker_ip_owner_country=$(awk -F" " '{print $2}' <<< ${str_whois_data})
# Extract the IP Owners email addresses.
local str_attacker_ip_owner_email=$(awk -F" " '{print $3}' <<< ${str_whois_data})
# Name of new file to add evidence too.
local str_evidence_log_name="${str_exim_log_dir}/exim_attacker_evidence_log__${int_log_unix_time}__${str_tmp_attackers_ip}__.txt"
# Echo out the data to the new file.
echo "Evidence Log Creation : ${str_log_time}" > "${str_evidence_log_name}"
echo "Attacking Email Server IP : ${str_tmp_attackers_ip}" >> "${str_evidence_log_name}"
echo "Attacking IP Owners Name : ${str_attacker_ip_owner}" >> "${str_evidence_log_name}"
echo "Attacking IP Owners registered Country : ${str_attacker_ip_owner_country}" >> "${str_evidence_log_name}"
echo "Attacking IP Owners email addresses : ${str_attacker_ip_owner_email}" >> "${str_evidence_log_name}"
echo "----START-Log-Activities---" >> "${str_evidence_log_name}" >> "${str_evidence_log_name}"
echo "===========================" >> "${str_evidence_log_name}" >> "${str_evidence_log_name}"
# Search both logs for all entries of the attacking IP.
grep -i "${str_tmp_attackers_ip}" "${str_exim_main_log_file}" >> "${str_evidence_log_name}"
grep -i "${str_tmp_attackers_ip}" "${str_exim_reject_log_file}" >> "${str_evidence_log_name}"
echo "===========================" >> "${str_evidence_log_name}" >> "${str_evidence_log_name}"
echo "----End-Log-Activities-----" >> "${str_evidence_log_name}" >> "${str_evidence_log_name}"
# echo the log name and location to act as a "return".
echo "${str_evidence_log_name}"
}
function fun_get_ip_whois_details() {
# Set the given IP that was passed to this function.
local str_ip_to_check="${1}"
# Get the Whois is data of the IP given. Keeps all data in one variable, so multiple whois requests are not made.
local str_whois_data=$(/usr/bin/whois "${str_ip_to_check}")
# Extract the IP Owners Name
local str_netname=$(grep -i "netname\|Organization\|OrgName" <<< "${str_whois_data}" | awk -F: '{print $2}' |\
tr -d " " | tr -d '\n' | tr ',' '.'|sed 's/,*$//g')
# Extract the IP Owners registered Country
local str_country_code=$(grep -i "country" <<< "${str_whois_data}" | uniq -i | awk -F: '{print $2}' |\
tr -d ' ' | tr '\n' ';'| tr ',' '.'|sed 's/;*$//g')
# Extract the IP Owners email addresses.
local str_email=$(echo "${str_whois_data}" | grep -i -o '[A-Z0-9._%+-]\+@[A-Z0-9.-]\+\.[A-Z]\{2,4\}' |\
uniq -i | sort | tr '\n' ',' | tr -d " "| sed 's/,*$//g')
# Remove Dup email addresses.
IFS=',' read -r -a ary_tmp_email_addresses <<< ${str_email}
local str_email=($(printf "%s\n" "${ary_tmp_email_addresses[@]}" | sort -u | tr '\n' ','))
# echo the values to act as a "return".
echo "${str_netname}" "${str_country_code}" "${str_email}"
}
function fun_make_abuse_email(){
# Get the evidence Logged that was passed.
local str_tmp_evidence_log_passed="${1}"
# Beginning of Email to send to Abuse.
local str_tmp_begin_abuse_email='Hello Abuse Team,\n An IP address registered under your control has been involved in committing malicious attacks. Please take imminent action to stop the attackers or blackhole the offending IP.\n\nBelow are the details of the attack.\n\n--Type-of-Attack--\n'"${str_type_of_attack}"'\n\n--Evidence-Log-Data--\n'
# End of Email to send to Abuse.
local str_tmp_end_abuse_email='\n\nPlease let our team know if you have any questions or require further evidence.\n\nRegards,\nHoneyPot Team\n\n'
# echo the full email body to act as a "return".
echo -e "${str_tmp_begin_abuse_email}"; echo -E "${str_tmp_evidence_log_passed}"; echo -e "${str_tmp_end_abuse_email}"
}
function fun_send_abuse_email(){
# Function Usage: fun_send_abuse_email <send-to> <send-from> <send-cc> <subject> <email-body>
# Note: all arguments must be passed. If there a none for a give argument then set it to ""
# Example: fun_send_abuse_email "[email protected]" "[email protected]" "" "ReadEmail" "Hello, I am a email."
# Temp File to craft the email.
local str_tmp_email_file_name_and_location='./tmp_email_to_send.eml'
# Set the variable that were passed to this functions.
local str_tmp_send_email_to="${1}"
local str_tmp_send_email_from="${2}"
local str_tmp_send_email_cc="${3}"
local str_tmp_send_email_subject="${4}"
local str_tmp_send_email_body="${5}"
local str_tmp_send_email_all_to_addresses="${6}"
# Start adding email header details
echo "TO: ${str_tmp_send_email_to}" > "${str_tmp_email_file_name_and_location}"
echo "From: ${str_tmp_send_email_from}" >> "${str_tmp_email_file_name_and_location}"
# echo "CC: ${str_tmp_send_email_cc}" >> "${str_tmp_email_file_name_and_location}"
echo "Reply-To: ${str_tmp_send_email_from}" >> "${str_tmp_email_file_name_and_location}"
echo "SUBJECT: ${str_tmp_send_email_subject}" >> "${str_tmp_email_file_name_and_location}"
echo "Content-Type: text/plain; charset=utf-8" >> "${str_tmp_email_file_name_and_location}"
echo "${str_tmp_send_email_body}" >> "${str_tmp_email_file_name_and_location}"
# Send the Email
/usr/sbin/exim4 -f"${str_tmp_send_email_from}" "${str_tmp_send_email_all_to_addresses}" <<< $(cat "${str_tmp_email_file_name_and_location}")
# Remove the temp email file after sending.
rm -f "${str_tmp_email_file_name_and_location}"
}
function fun_clean_and_preserve_logs() {
# Wait for emails to send.
sleep 60
# Attempt made preserve the logs.
tar cvf ./tmp_log_archive.tar ${str_exim_main_log_file} ${str_exim_reject_log_file} "${str_exim_log_dir}"/exim_attacker_e*
# Get a hash of the file to ensure file integrity and add the files name.
local str_log_archive_hash=$(md5sum ./tmp_log_archive.tar | awk -F' ' '{print $1}'|tr -d ' ')
# Get Time to add to the new file name.
local str_log_time=$(date)
local int_log_unix_time=$(date -d "${str_log_time}" +%s)
# Move and rename the log archive with the hash and time stamp.
mv ./tmp_log_archive.tar "${str_exim_log_dir}/${str_log_archive_hash}_${int_log_unix_time}.tar"
# No attack attempts found, wipe logs.
echo "" > "${str_exim_reject_log_file}"
echo "" > "${str_exim_main_log_file}"
rm "${str_exim_log_dir}"/exim_attacker_evidence_log_*
}
function fun_check_for_exploit_attempts() {
# Log File passed to function.
local str_tmp_log_file_to_check="${1}"
# Parse log for lines with denied exploit attempt.
local str_tmp_exploit_check=$(grep -i "${str_exploit_attempt_confirmation_string}" "${str_tmp_log_file_to_check}")
# Check if there are line returned.
if [ ! -z "${str_tmp_exploit_check}" ]; then
# Attempt Found. Start the evidence log creation. For attempt create a evidence log.
# Get all the IPs that have attempted a exploit and create list of only the IPs.
local ary_tmp_ip_attempting_attacks=()
while read -r str_tmp_single_attempt_made_log; do
# Extract just the IP of the attacking servers from the line of the log file currently being processed.
local str_tmp_attacker_email_server_ip=$(echo "${str_tmp_single_attempt_made_log}"|awk -F[ '{print $2}'|\
awk -F] '{print $1}' | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b")
# Append the array of attacker IPs.
ary_tmp_ip_attempting_attacks+=("${str_tmp_attacker_email_server_ip}")
done<<<"${str_tmp_exploit_check}"
# Remove duplicate IPs in the array
ary_tmp_ip_attempting_attacks=($(echo "${ary_tmp_ip_attempting_attacks[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
# Read the array of IPs found suspected of attacking.
for str_tmp_attacking_ip in "${ary_tmp_ip_attempting_attacks[@]}" ; do
# Create a log of the IPs attack.
local str_tmp_name_of_evidence_log=$(fun_create_evidence_log "${str_tmp_attacking_ip}")
# Extract abuse TO Email addresses form evidence log.
local str_tmp_abuse_email_to_field=$(grep -i 'Attacking IP Owners email addresses' "${str_tmp_name_of_evidence_log}" |\
awk -F: '{print $2}' | awk -F, '{print $1}')
# Extract abuse cc Email addresses form evidence log.
local str_tmp_abuse_email_cc_field=$(grep -i 'Attacking IP Owners email addresses' "${str_tmp_name_of_evidence_log}" |\
awk -F: '{print $2}')
local str_tmp_email_subject="Abuse from IP: ${str_tmp_attacking_ip}"
# Create a Abuse email with the evidence log.
local str_tmp_body_of_abuse_email=$(fun_make_abuse_email "$(cat "${str_tmp_name_of_evidence_log}")" )
# Clean up list of emails addresses to send to.
local str_tmp_all_email_addresses_to_sent_to=$(\
echo "${str_tmp_abuse_email_to_field}"','\
"${str_my_abuse_email_address_to_send_copy_of_abuse_report}"','\
"${str_tmp_abuse_email_cc_field}"| tr -d " ")
# Remove Dup email addresses.
IFS=',' read -r -a ary_all_email_addresses <<< ${str_tmp_all_email_addresses_to_sent_to}
str_tmp_all_email_addresses_to_sent_to=($(printf "%s\n" "${ary_all_email_addresses[@]}" | sort -u | tr '\n' ','|sed 's/.$//'))
# Send a abuse report with the log to the IP owners(all email found on the whois).
fun_send_abuse_email \
"${str_tmp_abuse_email_to_field}" \
"${str_my_abuse_email_address_to_use_in_from_field}" \
"${str_tmp_abuse_email_cc_field}" \
"${str_tmp_email_subject}" \
"${str_tmp_body_of_abuse_email}" "${str_tmp_all_email_addresses_to_sent_to}"
##
done
# Preserve Evidence and clean up directory.
fun_clean_and_preserve_logs
else
# No attempts made. End check of the log.
printf "No attempts found in log ${str_tmp_log_file_to_check} \n"
fi
}
#
##
## END Functions Code ##
##
## Start of Code ##
##
#
fun_check_for_exploit_attempts "${str_exim_main_log_file}"
# Email abuse .
#
##
## END of Code ##
#
exit 0