-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcheck-auditd.sh
executable file
·395 lines (369 loc) · 12.1 KB
/
check-auditd.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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
#!/bin/bash
# GPL-3.0-or-later
# This script is meant to make querying auditd logs easier with some granularity.
# Thanks to the following projects for code, ideas, and guidance:
# https://github.com/g0tmi1k/OS-Scripts
# https://github.com/angristan/wireguard-install
# https://static.open-scap.org/ssg-guides/ssg-ubuntu2004-guide-stig.html
# https://github.com/ComplianceAsCode/content
# https://github.com/Neo23x0/auditd
# https://github.com/bfuzzy1/auditd-attack
# https://github.com/carlospolop/PEASS-ng
# shellcheck disable=SC2034
# shellcheck disable=SC2221
# shellcheck disable=SC2222
# shellcheck disable=SC2317
# Colors and color printing code taken directly from:
# https://github.com/carlospolop/PEASS-ng/blob/master/linPEAS/builder/linpeas_parts/linpeas_base.sh
C=$(printf '\033')
RED="${C}[1;31m"
SED_RED="${C}[1;31m&${C}[0m"
GREEN="${C}[1;32m"
SED_GREEN="${C}[1;32m&${C}[0m"
YELLOW="${C}[1;33m"
SED_YELLOW="${C}[1;33m&${C}[0m"
RED_YELLOW="${C}[1;31;103m"
SED_RED_YELLOW="${C}[1;31;103m&${C}[0m"
BLUE="${C}[1;34m"
SED_BLUE="${C}[1;34m&${C}[0m"
ITALIC_BLUE="${C}[1;34m${C}[3m"
LIGHT_MAGENTA="${C}[1;95m"
SED_LIGHT_MAGENTA="${C}[1;95m&${C}[0m"
LIGHT_CYAN="${C}[1;96m"
SED_LIGHT_CYAN="${C}[1;96m&${C}[0m"
LG="${C}[1;37m" #LightGray
SED_LG="${C}[1;37m&${C}[0m"
DG="${C}[1;90m" #DarkGray
SED_DG="${C}[1;90m&${C}[0m"
NC="${C}[0m"
UNDERLINED="${C}[5m"
ITALIC="${C}[3m"
CMD_LIST='
wget
curl
sudo
whoami
useradd
groupadd
usermod
groupmod
adduser
addgroup
passwd
pkexec
dbus-send
gdbus
poweroff
reboot
shutdown
halt
nc
nc.openbsd
nc.traditional
ncat
netcat
nmap
tcpdump
ping
ping6
id
ip
ifconfig
ss
netstat
stunnel
socat
ssh
sftp
ftp
base64
xxd
zip
unzip
gzip
gunzip
tar
bzip2
lzip
lz4
lzop
plzip
pbzip2
pixz
pigz
unpigz
zstd
python
python3
ruby
perl
'
FILE_LIST='
/etc/passwd
/etc/shadow
/etc/sudoers
.bashrc
'
function UidSummary() {
echo -e ""
echo -e "${ITALIC_BLUE}EVENTS BY UID${NC}"
echo -e ""
sudo aureport -if "$IF_PATH" -ts "$TIME_START" -te "$TIME_END" -u | cut -d ' ' -f 4 | sort | grep -P "(\-1|(\d){1,})" | uniq -c | sort -nr
}
function CmdEvents() {
echo -e ""
echo -e "${ITALIC_BLUE}COMMAND EVENTS${NC}"
echo -e ""
for cmd in $CMD_LIST; do
TMPLOGS_CMD="/tmp/$cmd.tmplog"
if (command -v "$cmd" > /dev/null); then
SORTED_COMMANDS="$(sudo ausearch -if "$IF_PATH" -ts "$TIME_START" -te "$TIME_END" -i -l -c "$cmd" 2>/dev/null | grep -Pv "\bsudo (ausearch|aureport)\s+-(ts|if)\b" | grep 'proctitle=' | sed 's/ proctitle=/\nproctitle=/g' | grep 'proctitle=' | sed 's/proctitle=//g' | sort | uniq -c | sort -n -r)"
if [[ "$SORTED_COMMANDS" != '' ]]; then
echo "$SORTED_COMMANDS" > "$TMPLOGS_CMD"
echo -e "=================================================="
echo -e ""
echo -e "${ITALIC}CMD:${NC} ${LIGHT_MAGENTA}$cmd${NC}"
echo -e "${ITALIC}TIME:${NC} ${YELLOW}$TIME_START → $TIME_END${NC}"
echo -e ""
sed -E "s/$cmd/$SED_LIGHT_MAGENTA/" "$TMPLOGS_CMD" | sed -E "s/(((\w){1,3}\.){3}(\w){1,3}|([a-f0-9]{1,4}(:|::)){3,8}[a-f0-9]{1,4})/${SED_LIGHT_CYAN}/"
fi
fi
# Clean up tmplog files
rm -f "$TMPLOGS_CMD"
done
}
function FileEvents() {
echo -e ""
echo -e "${ITALIC_BLUE}FILE EVENTS${NC}"
echo -e ""
for file in $FILE_LIST; do
SORTED_EVENTS="$(sudo ausearch -if "$IF_PATH" -ts "$TIME_START" -te "$TIME_END" -i -l -f "$file" 2>/dev/null | grep -Pv "\bsudo (ausearch|aureport)\s+-(ts|if)\b" | grep 'proctitle=' | sed 's/ proctitle=/\nproctitle=/g' | grep 'proctitle=' | sed 's/proctitle=//g' | sort | uniq -c | sort -n -r)"
if [[ "$SORTED_EVENTS" != '' ]]; then
echo -e "=================================================="
echo -e ""
echo -e "${ITALIC}FILE:${NC} ${LIGHT_MAGENTA}$file${NC}"
echo -e "${ITALIC}TIME:${NC} ${YELLOW}$TIME_START → $TIME_END${NC}"
echo -e ""
echo "$SORTED_EVENTS"
fi
done
}
function NetEvents() {
TMPLOGS_NET='/tmp/net-events.tmplog'
TMPLOGS_CONN='/tmp/connections.tmplog'
# https://unix.stackexchange.com/questions/304389/remove-newline-character-just-every-n-lines
echo -e "=================================================="
echo -e ""
echo -e "${ITALIC_BLUE}NETWORK CONNECTIONS${NC}"
echo -e ""
NET_CONNECTIONS="$(sudo ausearch -if "$IF_PATH" -ts "$TIME_START" -te "$TIME_END" -i -l -sc connect -sv yes | grep -Pv "\bsudo (ausearch|aureport)\s+-(ts|if)\b" | grep -P "( proctitle=| saddr=)" | sed 's/ proctitle=/\nproctitle=/g' | sed 's/ saddr=/\nsaddr=/g' | grep -P "(proctitle=|saddr=)" | paste -sd ' \n' - | sort )"
echo "$NET_CONNECTIONS" > "$TMPLOGS_NET"
echo ""
echo -e "${ITALIC}${YELLOW}PORTS BY FREQUENCY${NC}"
grep -oP "lport=(\w){1,5}" "$TMPLOGS_NET" | sort | uniq -c | sort -n -r
echo ""
# Create a CSV file of all connections for easy display with `column -t`
echo -e "${ITALIC}${YELLOW}ADDRESSES BY FREQUENCY${NC}"
echo "TOTAL,HOST,SYSCALL,USER" | tee "$TMPLOGS_CONN" >/dev/null
sudo aureport -if "$IF_PATH" -ts "$TIME_START" -h -i | cut -d ' ' -f 4-6 | grep -Pv "(^\s|^=+|host syscall auid)" | sort | uniq -c | sort -nr | sed -E 's/\s+/,/g' | sed -E 's/^,//g' | tee -a "$TMPLOGS_CONN" >/dev/null
tr ',' '\t' < "$TMPLOGS_CONN" | column -t | sed -E "s/(((\w){1,3}\.){3}(\w){1,3}|([a-f0-9]{1,4}(:|::)){3,8}[a-f0-9]{1,4})/${SED_LIGHT_CYAN}/" | sed 's/^/ /g' | sed -E "s/root$/${SED_RED}/"
echo ""
echo -e "${ITALIC}${YELLOW}EXTRACTED URLS${NC}"
# Try to match all protocols, infinite subdomains, directory paths, and finally special characters (essentially any non-space character) appended, followed by alphanumeric characters
grep -oP "\b\w+(://|@)((\w+\.)?){1,}\w+\.\w+((/\w+)?){1,}(((\S){1,}\w+)?){1,}" "$TMPLOGS_NET" | sort | uniq -c | sort -n -r
echo ""
# Extract binaries from the proctitle= field
echo -e "${ITALIC}${YELLOW}UNIQUE APPLICATIONS${NC}"
cut -d ' ' -f 1 "$TMPLOGS_NET" | grep -Po 'proctitle=([\S]*)' | sed 's/proctitle=//g' | sort | uniq -c | sort -nr
echo ""
echo -e "${ITALIC}${YELLOW}CONNECTIONS BY FREQUENCY${NC}"
sed -E "s/laddr=(((\w){1,3}\.){3}(\w){1,3}|([a-f0-9]{1,4}(:|::)){3,8}[a-f0-9]{1,4})/${SED_LIGHT_CYAN}/" "$TMPLOGS_NET" | sed -E "s/lport=(\w){1,5}/${SED_GREEN}/" | sed -E "s/proctitle=([^[:space:]]*)/${SED_LIGHT_MAGENTA}/" | sort | uniq -c | sort -n -r
echo ""
echo -e "${ITALIC}${YELLOW}CONNECTIONS BY APPLICATION${NC}"
sed -E "s/^.*proctitle=/proctitle=/g" "$TMPLOGS_NET" | sed -E "s/laddr=(((\w){1,3}\.){3}(\w){1,3}|([a-f0-9]{1,4}(:|::)){3,8}[a-f0-9]{1,4})/${SED_LIGHT_CYAN}/" | sed -E "s/lport=(\w){1,5}/${SED_GREEN}/" | sed -E "s/proctitle=([^[:space:]]*)/${SED_LIGHT_MAGENTA}/" | sort | uniq -c
# Cleanup tmplog files
rm -f "$TMPLOGS_NET"
rm -f "$TMPLOGS_CONN"
}
# Usage options
function HelpMenu() {
echo -e ""
echo -e "${LIGHT_MAGENTA}check-auditd.sh${NC}; a wrapper to summarize ${LIGHT_MAGENTA}auditd${NC} logs."
echo -e ""
echo -e "${ITALIC}Color scheme: ${LIGHT_MAGENTA}Commands${NC} | ${YELLOW}Time${NC} | ${LIGHT_CYAN}IP Addresses${NC} | ${GREEN}Ports${NC}"
echo -e ""
echo -e "This script can do the following:"
echo -e ""
echo -e " * Parse active auditd logs or a take a path to offline logs"
echo -e " * Prints a summary of UIDs appearing in events"
echo -e " * Search for command events matching a built in list of living-off-the-land binaries"
echo -e " * Match any entries of a specific [COMMAND]"
echo -e " * Show each unique command line string, sorted by frequency"
echo -e " * Shows log entries related to a [FILE], or a built in list of special files, sorted by frequency"
echo -e " * Summarizes logged network activity, such as dest port, dest IP, URL patterns, or applications making connections"
echo -e " * Network activity is also sorted by frequency"
echo -e ""
echo -e "An attempt is made to filter out command events using specific 'ausearch' and 'aureport' strings to prevent queries from flooding the results."
echo -e "${ITALIC}Activity must already be logged by audit rules for this script to parse it out of a log file.${NC}"
echo -e ""
echo -e "${LIGHT_MAGENTA}[*]Usage: $0 -ts today [-if FILE] [OPTIONS...]${NC}"
echo -e ""
echo -e "MAIN ARGUMENTS"
echo -e ""
echo -e " -ts, --start [start-date|start-time|keyword]"
echo -e " The time frame to begin searching in logs. Example date: 01/01/2024. Example time: 18:00:00. You can also use keywords."
echo -e " Keywords include: now, recent, this-hour, boot, today, yesterday, this-week, week-ago, this-month, this-year, or checkpoint."
echo -e " Currently can only use either a date or a time, not both."
echo -e ""
echo -e " -te, --end [end-date|end-time|keyword]"
echo -e " The time frame to end searching in logs. If blank, default is 'now'. Like start-time, you can also use keywords."
echo -e " Currently can only use either a date or a time, not both."
echo -e ""
echo -e " -if, --input"
echo -e " Path to an offline audit log file."
echo -e ""
echo -e " -h, --help"
echo -e " Print this help menu."
echo -e ""
echo -e "OPTIONAL ARGUMENTS"
echo -e " ${ITALIC}Only one of these arguments will work at a time. If multiple are present, the first one wins.${NC}"
echo -e ""
echo -e " -ae, --all-events"
echo -e " Display command, file, and network events."
echo -e ""
echo -e " -ne, --net-events"
echo -e " Only display network related information."
echo -e ""
echo -e " -fe, --file-events"
echo -e " Only display file related information."
echo -e ""
echo -e " -ce, --cmd-events"
echo -e " Only display command related information."
echo -e ""
echo -e " -c, --command"
echo -e " Match events that include [COMMAND]."
echo -e ""
echo -e " -f, --file"
echo -e " Match events that include [FILE]."
echo -e ""
exit 0
}
# Show help if there aren't any arguments
if [[ $# -eq 0 ]]; then
HelpMenu
exit 1
fi
# This is the easiest way to do this in bash, but it won't work in other shells
# See getopt-parse under /usr/share/doc/util-linux/examples
# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash
POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
case $1 in
-ts|--start)
TIME_START="$2"
shift # past argument
shift # past value
;;
-te|--end)
TIME_END="$2"
shift # past argument
shift # past value
;;
-ne|--net-events)
NET_EVENTS="1"
shift # past argument
shift # past value
;;
-fe|--file-events)
FILE_EVENTS="1"
shift # past argument
shift # past value
;;
-ce|--cmd-events)
CMD_EVENTS="1"
shift # past argument
shift # past value
;;
-c|--command)
CMD_SEARCH_STRING="$2"
shift # past argument
shift # past value
;;
-f|--file)
FILE_SEARCH_STRING="$2"
shift # past argument
shift # past value
;;
-if|--input)
INPUT_FILE="$2"
shift # past argument
shift # past value
;;
-ae|--all-events)
ALL_EVENTS="1"
shift # past argument
shift # past value
;;
-h|--help)
HelpMenu
shift # past argument
shift # past value
;;
-*|--*)
echo "Unknown option $1"
exit 1
;;
*)
POSITIONAL_ARGS+=("$1") # save positional arg
shift # past argument
;;
esac
done
# Argument logic
CheckAuditd() {
# If start time -ts argument is missing, exit
if [[ "$TIME_START" == '' ]]; then
echo -e "${RED}[*]Missing argument for start time: -ts, --start. See $0 -h for more options.${NC}"
echo ""
exit 1
fi
# Set current time if -te argument is ommitted
if [[ "$TIME_END" == '' ]]; then
TIME_END='now'
fi
# Use an input file if -if has an argument
if [[ "$INPUT_FILE" != '' ]]; then
IF_PATH="$INPUT_FILE"
else
IF_PATH='/var/log/audit/audit.log'
fi
# Always execute the UID summary
UidSummary
# Execute functions based on arguments
if [[ "$ALL_EVENTS" == "1" ]]; then
CmdEvents
FileEvents
NetEvents
fi
if [[ "$CMD_EVENTS" == "1" ]]; then
CmdEvents
fi
if [[ "$FILE_EVENTS" == "1" ]]; then
FileEvents
fi
if [[ "$NET_EVENTS" == "1" ]]; then
NetEvents
fi
# Use built in lists unless user specifies a search string
if [[ "$CMD_SEARCH_STRING" != '' ]]; then
CMD_LIST="$CMD_SEARCH_STRING"
CmdEvents
fi
if [[ "$FILE_SEARCH_STRING" != '' ]]; then
FILE_LIST="$FILE_SEARCH_STRING"
FileEvents
fi
# Clean up all tmplog files
rm -f /tmp/*.tmplog
}
CheckAuditd