sleat-parse.py
- Python script for parsing output from python-evtx
If sleat-collect.ps1 was used to generate the CSV file, then this step can be skipped.
If the Security.evtx log was copied off the Windows host (usually found at C:\Windows\System32\winevt\Logs\Security.evtx), then the first step in parsing it locally is to convert it from the proprietary binary XML format into an ASCII XML format. This can be done with python-evtx:root@kali:~# git clone https://github.com/williballenthin/python-evtx.git
Cloning into 'python-evtx'...
remote: Counting objects: 896, done.
remote: Total 896 (delta 0), reused 0 (delta 0), pack-reused 896
Receiving objects: 100% (896/896), 2.69 MiB | 0 bytes/s, done.
Resolving deltas: 100% (469/469), done.
Checking connectivity... done.
root@kali:~# ll
total 336988
drwxr-xr-x 6 root root 4096 Feb 4 12:33 python-evtx
-rw-r--r-- 1 root root 314576896 Feb 4 07:21 Security.evtx
root@kali:~# python python-evtx/scripts/evtxdump.py Security.evtx > CORPDOM-dump.xml
Once the data has been converted to ASCII XML, the relevant fields need to be pulled from the Logon events. This can be done by sleat-parse.py:$ python sleat-parse.py -h
Usage: sleat-parse.py INFILE [-o OUTFILE]
An XML parser for output generated by python-evtx. Parses input XML file and pulls fields related to Logon events (EventID 4624).
Sorts and removes duplicates records. By default writes output to 'logons.csv' in current working directory unless -o option is specified.
Output format:
IpAddress,TargetDomainName,TargetUserName,WorkstationName
Examples:
sleat-parse.py CORP-dump.xml
sleat-parse.py CORP-dump.xml -o CORP-logons.csv
Type -h or --help for a full listing of options.
Options:
-h, --help show this help message and exit
-o OUTFILE Write output to OUTFILE. If this option is not specified, then
will write output to 'logons.csv' by default in the current
working directory.
Using sleat-parse.py to generate ‘CORPDOM-logons.csv’ from ‘CORPDOM-dump.xml’:$ python sleat-parse.py CORPDOM-dump.xml -o CORPDOM-logons.csv
Output file: CORPDOM-logons.csv
The resulting CSV file can then be passed to sleat-analyze.rb.
sleat-analyze.rb
- Ruby script for validating scope, identifying locations of privileged users, building graphs of logon relationships, and more.$ ruby sleat-analyze.rb -h
Usage: sleat-analyze.rb [options] <logons.csv> <corp networks> <cde networks>
logons.csv - a CSV produced by sleat-collect.ps1 or sleat-parse.py
corp networks - newline-delimited file of networks in corporate scope with CIDR notation (ex: 10.5.1.0/24)
cde networks - newline-delimited file of networks in CDE scope with CIDR notation (ex: 172.16.10.0/24)
Example usage
-------------
Show scope and user for all logon events (default):
sleat-analyze.rb logons.csv corp-vlans.txt cde-vlans.txt
Filter out all corporate hosts:
sleat-analyze.rb -c logons.csv corp-vlans.txt cde-vlans.txt
Filter out all machine accounts and exclude domain\user from output:
sleat-analyze.rb -mu logons.csv corp-vlans.txt cde-vlans.txt
Show logons performed by privileged users:
sleat-analyze.rb -p privusers.txt logons.csv corp-vlans.txt cde-vlans.txt
Show logons performed by privileged users only from the CDE:
sleat-analyze.rb -cnp privusers.txt logons.csv corp-vlans.txt cde-vlans.txt
-p privUsersFile File containing newline-delimited list of privileged users. Will only show results for privileged users.
-u Filter out domain\username from output
-m Filter out machine accounts (ex: WIN7-BOB$)
-n Filter out hosts not in scope
-c Filter out hosts in corp
-d Filter out hosts in CDE
-h, --help Displays help
By default, the script shows a fully verbose dump:$ ruby sleat-analyze.rb CORPDOM-logons.csv corp-vlans.txt cde-vlans.txt
Corp: 10.10.10.130 - CORPDOM\ORSK01$
Corp: 10.10.10.131 - CORPDOM\ORSK02$
Corp: 10.10.10.132 - CORPDOM\ORSKQ01$
Corp: 10.10.10.139 - CORPDOM\SKLEP01$
Corp: 10.10.10.140 - CORPDOM\LPND01$
Corp: 10.10.10.173 - CORPDOM\ESX01$
Corp: 10.10.10.192 - CORPDOM\PSS2$
Corp: 10.10.10.222 - CORPDOM\EFCT01$
CDE: 10.10.200.153 - CORPDOM\atlfosvc
CDE: 10.10.202.71 - CORPDOM\PBBCDB$
CDE: 10.10.202.73 - CORPDOM\cjones
Out: 10.10.21.16 - CORPDOM\ajones
Out: 10.10.21.17 - CORPDOM\ATL-EYJR$
Out: 10.10.21.17 - CORPDOM\eyjr
Out: 10.10.21.18 - CORPDOM\mgiles
Out: 10.10.21.18 - CORPDOM\ATL-mgiles$
<snipped>
Out: 10.9.66.38 - CORPDOM\gmaddux
Out: 10.9.66.64 - CORPDOM\GWI-AAA$
Out: 10.9.86.15 - CORPDOM\kmillwood
Out: 172.16.0.133 - CORPDOM\MIS-AA$
Corp: 208.31.22.10 - CORPDOM\atlfosvc
Counts:
CDE: 13
Corp: 314
Out of scope: 449
Run: neato -T png -O inscope.dot && neato -T png -O outscope.dot
This output can be filtered using various options. For example, filtering out corporate hosts:$ ruby sleat-analyze.rb -c CORPDOM-logons.csv corp-vlans.txt cde-vlans.txt
CDE: 10.10.200.153 - CORPDOM\atlfosvc
CDE: 10.10.202.71 - CORPDOM\PBBCDB$
CDE: 10.10.202.73 - CORPDOM\cjones
Out: 10.10.21.16 - CORPDOM\ajones
Out: 10.10.21.17 - CORPDOM\ATL-EYJR$
Out: 10.10.21.17 - CORPDOM\eyjr
Out: 10.10.21.18 - CORPDOM\mgiles
Out: 10.10.21.18 - CORPDOM\ATL-mgiles$
<snipped>
Out: 10.9.66.38 - CORPDOM\gmaddux
Out: 10.9.66.64 - CORPDOM\GWI-AAA$
Out: 10.9.86.15 - CORPDOM\dfodbmdbv
Out: 172.16.0.133 - CORPDOM\MIS-AA$
Corp: 208.31.22.10 - CORPDOM\atlfosvc
Counts:
CDE: 13
Corp: 0
Out of scope: 449
Run: neato -T png -O inscope.dot && neato -T png -O outscope.dot
Filtering out machine accounts and domain\username from output:$ ruby sleat-analyze.rb -mu CORPDOM-logons.csv corp-vlans.txt cde-vlans.txt
CDE: 10.10.200.153
CDE: 10.10.200.153
CDE: 10.10.202.73
Out: 10.10.21.16
Out: 10.10.21.17
Out: 10.10.21.18
Out: 10.10.21.24
Out: 10.10.21.25
Out: 10.10.21.26
Out: 10.10.21.29
Out: 10.10.21.30
Out: 10.10.21.30
<snipped>
Out: 10.9.44.35
Out: 10.9.66.38
Out: 10.9.86.15
Corp: 208.31.22.10
Counts:
CDE: 12
Corp: 166
Out of scope: 290
Run: neato -T png -O inscope.dot && neato -T png -O outscope.dot
Instead of finding hosts based on their scope, you may want to find hosts that belong to a privileged user. Let’s say a list of privileged users resides in a file named privusers.txt:$ cat privusers.txt
CORPDOM\adback
CORPDOM\a_ffreeman
CORPDOM\a_oalbies
CORPDOM\a_dswanson
CORPDOM\a_ariley
CORPDOM\a_msmith
CORPDOM\a_einciarte
CORPDOM\a_jteheran
This file can be passed with the -p option to only show logons for these users (domain names are ignored - this may help find accounts with the same name across different domains):$ ruby sleat-analyze.rb -p privusers.txt CORPDOM-logons.csv corp-vlans.txt cde-vlans.txt
Corp: 10.10.6.161 - CORPDOM\a_ffreeman
Corp: 10.10.6.161 - CORPDOM\a_jteheran
Corp: 10.10.6.161 - CORPDOM\a_oalbies
Corp: 10.10.6.161 - CORPDOM\a_msmith
Corp: 10.10.6.43 - CORPDOM\a_ffreeman
Counts:
CDE: 0
Corp: 5
Out of scope: 0
Run: neato -T png -O inscope.dot && neato -T png -O outscope.dot
Each time the script is ran, two files are generated: inscope.dot and outscope.dot. The reminder at the end of the output shows an example of how to render these dot files into a visual graph using neato. The contents of the dot files will only contain the results from the latest sleat-analyze.rb output.
Example output of inscope.dot.png. Red nodes indicate CDE networks, light green nodes indicate corporate networks: