├── README.md ├── requirements.txt ├── result.png ├── search.png └── winevt_logs_analysis.py /README.md: -------------------------------------------------------------------------------- 1 | ## Winevt logs analysis (Remote connections) 2 | 3 | ### Simple script for the purpose of finding remote connections to Windows machine and ideally some public IPs. It checks for some EventIDs regarding remote logins and sessions. 4 | 5 | You should **pip install -r requirements.txt** so the script can work and parse some of the .evtx files inside winevt folder. 6 | 7 | The **winevt/Logs** folders and the script must have identical file path. 8 | 9 | ##### Execution Example ##### 10 | 11 | ![Image of Spreadsheet](https://github.com/georgi-i/winevt_logs_analysis/blob/main/search.png) 12 | 13 | ##### Result Example ##### 14 | 15 | ![Image of Spreadsheet](https://github.com/georgi-i/winevt_logs_analysis/blob/main/result.png) 16 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | alive_progress==2.4.1 2 | Evtx==0.7.3 3 | pandas==1.3.1 4 | -------------------------------------------------------------------------------- /result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgi-i/winevt_logs_analysis/f44e7594a4e171c1edb14962100f57649b8f8f8e/result.png -------------------------------------------------------------------------------- /search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgi-i/winevt_logs_analysis/f44e7594a4e171c1edb14962100f57649b8f8f8e/search.png -------------------------------------------------------------------------------- /winevt_logs_analysis.py: -------------------------------------------------------------------------------- 1 | 2 | #[\winevt\Logs\Microsoft-Windows-TerminalServices-RemoteConnectionManager%4Operational.evtx] 3 | #EventID 1149 - User authentication succeeded -> 2624 -> 21 -> 22 4 | 5 | #[\winevt\Logs\Security.evtx] 6 | #EventID 4624 - User successfully logged on to this system with the specified TargetUserName and TargetDomainName from the specified IpAddress 7 | #EventID 4625 - User failed to log on to this system with the specified TargetUserName and TargetDomainName from the specified IpAddress 8 | #EventID 4634 - A user disconnected from, or logged off, an RDP session 9 | #EventID 4647 - The user initiated a formal logoff 10 | #EventID 4778 - The user reconnected to an existing RDP session 11 | #EventID 4779 - The user disconnected from from an RDP session 12 | 13 | #[\winevt\Logs\Microsoft-Windows-TerminalServices-LocalSessionManager%4Operational.evtx] 14 | #EventID 21 - successful RDP logon (as long as Source Network Address is NOT local) 15 | #EventID 22 - successful RDP logon with GUI Desktop (as long as Source Network Address is NOT local) 16 | #EventID 23 - The user initiated a formal system logoff 17 | #EventID 24 - user has disconnected from an RDP session (if NOT local IP) 18 | #EventID 25 - user has reconnected to an existing RDP session (if NOT local IP) 19 | #EventID 39 - The user formally disconnected from the RDP session 20 | #EventID 40 - The user disconnected from or reconnected to an RDP session 21 | 22 | import Evtx.Evtx as evtx 23 | import re 24 | import pandas as pd 25 | from alive_progress import alive_bar 26 | 27 | def write_results(df): 28 | 29 | with open('result.html', 'a') as result: 30 | 31 | df['SystemTime'] = pd.to_datetime(df['SystemTime']) 32 | df = df.sort_values(by="SystemTime").reset_index(drop=True) 33 | 34 | df.to_html(result, header=result) 35 | result.write('
') 36 | 37 | 38 | 39 | def append_results(df, event_id, event_id_info, ip, sys_time, log_info): 40 | 41 | df = df._append({'EventID': event_id, 42 | 'Info': event_id_info, 43 | 'IP': ip, 44 | 'SystemTime': sys_time, 45 | 'Log': log_info}, 46 | ignore_index=True) 47 | 48 | return df 49 | 50 | 51 | 52 | def read_data(df, path, input): 53 | 54 | event_data = '' 55 | 56 | re_system_time = r'SystemTime=\"(.+)\.' 57 | 58 | re_rcm_id = r'>(1149)<\/EventID' 59 | re_ip_rcm = r'(.+)<' 60 | 61 | 62 | re_lsm_login = r'>(21)<\/EventID' 63 | re_lsm_login_gui = r'>(22)(24)<\/EventID' 65 | re_lsm_rec = r'>(25)<\/EventID' 66 | re_ip_lsm = r'Address>(\d+\.\d+\.\d+\.\d+)<' 67 | 68 | re_sec_login = r'>(4624)<\/EventID' 69 | re_sec_reconnect = r'>(4778)<\/EventID' 70 | re_sec_disconnect = r'>(4779)<\/EventID' 71 | re_ip_login = r'\"IpAddress\">(\d+\.\d+\.\d+\.\d+)<' 72 | re_ip_rec = r'\"ClientAddress\">(\d+\.\d+\.\d+\.\d+)<' 73 | 74 | print_rcm = False 75 | print_lsm = False 76 | print_security = False 77 | 78 | 79 | with evtx.Evtx(path) as log: 80 | records = log.records() 81 | with alive_bar(len(list(records))) as bar: 82 | for record in log.records(): 83 | bar() 84 | event_data = record.xml() 85 | match_sys_time = re.search(re_system_time, event_data) 86 | 87 | if input == 'rcm': 88 | 89 | if not print_rcm: 90 | print('Searching for matching events in RemoteConnectionManager logs...') 91 | print_rcm = True 92 | 93 | 94 | match_id_1149 = re.search(re_rcm_id, event_data) 95 | if match_id_1149 != None: 96 | 97 | match_ip_1149 = re.search(re_ip_rcm, event_data) 98 | 99 | df = append_results(df, 100 | match_id_1149.group(1), 101 | 'User authentication succeeded', 102 | match_ip_1149.group(1), 103 | match_sys_time.group(1), 104 | 'RemoteConnectionManager_Operational') 105 | 106 | 107 | elif input == 'lsm': 108 | 109 | if not print_lsm: 110 | print('Searching for matching events in LocalSessionManager logs...') 111 | print_lsm = True 112 | 113 | match_id_21 = re.search(re_lsm_login, event_data) 114 | match_id_22 = re.search(re_lsm_login_gui, event_data) 115 | match_id_24 = re.search(re_lsm_disc, event_data) 116 | match_id_25 = re.search(re_lsm_rec, event_data) 117 | match_ip_lsm = re.search(re_ip_lsm, event_data) 118 | 119 | if match_id_21 != None: 120 | 121 | if match_ip_lsm != None: 122 | df = append_results(df, 123 | match_id_21.group(1), 124 | 'successful RDP logon', 125 | match_ip_lsm.group(1), 126 | match_sys_time.group(1), 127 | 'LocalSessionManager_Operational') 128 | elif match_id_22 != None: 129 | 130 | if match_ip_lsm != None: 131 | df = append_results(df, 132 | match_id_22.group(1), 133 | 'successful RDP logon with GUI Desktop', 134 | match_ip_lsm.group(1), 135 | match_sys_time.group(1), 136 | 'LocalSessionManager_Operational') 137 | elif match_id_24 != None: 138 | 139 | if match_ip_lsm != None: 140 | df = append_results(df, 141 | match_id_24.group(1), 142 | 'user has disconnected from an RDP session', 143 | match_ip_lsm.group(1), 144 | match_sys_time.group(1), 145 | 'LocalSessionManager_Operational') 146 | elif match_id_25 != None: 147 | 148 | if match_ip_lsm != None: 149 | df = append_results(df, 150 | match_id_25.group(1), 151 | 'user has reconnected to an existing RDP session', 152 | match_ip_lsm.group(1), 153 | match_sys_time.group(1), 154 | 'LocalSessionManager_Operational') 155 | 156 | elif input == 'security': 157 | 158 | if not print_security: 159 | print('Searching for matching events in Security logs...This may take a while...') 160 | print_security = True 161 | 162 | match_id_4624 = re.search(re_sec_login, event_data) 163 | match_id_4778 = re.search(re_sec_reconnect, event_data) 164 | match_id_4779 = re.search(re_sec_disconnect, event_data) 165 | 166 | if match_id_4624 != None: 167 | 168 | match_ip_4624 = re.search(re_ip_login, event_data) 169 | if match_ip_4624 != None: 170 | df = append_results(df, match_id_4624.group(1), 171 | 'User successfully logged on', 172 | match_ip_4624.group(1), 173 | match_sys_time.group(1), 174 | 'Security') 175 | elif match_id_4778 != None: 176 | 177 | match_ip_4778 = re.search(re_ip_rec, event_data) 178 | if match_ip_4778 != None: 179 | df = append_results(df, 180 | match_id_4778.group(1), 181 | 'The user reconnected', 182 | match_ip_4778.group(1), 183 | match_sys_time.group(1), 184 | 'Security') 185 | elif match_id_4779 != None: 186 | 187 | match_ip_4779 = re.search(re_ip_rec, event_data) 188 | if match_ip_4779 != None: 189 | df = append_results(df, 190 | match_id_4779.group(1), 191 | 'The user disconnected', 192 | match_ip_4779.group(1), 193 | match_sys_time.group(1), 194 | 'Security') 195 | 196 | write_results(df) 197 | 198 | 199 | df = pd.DataFrame(columns=['EventID', 'Info', 'IP', 'SystemTime', 'Log']) 200 | 201 | path_prefix = 'winevt/Logs/' 202 | log_prefix = 'Microsoft-Windows-TerminalServices-' 203 | try: 204 | print('Reading data from RemoteConnectionManager%4Operational.evtx...') 205 | read_data(df, path_prefix + log_prefix + 'RemoteConnectionManager%4Operational.evtx', 'rcm') 206 | except: 207 | print('Failed to read RemoteConnectionManager%4Operational.evtx') 208 | try: 209 | print('Reading data from LocalSessionManager%4Operational.evtx...') 210 | read_data(df, path_prefix + log_prefix + 'LocalSessionManager%4Operational.evtx', 'lsm') 211 | except: 212 | print('Failed to read LocalSessionManager%4Operational.evtx') 213 | try: 214 | print('Reading data from Security.evtx...') 215 | read_data(df, path_prefix + 'Security.evtx', 'security') 216 | except: 217 | print('Failed to read Security.evtx') 218 | 219 | 220 | 221 | --------------------------------------------------------------------------------