forked from sans-blue-team/DeepBlueCLI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDeepBlue.py
More file actions
163 lines (148 loc) · 6.34 KB
/
DeepBlue.py
File metadata and controls
163 lines (148 loc) · 6.34 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
#!/usr/bin/python
# DeepBlue.py Alpha 0.12 (post-DerbyCon release)
# Eric Conrad
# Twitter: @eric_conrad
# http://ericconrad.com
# deepblue at backshore dot net
# Currently alpha level functionality, supports CLI parsing only
# More features to come
# Requires libevtx: https://github.com/libyal/libevtx
import sys
import re
import csv
import base64
import os.path
import string
from subprocess import Popen, PIPE
def filter(str):
# Used to convert base64 decoded data (unicode) to ASCII
return ''.join([c for c in str if ord(c) > 31 or ord(c) == 9])
def CheckRegex(regexes,command):
string=""
for regex in regexes:
if (regex[0] == "0"):
if re.search(regex[1],command,re.IGNORECASE):
string+=" - "+regex[2]+"\n"
return(string)
def CheckObfu(cli,minpercent,minlength):
string=""
noalphastring=re.sub("[A-Za-z0-9]","",cli)
length1=float(len(cli))
if (length1 > minlength):
length2=float(len(noalphastring))
if ((length1/150) < minpercent):
minpercent=length1/150 # Shorter strings get lower minpercent, based on the string length
percent =((length1-length2)/length1)
if (percent < minpercent):
percent=(round(percent,2))*100
string += " - Potential command obfuscation: "+str(int(percent))+"% alpha characters"
return(string)
def CheckPasswordSpray(targetusername, accessingusername, passspraytrack, passsprayloginmax=6, passsprayuniqusermax=6):
passspraytrack[targetusername] = passspraytrack[targetusername] + 1 if targetusername in passspraytrack else 1
if passspraytrack[targetusername] > passsprayloginmax:
# This user account has exceedd the threshoold for explicit logins. Identify the total number
# of accounts that also have similar explicit login patterns.
targetusernames = []
for t in passspraytrack:
if passspraytrack[t] > passsprayloginmax:
targetusernames += [t]
if len(targetusernames) > passsprayuniqusermax:
print "Distributed Account Explicit Credential Use (Password Spray Attack)"
print "The use of multiple user account access attempts with explicit credentials is "
print "an indicator of a password spray attack.\n"
print "Target usernames: " + " ".join(targetusernames)
print "Accessing username: " + accessingusername
passspraytrack.clear()
def CheckCommand(time, log, eventid, cli):
minpercent=.65
minlength=25 # Minimum CLI length to check for obfuscation
string=""
decoded=""
noalphastring=""
string=CheckRegex(regexes,cli)
if re.search("\-enc.*[A-Za-z0-9/+=]{100}",cli,re.IGNORECASE):
b64=re.sub("^.* \-Enc(odedCommand)? ","",cli,re.IGNORECASE)
decoded=base64.b64decode(b64)
decoded=str(filter(decoded)) # Convert base64 to ASCII
string+=CheckRegex(regexes,decoded)
string += CheckObfu(cli,minpercent,minlength)
if(string):
print "Date: %s\nLog: %s\nEventID: %s" % (time,log,eventid)
print "Results:\n%s\n" % (string.rstrip())
print "Command: %s\n" % (cli)
if(decoded):
print "Decoded: %s" % (decoded)
if(string):
print "\n"
filename=""
regexfile="regexes.txt"
regexes=[]
if len(sys.argv)==2:
if os.path.isfile(sys.argv[1]):
filename=sys.argv[1]
if os.path.isfile(regexfile):
with open(regexfile) as csvfile:
reader = csv.reader(csvfile, delimiter=',')
for row in reader:
if not row[0].startswith('#'):
regexes.append(row)
else:
print "Error: cannot open "+regexfile+"\n"
else:
print "Error: no such file: %s\n" % (sys.argv)
else:
print "Error: filename required as an argument\n"
passspraytrack = {}
if (filename and regexes):
process=""
try:
process = Popen(['evtxexport', filename], stdout=PIPE, stderr=PIPE)
except:
print 'Can\'t find libevtx. Check the path and verify it is installed. See: https://github.com/libyal/libevtx'
if (process):
time=""
log=""
eventid=""
cli=""
path=""
targetusername=""
accessingusername=""
for line in iter(process.stdout.readline,''):
if re.search("^Written time",line):
#Written time : Aug 30, 2017 19:16:26.133985000 UTC
time = re.sub("^.*: ","",line)
time = time[:21]
elif re.search("^Source name",line):
log = re.sub("^.*: ","",line).rstrip()
elif re.search("^Event identifier",line):
# Looks like this, grab the number between the parentheses:
#Event identifier : 0x00001008 (4104)
#Event identifier : 0x00000001 (1)
eventid = re.sub("^.*\(","",line.rstrip())
eventid = re.sub("\).*$","",eventid)
elif re.search("^String: 3",line):
#Source name : Microsoft-Windows-PowerShell
if log=="Microsoft-Windows-PowerShell":
cli = line[14:].rstrip()
elif re.search("^String: 2",line):
if log=="Microsoft-Windows-Security-Auditing" and eventid=="4648":
accessingusername=line[14:].rstrip()
elif re.search("^String: 5",line):
if log=="Microsoft-Windows-PowerShell":
path = line[14:].rstrip()
elif log=="Microsoft-Windows-Sysmon":
cli = line[14:].rstrip()
elif re.search("^String: 6",line):
if log=="Microsoft-Windows-Security-Auditing" and eventid=="4648":
targetusername=line[14:].rstrip()
elif re.search("^String: 9",line):
if log=="Microsoft-Windows-Security-Auditing":
cli = line[14:].rstrip()
elif re.search("^$",line):
# 4688: CLI via System log
# 4104: PowerShell CLI if path is blank (non-blank path == PowerShell script)
# 1: Sysmon CLI
if ((eventid=="4688")or(eventid=="1")or((eventid=="4104")and(path==""))):
CheckCommand(time,log,eventid,cli)
if (eventid=="4648"):
CheckPasswordSpray(targetusername, accessingusername, passspraytrack)