-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathyaraZeekAlert.py
207 lines (164 loc) · 6.64 KB
/
yaraZeekAlert.py
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
#!/usr/bin/python
# Name: yaraZeekAlert.py
# Author: David Bernal Michelena - SCILabs, 2019
# License: CREATIVE COMMONS LICENSE BY-NC https://creativecommons.org/licenses/by-nc/4.0/
# Description:
# This script scans the files extracted by Zeek with YARA rules located on the rules folder on a Linux based Zeek sensor, if there is a match it sends email alerts to the email address specified in the mailTo parameter on yaraAlert.conf file. The alert includes network context of the file transfer and attaches the suspicious file if it is less than 10 MB. Alerted files are copied locally to the alerted files folder.
# A Sample yaraAlert.conf configuration file is provided below, this file should be in the same folder than this script.
# mailUsername=DOMAIN\username2
# mailPassword=password
# mailServer=mail server IP address
# mailPort=25
import subprocess
import os
import time
import sys
import hashlib
import smtplib
import glob
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email import Encoders
# Change the following variables based on your own configuration
alertedFilesFolder = "/home/bro/YARA/alertedFiles"
extractedFilePath = "/home/bro/extracted"
yaraRulesPath = "/home/bro/YARA/rules"
sevenZipCommand = "/bin/7za"
yaraAlertConfigFile = "/home/bro/YARA/yaraAlert.conf"
if not os.path.isfile(yaraAlertConfigFile):
print "file does not exist: " + yaraAlertConfigFile
sys.exit(1)
with open(yaraAlertConfigFile,"r") as f:
for line in f:
lineLst = line.strip("\n").split("=")
if lineLst[0] in "mailUsername":
broMailUsername = lineLst[1]
elif lineLst[0] in "mailPassword":
broMailPassword = lineLst[1]
elif lineLst[0] in "mailServer":
mailServer = lineLst[1]
elif lineLst[0] in "mailPort":
mailPort = lineLst[1]
elif lineLst[0] in "mailDisplayFrom":
mailDisplayFrom = lineLst[1]
elif lineLst[0] in "mailTo":
mailTo = lineLst[1]
def hashes(fname):
md5 = hashlib.md5(open(fname,'rb').read()).hexdigest()
sha1 = hashlib.sha1(open(fname,'rb').read()).hexdigest()
sha256 = hashlib.sha256(open(fname,'rb').read()).hexdigest()
return [md5,sha1,sha256]
def searchContext(searchPath, pattern,archived):
flog = open("/home/bro/YARA/actions.log","w+")
flog.write("searching for pattern: " + pattern + " in " + searchPath)
out = ""
currentLogPath="/home/bro/logs/current"
if not archived:
files = glob.glob(searchPath + "/*.log")
else:
files = glob.glob(searchPath + "/*.log.gz")
for f in files:
flog.write("searching in " + f)
if not archived:
command = "/bin/cat " + f + " | /usr/local/bro/bin/bro-cut -d | grep " + pattern + " "
flog.write("command :" + command)
else:
command = "/bin/zgrep " + pattern + " " + f
flog.write("command :" + command)
print command
try:
flog.write("before appending \n" + out)
out += subprocess.check_output(command, shell=True)
flog.write("after appending \n" + out)
except:
pass
print "context found in path: " + searchPath
flog.write("context found in path: \n" + searchPath)
if out =="":
out = "Context not found in current logs \n"
print out
flog.write("output: " + out)
return out
def sendAlertEmail(message,fromaddr,recipient,filepath,context):
toaddr = recipient
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = recipient
msg['Subject'] = "YARA Alert"
body = "alerted rules: " + str(message[0]) + "\n"
body = body + "filepath: " + str(message[1]) + "\n"
body = body + "md5sum : " + str(message[2]) + "\n"
body = body + "sha1sum: " + str(message[3]) + "\n"
body = body + "sha256sum: " + str(message[4]) + "\n\n"
filename = filepath.split("/")[-1]
generatedZip = alertedFilesFolder + "/" + filename + ".zip"
print "generatedZip: " + generatedZip
if os.path.isfile(generatedZip):
os.remove(generatedZip)
rc = subprocess.call([sevenZipCommand, 'a', '-pinfected', '-y', generatedZip, filepath])
body = body + "saved Zip file: " + generatedZip + "\n\n"
body = body + "context: " + context + "\n"
filesize = os.path.getsize(generatedZip)
print body
print "filepath: " + filepath + " size: " + str(filesize)
if os.path.getsize(generatedZip) < 10000000:
part = MIMEBase('application', "zip")
part.set_payload(open(generatedZip, "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="' + filename + ".zip")
msg.attach(part)
else:
body = body + "File is too big for the attachment"
msg.attach(MIMEText(body, 'plain'))
server = smtplib.SMTP(mailServer,mailPort)
server.ehlo()
server.starttls()
server.ehlo
# Base64 encoding prevents issues with special characters with passwords/usernames
broMailPasswordB64 = broMailPassword.encode("base64")
broMailUsernameB64 = broMailUsername.encode("base64")
server.login(broMailUsernameB64.decode("base64"),broMailPasswordB64.decode("base64"))
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.close()
fout = open("/tmp/yaraAllRules","w")
print extractedFilePath
yaraRules = subprocess.check_output("find " + yaraRulesPath + " -name '*.yar' -exec cat {} + ", shell=True)
fout.write(yaraRules)
fout.close()
start = time.time()
#scanOutput = subprocess.check_output("yara -r /tmp/yaraAllRules " + extractedFilePath, shell=True)
scanOutput = subprocess.check_output("yara -r /tmp/yaraAllRules " + extractedFilePath + " -d extension=\"noext\" -d filename=\"nofilename\" -d filepath=\"nofilepath\" -d filetype=\"nofiletype\"", shell=True)
end = time.time()
print "Run time: " + str((end - start))
i=0
scanOutput = scanOutput.split("\n")
filesWithAlerts = {}
for line in scanOutput:
if not "warning" in line and len(line) > 10:
rule,filepath = line.strip().split(" ")
# If the file exists, it obtains the file hash
if filepath in filesWithAlerts.keys():
filesWithAlerts[filepath].append(rule)
else:
filesWithAlerts[filepath] = [rule]
for filepath, matchedRules in filesWithAlerts.items():
print "filepath: " + filepath + " v: " + str(matchedRules)
entry = [str(matchedRules),filepath] + hashes(filepath)
try:
print "send alert email"
pattern = filepath.split("/")[-1].split("-")[-1].split(".")[-2]
context = searchContext("/home/bro/logs/current", pattern,archived=False)
if context == "":
print "No additional context was found, searching on the historical log."
else:
print context
sendAlertEmail(entry,mailDisplayFrom,mailTo,filepath,context)
except Exception as e:
print(e)
files = glob.glob(extractedFilePath + "/*")
for f in files:
os.remove(f)