11
11
string ]] # Sequences are immutable so need to create a sequence of pointers to tables so we can update ["ElapsedTime"]
12
12
seqOfLogoffEventTables* : seq [Table[string , string ]] # This sequence can be immutable
13
13
logoffEvents* : Table[string , string ] = initTable[string , string ]()
14
+ rdpLogoffEvents* : Table[string , seq [string ]] = initTable[string , seq [string ]]()
14
15
adminLogonEvents* : Table[string , string ] = initTable[string , string ]()
16
+ EID_21_count* : int = 0 # RDP Logon
17
+ EID_23_count* : int = 0 # RDP Logoff
15
18
EID_4624_count* = 0 # Successful logon
16
19
EID_4625_count* = 0 # Failed logon
17
20
EID_4634_count* = 0 # Logoff
24
27
25
28
method filter* (self: TimelineLogonCmd, x: HayabusaJson): bool =
26
29
return x.EventId == 4624 or x.EventId == 4625 or x.EventId == 4634 or
27
- x.EventId == 4647 or x.EventId == 4648 or x.EventId == 4672
30
+ x.EventId == 4647 or x.EventId == 4648 or x.EventId == 4672 or x.EventId == 21 or x.EventId == 23
28
31
29
32
method analyze* (self: TimelineLogonCmd, x: HayabusaJson) =
30
33
let ruleTitle = x.RuleTitle
@@ -174,6 +177,71 @@ method analyze*(self: TimelineLogonCmd, x: HayabusaJson) =
174
177
singleResultTable[" LID" ] = details.extractStr(" LID" )
175
178
self.seqOfResultsTables.add(singleResultTable)
176
179
180
+ # EID 21 Logon
181
+ if ruleTitle == " RDP Logon" :
182
+ inc self.EID_21_count
183
+ var singleResultTable = newTable[string , string ]()
184
+ singleResultTable[" Event" ] = ruleTitle
185
+ singleResultTable[" Timestamp" ] = jsonLine.Timestamp
186
+ singleResultTable[" Channel" ] = jsonLine.Channel
187
+ singleResultTable[" EventID" ] = " 21"
188
+ let details = jsonLine.Details
189
+ singleResultTable[" TargetComputer" ] = jsonLine.Computer
190
+ singleResultTable[" SourceIP" ] = details.extractStr(" SrcIP" )
191
+ let userDetail = details.extractStr(" TgtUser" )
192
+ if userDetail.contains(" \\ " ):
193
+ let parts = userDetail.split(" \\ " )
194
+ singleResultTable[" TargetDomainName" ] = parts[0 ]
195
+ singleResultTable[" TargetUser" ] = parts[1 ]
196
+ else :
197
+ singleResultTable[" TargetUser" ] = userDetail
198
+ singleResultTable[" LID" ] = details.extractStr(" SessID" )
199
+ singleResultTable[" LogoffTime" ] = " "
200
+ singleResultTable[" ElapsedTime" ] = " "
201
+ self.seqOfResultsTables.add(singleResultTable)
202
+
203
+ # EID 23 RDP Logoff
204
+ if ruleTitle == " RDP Logoff" :
205
+ inc self.EID_23_count
206
+ # If we want to calculate ElapsedTime
207
+ let details = jsonLine.Details
208
+ if self.calculateElapsedTime:
209
+ # Create the key in the format of LID:Computer:User with a value of the timestamp
210
+ var tgtUser = details.extractStr(" TgtUser" )
211
+ if tgtUser.contains(" \\ " ):
212
+ let parts = tgtUser.split(" \\ " )
213
+ tgtUser = parts[1 ]
214
+ let key = jsonLine.Details[" SessID" ].getStr() & " :" &
215
+ jsonLine.Computer & " :" & tgtUser
216
+ let logoffTime = jsonLine.Timestamp
217
+ if self.rdpLogoffEvents.hasKey(key):
218
+ self.rdpLogoffEvents[key].add(logoffTime)
219
+ else :
220
+ self.rdpLogoffEvents[key] = @ [logoffTime]
221
+ if self.outputLogoffEvents:
222
+ var singleResultTable = newTable[string , string ]()
223
+ singleResultTable[" Event" ] = ruleTitle
224
+ singleResultTable[" Timestamp" ] = jsonLine.Timestamp
225
+ singleResultTable[" Channel" ] = jsonLine.Channel
226
+ singleResultTable[" TargetComputer" ] = jsonLine.Computer
227
+ singleResultTable[" EventID" ] = " 23"
228
+ let userDetail = details.extractStr(" TgtUser" )
229
+ if userDetail.contains(" \\ " ):
230
+ let parts = userDetail.split(" \\ " )
231
+ singleResultTable[" TargetDomainName" ] = parts[0 ]
232
+ singleResultTable[" TargetUser" ] = parts[1 ]
233
+ else :
234
+ singleResultTable[" TargetUser" ] = userDetail
235
+ singleResultTable[" LID" ] = details.extractStr(" SessID" )
236
+ self.seqOfResultsTables.add(singleResultTable)
237
+
238
+ proc calculateDuration(logonTime: string , logoffTime: string , timeFormat: string ): Duration =
239
+ let logonTime = if logonTime.endsWith(" Z" ): logonTime.replace(" Z" , " " ) else : logonTime[0 ..< logonTime.len - 7 ]
240
+ let logoffTime = if logoffTime.endsWith(" Z" ): logoffTime.replace(" Z" , " " ) else : logoffTime[0 ..< logoffTime.len - 7 ]
241
+ let parsedLogoffTime = parse(padString(logoffTime, '0' , timeFormat), timeFormat)
242
+ let parsedLogonTime = parse(padString(logonTime, '0' , timeFormat), timeFormat)
243
+ return parsedLogoffTime - parsedLogonTime
244
+
177
245
method resultOutput* (self: TimelineLogonCmd) =
178
246
if self.displayTable:
179
247
echo " "
@@ -183,28 +251,25 @@ method resultOutput*(self: TimelineLogonCmd) =
183
251
# Calculating the logon elapsed time (default)
184
252
if self.calculateElapsedTime:
185
253
for tableOfResults in self.seqOfResultsTables:
186
- if tableOfResults[" EventID" ] == " 4624" :
187
- var logoffTime = " "
254
+ if tableOfResults[" EventID" ] == " 4624" or tableOfResults[" EventID" ] == " 21" :
188
255
var logonTime = tableOfResults[" Timestamp" ]
189
-
190
256
let key = tableOfResults[" LID" ] & " :" & tableOfResults[
191
257
" TargetComputer" ] & " :" & tableOfResults[" TargetUser" ]
192
258
if self.logoffEvents.hasKey(key):
193
- logoffTime = self.logoffEvents[key]
194
- tableOfResults[][" LogoffTime" ] = logoffTime
195
- logonTime = if logonTime.endsWith(" Z" ): logonTime.replace(
196
- " Z" , " " ) else : logonTime[0 ..< logonTime.len - 7 ]
197
- logoffTime = if logoffTime.endsWith(
198
- " Z" ): logoffTime.replace(" Z" , " " ) else : logoffTime[
199
- 0 ..< logofftime.len - 7 ]
200
- let parsedLogoffTime = parse(padString(logoffTime, '0' ,
201
- timeFormat), timeFormat)
202
- let parsedLogonTime = parse(padString(logonTime, '0' ,
203
- timeFormat), timeFormat)
204
- let duration = parsedLogoffTime - parsedLogonTime
205
- tableOfResults[][" ElapsedTime" ] = formatDuration(duration)
206
- else :
207
- logoffTime = " n/a"
259
+ let logoffTime = self.logoffEvents[key]
260
+ if logoffTime > logonTime:
261
+ tableOfResults[][" LogoffTime" ] = logoffTime
262
+ let duration = calculateDuration(logonTime, logoffTime, timeFormat)
263
+ tableOfResults[][" ElapsedTime" ] = formatDuration(duration)
264
+ elif self.rdpLogoffEvents.hasKey(key):
265
+ var logoffTimes = self.rdpLogoffEvents[key]
266
+ logoffTimes.sort()
267
+ for logoffTime in logoffTimes:
268
+ if logoffTime > logonTime:
269
+ tableOfResults[][" LogoffTime" ] = logoffTime
270
+ let duration = calculateDuration(logonTime, logoffTime, timeFormat)
271
+ tableOfResults[][" ElapsedTime" ] = formatDuration(duration)
272
+ break
208
273
209
274
# Find admin logons
210
275
for tableOfResults in self.seqOfResultsTables:
@@ -241,7 +306,11 @@ method resultOutput*(self: TimelineLogonCmd) =
241
306
padString(" EID 4648 (Explicit Logon): " & intToStr(
242
307
self.EID_4648_count).insertSep(',' ), ' ' , 80 ) &
243
308
padString(" EID 4672 (Admin Logon): " & intToStr(
244
- self.EID_4672_count).insertSep(',' ), ' ' , 80 )
309
+ self.EID_4672_count).insertSep(',' ), ' ' , 80 ) &
310
+ padString(" EID 21 (RDP Logon): " & intToStr(
311
+ self.EID_21_count).insertSep(',' ), ' ' , 80 ) &
312
+ padString(" EID 23 (RDP Logoff): " & intToStr(
313
+ self.EID_23_count).insertSep(',' ), ' ' , 80 )
245
314
if self.displayTable:
246
315
echo " "
247
316
echo " Found logon events:"
@@ -256,8 +325,13 @@ method resultOutput*(self: TimelineLogonCmd) =
256
325
self.EID_4648_count).insertSep(',' )
257
326
echo " EID 4672 (Admin Logon): " , intToStr(
258
327
self.EID_4672_count).insertSep(',' )
328
+ echo " EID 21 (RDP Logon): " , intToStr(
329
+ self.EID_21_count).insertSep(',' )
330
+ echo " EID 23 (RDP Logoff): " , intToStr(
331
+ self.EID_23_count).insertSep(',' )
259
332
echo " "
260
333
334
+
261
335
# Save results
262
336
var outputFile = open(self.output, fmWrite)
263
337
let header = [" Timestamp" , " Channel" , " EventID" , " Event" , " LogoffTime" ,
@@ -272,6 +346,10 @@ method resultOutput*(self: TimelineLogonCmd) =
272
346
outputFile.write(" \p " )
273
347
274
348
# # Write contents
349
+ self.seqOfResultsTables.sort(proc (a, b: TableRef[string , string ]): int =
350
+ if a[" Timestamp" ] < b[" Timestamp" ]: return - 1
351
+ if a[" Timestamp" ] > b[" Timestamp" ]: return 1
352
+ return 0 )
275
353
for table in self.seqOfResultsTables:
276
354
for key in header:
277
355
if table.hasKey(key):
0 commit comments