Skip to content

Commit

Permalink
Version 1.2
Browse files Browse the repository at this point in the history
* Added new pattern for WSL Discovery
* Fixed bugs with TSAK
* Added DeviceGuard and Local Groups discovery to TSAK
  • Loading branch information
codefitz committed May 10, 2019
1 parent 44add1f commit 055bb00
Show file tree
Hide file tree
Showing 4 changed files with 373 additions and 226 deletions.
9 changes: 5 additions & 4 deletions tsak_license.tpl → traversys_License.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
tpl 1.15 module TSAKLicense;

metadata
__name:='Traversys Swiss Army Knife (TSAK)';
__name :='Traversys License';
origin :='Traversys';
description:='GPL 3.0 License File';
tree_path:='Traversys', 'Extensions', 'TSAK GPL License';
tree_path :='Traversys', 'Extensions', 'TSAK GPL License';
end metadata;

configuration gpl_license 1.0
Expand Down Expand Up @@ -688,5 +689,5 @@ configuration gpl_license 1.0
"""

"Accept License" accept_gpl := true;
end configuration;

end configuration;
245 changes: 245 additions & 0 deletions traversys_TSAK.tpl
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;
123 changes: 123 additions & 0 deletions traversys_WSL.tpl
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;
Loading

0 comments on commit 055bb00

Please sign in to comment.