├── 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 | 
12 |
13 | ##### Result Example #####
14 |
15 | 
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 |
--------------------------------------------------------------------------------