Advertisement
opexxx

event2timeline.py

May 2nd, 2014
335
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.31 KB | None | 0 0
  1. ########################################################################################################
  2. #                                                                                                      #
  3. #   Event2Timeline by @tomchop_ for CERT Societe Generale (@CertSG). Some features added by @Jipe_     #
  4. #                                                                                                      #
  5. #   This work is licensed under the GPL License                                                        #
  6. #   http://www.gnu.org/licenses/gpl.txt                                                                #
  7. #                                                                                                      #
  8. #   https://cert.societegenerale.com/ - https://github.com/certsocietegenerale/event2timeline/         #
  9. #                                                                                                      #
  10. ########################################################################################################
  11.  
  12. ### /!\ You must modify the USERNAME_STRING to match the "username" strings in your langage! /!\ ###
  13.  
  14. import csv, sys, re
  15. import optparse
  16. import datetime
  17. import calendar
  18. import mmap
  19. import contextlib
  20. from dateutil.parser import parse
  21. from Evtx.Evtx import FileHeader
  22. from Evtx.Views import evtx_file_xml_view
  23.  
  24. __description__ = "Event2Timeline"
  25. __version__ = "0.0.2"
  26.  
  27. eid_regex = re.compile('<EventID Qualifiers="(?P<qualifiers>.*)">(?P<eid>\d+)</EventID>')
  28. sessid_regex = re.compile('<Data Name="TargetLogonId">(?P<session_id>0x[0-9a-fA-F]+)</Data>')
  29. time_regex = re.compile('SystemTime="(?P<time>.*)"')
  30.  
  31. EVTX_LOGIN = [
  32.                 4624,   # An account was successfully logged on
  33.                 4778,   # RDP - Session connceted / reconnected
  34.                 ]  
  35.  
  36. EVTX_LOGOFF = [
  37.                 4647,   # User initiated logoff
  38.                 4634,   # An account was logged off
  39.                 4779,   # RDP - Session disconnected
  40.                 ]
  41.  
  42. EVT_LOGIN = [i-4096 for i in EVTX_LOGIN] + [540] # Successful network logon (=4624 in EVTX)
  43. EVT_LOGOFF = [i-4096 for i in EVTX_LOGOFF]
  44.  
  45. USERNAME_STRING = 'tilisateur' ###### MODIFY THIS TO WHICHEVER LANGUAGE YOUR CSV FILE IS ######
  46.  
  47. def get_data(xml, name):
  48.     rex = re.compile('<Data Name="%s">(?P<%s>.*)</Data>' % (name, name))
  49.     try:
  50.         return rex.search(xml).group(name)
  51.     except Exception, e:
  52.         return None
  53.  
  54. def import_xml(filename):
  55.  
  56.     # 4624 - Login      528
  57.     # 4647 - Logoff     551
  58.  
  59.     #[*] Keys: Category, Description, Data, Domain\User, Date&Time, Source, Computer, Time, Date, Type, Event
  60.  
  61.     sessions = {}
  62.     user_sessions = {}
  63.     count = 0
  64.  
  65.     with open(filename, 'r') as f:
  66.         print "[*] Reading EVTX file %s" % filename
  67.         with contextlib.closing(mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)) as buf:
  68.             fh = FileHeader(buf, 0x0)
  69.             count = 0
  70.             for xml, record in evtx_file_xml_view(fh):
  71.                 if (count % 2000) == 0:
  72.                     print "%s records read" % count
  73.                 count +=1
  74.                
  75.                 match = eid_regex.search(xml)
  76.                 eid = int(match.group('eid'))
  77.                 session_id = get_data(xml, 'TargetLogonId')
  78.                
  79.                 # Insert new session in dictionary
  80.                 if sessions.get(session_id, None) == None:
  81.                     sessions[session_id] = {}
  82.  
  83.                 if eid in EVTX_LOGIN:
  84.  
  85.                     if session_id:
  86.                         sessions[session_id] = {}
  87.                     else:
  88.                         continue
  89.  
  90.                     info = {}
  91.                     info['logon_type'] = get_data(xml, 'LogonType')
  92.                     info['eid'] = str(eid)
  93.                     info['ip'] = get_data(xml, 'IpAddress') + ':' + get_data(xml, 'IpPort')
  94.                     info['datetime'] = parse(time_regex.search(xml).group('time')[:-7])
  95.  
  96.                     sessions[session_id][str(eid)] = info
  97.                     username = get_data(xml, 'TargetDomainName') + '\\' + get_data(xml, 'TargetUserName')
  98.                     sessions[session_id]['username'] = username
  99.                
  100.                 elif eid in EVTX_LOGOFF:
  101.                     # Ignore if orphan session
  102.                     if not sessions.get(session_id, None) == None:
  103.                         continue
  104.  
  105.                     info = {}
  106.                     info['eid'] = str(eid)
  107.                     info['datetime'] = parse(time_regex.search(xml).group('time')[:-7])
  108.                     sessions[session_id][str(eid)] = info
  109.  
  110.  
  111.     return sessions
  112.  
  113. def import_csv(filename, delimiter=';', quotechar='"'):
  114.  
  115.     with open (filename, 'rU') as csvfile:
  116.         logs = []
  117.         print "[*] Reading CSV file %s" % filename
  118.         logreader = csv.DictReader(csvfile, delimiter=delimiter, quotechar=quotechar)
  119.  
  120. # Audit Success;23/05/2013;09:00:00;23/05/2013 09:00:00;538;Security;Ouverture/Fermeture de session;\S-1-5-21-2052699199-3915784498-1582209984-43253;USER01;"Fermeture de la session utilisateur : Utilisateur :        username Domaine :        userdomain Id. de la session :        (0x0,0xB38D21AB) Type de session :        4";
  121.  
  122.         for log in logreader:
  123.             logs.append(log)
  124.  
  125.         print "[*] %s lines imported" % (len(logs))
  126.         print '[*] Keys: %s' % ", ".join([i for i in logs[0]])
  127.  
  128.         # return logs[::-1]
  129.  
  130.         sessions = {}
  131.         user_sessions = {}
  132.  
  133.         count = 0
  134.  
  135.         for log in logs:
  136.  
  137.             count += 1
  138.  
  139.             try:
  140.                 session_id = re.search('(?P<session_id>0x([0-9a-fA-F]{2,}))', log['Description']).group('session_id')
  141.             except Exception, e:
  142.                 continue
  143.  
  144.             if sessions.get(session_id, None) == None:
  145.                 sessions[session_id] = {}
  146.  
  147.             if int(log['Event']) in EVT_LOGIN:
  148.                 info = {}
  149.                 info['eid'] = log['Event']
  150.                 info['datetime'] = parse(log['Date&Time'])
  151.                
  152.                 sessions[session_id][log['Event']] = info
  153.                 username = re.search("%s\W+(?P<username>[\w\.\-$]+)\n" %USERNAME_STRING, log['Description']).group('username')
  154.                 sessions[session_id]['username'] = username
  155.  
  156.             elif int(log['Event']) in EVT_LOGOFF:
  157.                 if sessions.get(session_id, None) == None: # Avoid orphan sessions
  158.                     continue
  159.                 info = {}
  160.                 info['eid'] = log['Event']
  161.                 info['datetime'] = parse(log['Date&Time'])
  162.  
  163.                 sessions[session_id][log['Event']] = info
  164.  
  165.         print "[*] %s sessions found (%s lines parsed)" % (len(sessions), count)
  166.         return sessions
  167.  
  168. def sessions2timeline(sessions):
  169.  
  170.         # generate session list by user
  171.         user_sessions = {}
  172.         for sid in [s for s in sessions if sessions[s].get('username', None) != None]:
  173.             s = sessions[sid]
  174.            
  175.             if user_sessions.get(s['username'], None) == None:
  176.                 user_sessions[s['username']] = {}
  177.            
  178.             user_sessions[s['username']][sid] = s
  179.            
  180.         print "[*] Unique users: %s" % len(user_sessions)
  181.                
  182.         lanes = [u for u in user_sessions]
  183.  
  184.         items = []
  185.         for i, username in enumerate(user_sessions):
  186.  
  187.             for user_session in get_sessions(user_sessions[username]):
  188.                 if user_session['end'] - user_session['start'] < datetime.timedelta(seconds=10):
  189.                     user_session['end'] = user_session['start'] + datetime.timedelta(seconds=10)
  190.  
  191.                 items.append({'info': user_session['info'],'lane': i, 'start': str(user_session['start']), 'end': str(user_session['end'])})
  192.            
  193.         time_begin = min([i['start'] for i in items])
  194.         time_end = max([i['end'] for i in items])
  195.  
  196.         return {'time_begin': time_begin, 'time_end': time_end, 'items': items, 'lanes': lanes}
  197.  
  198.  
  199.  
  200.  
  201. def get_sessions(user_sessions):
  202.    
  203.     sessions = []
  204.  
  205.     for sid in user_sessions:
  206.         s = user_sessions[sid]
  207.         start, end = None, None
  208.         for evt in s:
  209.             if evt != 'username':
  210.                 if int(evt) in EVT_LOGIN or int(evt) in EVTX_LOGIN: # deal with a login event- look for the smallest date for session start
  211.                     if start == None:
  212.                         start = s[evt]['datetime']
  213.                     elif s[evt]['datetime'] < start:
  214.                         start = s[evt]['datetime']
  215.                 if int(evt) in EVT_LOGOFF or int(evt) in EVTX_LOGOFF: # deal with a logoff event- look for the biggest date for session start
  216.                     if end == None:
  217.                         end = s[evt]['datetime']
  218.                     elif s[evt]['datetime'] > end:
  219.                         end = s[evt]['datetime']
  220.  
  221.         if end == None:
  222.             end = start
  223.         if start == None:
  224.             start = end
  225.  
  226.         # remove datetime object, which does not parse well to JS
  227.         for i in s:
  228.             try:
  229.                 s[i].pop('datetime')
  230.             except Exception, e:
  231.                 pass
  232.         sessions.append({'start': start, 'end': end, 'info': s})
  233.    
  234.     return sessions
  235.    
  236.  
  237. def print_log(log):
  238.     for key in log:
  239.         for entry in log[key]:
  240.             for k in entry:
  241.                 print "%s:\n%s\n" % (k, entry[k])  
  242.         else:
  243.             print "%s:\n%s\n" % (key, log[key])
  244.  
  245. if __name__ == '__main__':
  246.  
  247.     Parser = optparse.OptionParser(usage='usage: %prog [-c | -e] -f eventlogfile')
  248.     Parser.add_option('-f', '--filename', dest="eventlogfile", help='path to the evenlog file')
  249.     Parser.add_option('-c', '--csv', action="store_true", default=False, help='Specify the events are in CSV format (for an exported .evt)')
  250.     Parser.add_option('-e', '--evtx', action="store_true", default=False, help='Specify the events are in EVTX format (for a native .evtx)')
  251.  
  252.     (options, args) = Parser.parse_args()
  253.    
  254.     if not options.eventlogfile:
  255.         Parser.error("You must specify a filename")
  256.  
  257.     if options.csv:
  258.         sessions = import_csv(options.eventlogfile)
  259.     elif options.evtx:
  260.         sessions = import_xml(options.eventlogfile)
  261.     else:
  262.         Parser.error("You must specify a file format format (csv or xml)")
  263.  
  264.     timeline = sessions2timeline(sessions)
  265.  
  266.     print "[*] Mapped %s sessions from %s to %s" % (len(timeline['items']), timeline['time_begin'], timeline['time_end'])
  267.  
  268.  
  269.     js = open('timeline/evtdata.js','w+')
  270.  
  271.     js.write("var lanes = %s,\n" % str(timeline['lanes']))
  272.     js.write("laneLength = lanes.length,\n")
  273.     js.write("items = %s,\n" % timeline['items'])
  274.     js.write("timeBegin = \'%s\',\n" % timeline['time_begin'])
  275.     js.write("timeEnd = \'%s\',\n" % timeline['time_end'])
  276.     js.write("filename = \'%s\';\n" % options.eventlogfile)
  277.  
  278.  
  279.     js.close()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement