-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added new pattern for WSL Discovery * Fixed bugs with TSAK * Added DeviceGuard and Local Groups discovery to TSAK
- Loading branch information
Showing
4 changed files
with
373 additions
and
226 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
// (C) 2019 Traversys Limited | ||
// Licensed under GPL-3.0-or-later | ||
|
||
tpl 1.15 module TSAK; | ||
|
||
metadata | ||
__name :='TPL Swiss Army Knife (TSAK)'; | ||
origin :='Traversys'; | ||
description:='Lots of additional discovery'; | ||
tree_path :='Traversys', 'Extensions', 'TSAK'; | ||
end metadata; | ||
|
||
from TSAKLicense import gpl_license 1.0; | ||
|
||
pattern TSAK_Host 1.2 | ||
""" | ||
Author: Wes Moskal-Fitzpatrick | ||
|
||
Get lots of useful additional data from Host systems. | ||
|
||
Change History: | ||
2019-04-23 1.0 WMF : Created. | ||
2019-04-24 1.1 WMF : Fixed ECA error caused by reg query failure with last_online. | ||
Fixed dn.result > dn.value. | ||
Updated Last Online to get registry key list. | ||
Fixed anaconda file parse. | ||
Added alternative commands for Linux DNS and Host uptime. | ||
Added License File. | ||
2019-05-08 1.2 WMF : Local Groups and Members powershell command. | ||
Fixed uptime typo. | ||
Added DeviceGuard policy capture. | ||
|
||
Troubleshooting Windows commands (remquery): | ||
1) Run cmd as Administrator | ||
2) psexec \\localhost -i -u "NT AUTHORITY\SYSTEM" cmd | ||
|
||
""" | ||
overview | ||
tags traversys, tsak; | ||
end overview; | ||
|
||
triggers | ||
on h:= Host created, confirmed; | ||
end triggers; | ||
|
||
body | ||
|
||
if gpl_license.accept_gpl = false then | ||
stop; | ||
end if; | ||
|
||
if h.os_type = "Windows" then | ||
|
||
// Get Device LDAP Details | ||
dn := discovery.registryKey(h, raw "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Distinguished-Name"); | ||
if dn and dn.value then | ||
h.tsak_distinguished_name := dn.value; | ||
end if; | ||
|
||
// Get Installation, Last Boot | ||
boot := discovery.wmiQuery(h, 'SELECT InstallDate, LastBootUpTime FROM Win32_OperatingSystem', 'root\CIMV2'); | ||
if boot then | ||
h.tsak_install_date := boot[0].InstallDate; | ||
h.tsak_last_boot := boot[0].LastBootUpTime; | ||
end if; | ||
|
||
// Get Build Date | ||
build := discovery.runCommand(h, 'systeminfo | find /i "date"'); | ||
if build and build.result then | ||
h.tsak_build_date := build.result; | ||
end if; | ||
|
||
// Get DNS Servers | ||
dns := discovery.wmiQuery(h, 'SELECT DNSServerSearchOrder FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled=1', 'root\CIMV2'); | ||
if dns then | ||
h.tsak_dns_servers := dns[0].DNSServerSearchOrder; | ||
end if; | ||
|
||
// Get BIOS Version | ||
bios := discovery.wmiQuery(h, 'SELECT SMBIOSBIOSVersion FROM Win32_BIOS', 'root\CIMV2'); | ||
if bios then | ||
h.tsak_bios_version := bios[0].SMBIOSBIOSVersion; | ||
end if; | ||
|
||
// Windows System Info | ||
sysinfo := discovery.runCommand(h, 'systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"OS Manufacturer"'); | ||
if sysinfo and sysinfo.result then | ||
h.tsak_sysinfo := sysinfo.result; | ||
end if; | ||
|
||
// Alternative OS Lookup | ||
productName := discovery.registryKey(h, raw "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName"); | ||
releaseId := discovery.registryKey(h, raw "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ReleaseId"); | ||
if productName and productName.value then | ||
h.tsak_os := productName.value; | ||
end if; | ||
if releaseId and releaseId.value then | ||
h.tsak_os_release := releaseId.value; | ||
end if; | ||
|
||
// Last Patch Info | ||
lastPatchPs := discovery.runCommand(h, | ||
"powershell \"Get-HotFix | sort InstalledOn -Descending | select HotFixID, @{Name='Installed'; Expression={'{0:dd MMMM yyyy}' -f [datetime]$_.InstalledOn.Tostring()}} -First 1\"" | ||
); | ||
lastPatchReg := discovery.registryKey(h, raw "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Install\LastSuccessTime"); | ||
lastOnlineList := discovery.listRegistry(h, raw "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\LastOnlineScanTimeForAppCategory"); | ||
if lastPatchPs and lastPatchPs.result then | ||
h.tsak_last_patch := lastPatchPs.result; | ||
elif lastPatchReg and lastPatchReg.value then | ||
h.tsak_last_patch := lastPatchReg.value; | ||
elif lastOnlineList then | ||
for key in lastOnlineList do | ||
lastOnline := discovery.registryKey(h, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update\\LastOnlineScanTimeForAppCategory\\%key%"); | ||
if lastOnline and lastOnline[0].value then | ||
h.tsak_last_online := lastOnline[0].value; | ||
end if; | ||
end for; | ||
end if; | ||
|
||
// Logged Users | ||
users := discovery.wmiQuery(h, 'select LastLogon, Name, UserType from Win32_NetworkLoginProfile', 'root\CIMV2'); | ||
loggedUsers := []; | ||
for row in users do | ||
user := "%row.Name%, %row.LastLogon%"; | ||
list.append(loggedUsers, user); | ||
end for; | ||
h.tsak_logged_users := loggedUsers; | ||
|
||
// Registered Owner | ||
regOwner := discovery.registryKey(h, raw "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\RegisteredOwner"); | ||
if regOwner and regOwner.value then | ||
h.tsak_registered_owner := regOwner.value; | ||
end if; | ||
|
||
// Get Groups and Members | ||
psGroups := discovery.runCommand(h, | ||
//'powershell "foreach ($LocalGroup in Get-LocalGroup){ Get-LocalGroupMember $LocalGroup -ErrorAction SilentlyContinue | select $LocalGroup.name, Name | convertTo-Json}"' | ||
//'powershell "Get-LocalGroup"' | ||
//'powershell "Get-LocalGroup | foreach { $_.Name }"' | ||
'powershell "Get-LocalGroup | foreach { Get-LocalGroupMember $_.Name -ErrorAction SilentlyContinue | select $_.Name, Name | Write-Host }"' | ||
); | ||
if psGroups and psGroups.result then | ||
groups:= regex.extractAll(psGroups.result, regex "@\{(.*?)=;\sName=(.*?)}"); | ||
log.debug("Groups = %groups%"); | ||
h.tsak_group_membership:= groups; | ||
end if; | ||
|
||
deviceGuard := discovery.runCommand(h, 'powershell "get-cipolicyinfo"'); | ||
if deviceGuard and deviceGuard.result then | ||
h.tsak_device_guard:= deviceGuard.result; | ||
end if; | ||
|
||
else // Non-Windows | ||
|
||
// Get DNS Servers | ||
dns := discovery.runCommand(h, "nmcli dev show | grep DNS"); | ||
if dns and dns.result then | ||
if dns.result matches "Error:" then | ||
dns := discovery.runCommand(h, "cat /etc/resolv.conf | grep 'nameserver'"); | ||
end if; | ||
h.tsak_dns_servers := dns.result; | ||
end if; | ||
|
||
// Get Host Uptime | ||
up := discovery.runCommand(h, "uptime -p"); | ||
if up and up.result matches "usage:" then | ||
up := discovery.runCommand(h, "uptime"); | ||
end if; | ||
h.tsak_uptime := up.result; | ||
|
||
// Last Reboot | ||
lastBoot := discovery.runCommand(h, "who -b"); | ||
if lastBoot and lastBoot.result then | ||
h.tsak_last_boot := lastBoot.result; | ||
end if; | ||
|
||
// Get Build Date | ||
build:= none; | ||
anacondaFile := discovery.runCommand(h, 'ls -ld --time-style=long-iso /var/log/anaconda 2> /dev/null || ls -ld --time-style=long-iso /var/log/installer 2> /dev/null'); | ||
if anacondaFile and anacondaFile.result then | ||
buildDate:= regex.extract(anacondaFile.result, regex "(\d{4}-\d+-\d+\s\d+:\d+)", raw "\1", no_match:= anacondaFile.result); | ||
h.tsak_build_date := buildDate; | ||
end if; | ||
if h.os_type matches "AIX" then | ||
build := discovery.runCommand(h, 'lslpp -h | grep -p bos.rte'); | ||
elif h.os_type matches "Solaris" then | ||
build := discovery.runCommand(h, 'pkg info kernel'); | ||
elif h.os_type matches "HP-UX" then | ||
build := discovery.runCommand(h, '/opt/ignite/bin/print_manifest | more'); | ||
end if; | ||
if build and build.result then | ||
h.tsak_build_date := build.result; | ||
end if; | ||
|
||
end if; | ||
|
||
end body; | ||
|
||
end pattern; | ||
|
||
|
||
pattern TSAK_UID 1.1 | ||
""" | ||
Author: Wes Moskal-Fitzpatrick | ||
|
||
Pattern for correcting usernames is set to UID. | ||
|
||
Change History: | ||
2019-04-23 1.0 WMF : Created. | ||
2019-04-24 1.0 WMF : Fixed ECA error for UID. | ||
|
||
""" | ||
|
||
overview | ||
tags traversys, tsak; | ||
end overview; | ||
|
||
triggers | ||
on p:= DiscoveredProcess where username = none or username matches regex "^\d+$"; | ||
end triggers; | ||
|
||
body | ||
|
||
if gpl_license.accept_gpl = false then | ||
stop; | ||
end if; | ||
|
||
if text.toNumber(p.username) = p.uid then | ||
da := discovery.access(p); | ||
if da.device_summary has subword "Windows" then | ||
// Skip | ||
stop; | ||
else | ||
pwd := discovery.fileGet(da, "/etc/passwd"); | ||
if pwd and pwd.content then | ||
rx := raw "(\w+):x:" + p.username + ":"; | ||
uid := regex.extract(pwd.content, rx, raw "\1", no_match:= p.username); | ||
p.tsak_username := uid; | ||
end if; | ||
end if; | ||
end if; | ||
|
||
end body; | ||
|
||
end pattern; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// (C) 2019 Traversys Limited | ||
// Licensed under GPL-3.0-or-later | ||
|
||
tpl 1.15 module WSL; | ||
|
||
metadata | ||
__name :='Windows Subsystem for Linux'; | ||
origin :='Traversys'; | ||
description:='Windows Subsystem for Linux'; | ||
tree_path :='Traversys', 'Software', 'WSL'; | ||
end metadata; | ||
|
||
from TSAKLicense import gpl_license 1.0; | ||
|
||
pattern WSL 1.0 | ||
|
||
""" | ||
Author: Wes Moskal-Fitzpatrick | ||
|
||
Models the Windows Subsystem for Linux as a RuntimeEnviroment. | ||
infers additional SoftwareInstance if the Linux Distro is running. | ||
|
||
WSL runs under user/administrator. Commands will not run as system user | ||
so this is recognition only. | ||
|
||
Change History: | ||
2019-05-06 1.0 WMF : Created. | ||
|
||
""" | ||
|
||
overview | ||
tags traversys, wsl, windows, subsystem, linux; | ||
end overview; | ||
|
||
constants | ||
type := "Windows Subsystem for Linux"; | ||
ls_type := "Linux Kernel (WSL)"; | ||
end constants; | ||
|
||
triggers | ||
on p:= DiscoveredProcess where cmd matches windows_cmd "wslhost"; | ||
end triggers; | ||
|
||
body | ||
if gpl_license.accept_gpl = false then | ||
stop; | ||
end if; | ||
|
||
host := model.host(p); | ||
instance:= regex.extract(p.args, regex "\{(\S+)\}", raw "\1"); | ||
|
||
rte := model.RuntimeEnvironment( | ||
key := instance, | ||
type := type, | ||
name := "%type% on %host.name%", | ||
instance := text.lower(instance), | ||
_traversys:= true | ||
); | ||
|
||
childs:= discovery.descendents(p); | ||
for child in childs do | ||
inference.associate(rte, child); | ||
end for; | ||
|
||
parent:= discovery.parent(p); | ||
inference.associate(rte, parent); | ||
linuxDistro:= discovery.parent(parent); | ||
|
||
if linuxDistro then | ||
|
||
path := linuxDistro.cmd; | ||
rte.path := linuxDistro.cmd; | ||
|
||
kernel := none; | ||
version := none; | ||
prVersion := none; | ||
distro := none; | ||
|
||
name := "%ls_type% on %host.name%"; | ||
|
||
|
||
kernelBin := regex.extract(path, regex "\\.+\\(.+)\.exe$", raw "\1"); | ||
if kernelBin then | ||
log.debug("Kernal Binary: %kernelBin%"); | ||
// This code won't work because WSL won't run as system user | ||
kernelCmd := discovery.runCommand(host, '"%path%" -c uname -r'); | ||
if kernelCmd and kernelCmd.result then | ||
kernel := kernelCmd.result; | ||
end if; | ||
release := discovery.runCommand(host, '"%path%" -c cat /etc/*-release'); | ||
if release and release.result then | ||
version := regex.extract(release.result, regex 'VERSION="(.*)"', raw '\1'); | ||
distro := regex.extract(release.result, regex 'PRETTY_NAME="(.*)"', raw '\1'); | ||
if distro then | ||
name:= "%distro% (WSL) on %host.name%"; | ||
end if; | ||
else | ||
// Use the binary name as identifier | ||
distro := kernelBin; | ||
name:= "%ls_type% (%distro%) on %host.name%"; | ||
end if; | ||
end if; | ||
|
||
prVersion := regex.extract(version, regex '^(\d+(?:\.\d+)?)', raw '\1', no_match := version); | ||
|
||
si:= model.SoftwareInstance( | ||
key := instance, | ||
type := ls_type, | ||
name := name, | ||
instance := text.lower(instance), | ||
kernel := kernel, | ||
path := path, | ||
distribution := distro, | ||
version := version, | ||
product_version := prVersion, | ||
_traversys := true | ||
); | ||
|
||
end if; | ||
|
||
end body; | ||
|
||
end pattern; |
Oops, something went wrong.