From a79ab385730283cdd4a479bd1ad90a50269ea104 Mon Sep 17 00:00:00 2001 From: Wes Moskal-Fitzpatrick Date: Mon, 10 Jun 2019 17:23:10 +0100 Subject: [PATCH] Version 1.4 Updated BAIs pattern to limit to elements with SI comms. Added NetworkDevice edge connectivity pattern (PoC) Added Win2k8 fix to TSAK and fixed some ECA errors. --- traversys_BAIs.tpl | 74 +++++++------- traversys_ND_Edge_Connectivity_POC.tpl | 61 ++++++++++++ traversys_TSAK.tpl | 127 ++++++++++++++++++++----- traversys_Win2k8Fix.tpl | 70 -------------- 4 files changed, 205 insertions(+), 127 deletions(-) create mode 100644 traversys_ND_Edge_Connectivity_POC.tpl delete mode 100644 traversys_Win2k8Fix.tpl diff --git a/traversys_BAIs.tpl b/traversys_BAIs.tpl index 6d2cc69..cc2c91f 100644 --- a/traversys_BAIs.tpl +++ b/traversys_BAIs.tpl @@ -19,7 +19,7 @@ configuration ignore 1.0 end configuration; -pattern WebsiteBAIs 1.0 +pattern WebsiteBAIs 1.1 """ Author: Wes Moskal-Fitzpatrick @@ -28,6 +28,7 @@ pattern WebsiteBAIs 1.0 Change History: 2019-05-25 1.0 WMF : Created. + 2019-06-04 1.1 WMF : Added conditional to limit BAI creation only if communicating SIs is discovered. """ @@ -57,40 +58,47 @@ pattern WebsiteBAIs 1.0 name := "%sc.instance% %type%"; key := text.hash(instance); - bai := model.BusinessApplicationInstance( - key := key, - type := type, - name := name, - instance := sc.instance, - _traversys:= true - ); - // ContainedSoftware:SoftwareContainment:SoftwareContainer:BusinessApplicationInstance - model.addContainment(bai, sc); - containing_sis := search(in sc traverse ContainedSoftware:SoftwareContainment:SoftwareContainer:SoftwareInstance); - model.addContainment(bai, containing_sis); - outgoing_sis := search(in containing_sis traverse Connecting:ObservedCommunication:Listening:SoftwareInstance); - model.addContainment(bai, outgoing_sis); - // Some of these will be DB servers, but the SIDs can vary so we can add the DB server and try to work it out manually. - databases := search(in outgoing_sis traverse ElementWithDetail:Detail:Detail:Database where lower(instance) = %instance%); - // Dependant:Dependency:DependedUpon:Database - model.rel.Dependency(Dependant := bai, DependedUpon := databases); - - si_dependencies:= search(in containing_sis traverse Dependant:Dependency:DependedUpon:SoftwareInstance); - model.addContainment(bai, si_dependencies); - - si_containers := search(in containing_sis traverse ContainedSoftware:SoftwareContainment:SoftwareContainer:SoftwareInstance); - model.addContainment(bai, si_containers); - - lb_members := search(in containing_sis traverse ServiceProvider:SoftwareService:Service:LoadBalancerMember); - lb_pools := search(in lb_members traverse ContainedMember:Containment:Container:LoadBalancerPool where lower(name) = "%instance%"); - lb_services := search(in lb_pools traverse ContainedPool:Containment:Container:LoadBalancerService); - model.addContainment(bai, lb_services); - - //lb_instances := search(in lb_pools traverse ContainedPool:Containment:Container:LoadBalancerInstance); - //lb_failover := search(in lb_instances traverse ContainedInstance:Containment:Container:LoadBalancerGroup - // traverse Container:Containment:ContainedInstance:LoadBalancerInstance where failover_state = "Standby"); + + // Create only a BAI if there is a communicating SI - in this way we + // try to model something that looks like like a genuine BAI + if size(outgoing_sis) > 0 then + + bai := model.BusinessApplicationInstance( + key := key, + type := type, + name := name, + instance := sc.instance, + _traversys:= true + ); + // ContainedSoftware:SoftwareContainment:SoftwareContainer:BusinessApplicationInstance + model.addContainment(bai, sc); + model.addContainment(bai, containing_sis); + model.addContainment(bai, outgoing_sis); + + // Some of these will be DB servers, but the SIDs can vary so we can add the DB server and try to work it out manually. + databases := search(in outgoing_sis traverse ElementWithDetail:Detail:Detail:Database where lower(instance) = %instance%); + + // Dependant:Dependency:DependedUpon:Database + model.rel.Dependency(Dependant := bai, DependedUpon := databases); + + si_dependencies:= search(in containing_sis traverse Dependant:Dependency:DependedUpon:SoftwareInstance); + model.addContainment(bai, si_dependencies); + + si_containers := search(in containing_sis traverse ContainedSoftware:SoftwareContainment:SoftwareContainer:SoftwareInstance); + model.addContainment(bai, si_containers); + + lb_members := search(in containing_sis traverse ServiceProvider:SoftwareService:Service:LoadBalancerMember); + lb_pools := search(in lb_members traverse ContainedMember:Containment:Container:LoadBalancerPool where lower(name) = "%instance%"); + lb_services := search(in lb_pools traverse ContainedPool:Containment:Container:LoadBalancerService); + model.addContainment(bai, lb_services); + + //lb_instances := search(in lb_pools traverse ContainedPool:Containment:Container:LoadBalancerInstance); + //lb_failover := search(in lb_instances traverse ContainedInstance:Containment:Container:LoadBalancerGroup + // traverse Container:Containment:ContainedInstance:LoadBalancerInstance where failover_state = "Standby"); + + end if; end body; diff --git a/traversys_ND_Edge_Connectivity_POC.tpl b/traversys_ND_Edge_Connectivity_POC.tpl new file mode 100644 index 0000000..e4b95e6 --- /dev/null +++ b/traversys_ND_Edge_Connectivity_POC.tpl @@ -0,0 +1,61 @@ +// (C) 2019 Traversys Limited +// Licensed under GPL-3.0-or-later + +tpl 1.15 module ndEdgeConnectivity; + +metadata + __name :='NetworkDevice Edge Connectivity PoC'; + origin :='Traversys'; + description:='Proof of Concept for Network Device Edge Connectivity'; + tree_path :='Traversys', 'Extensions', 'ND Edge Connectivity'; +end metadata; + +from TSAKLicense import gpl_license 1.0; + +pattern ndEdgeConnectivity 1.0 + + """ + Author: Wes Moskal-Fitzpatrick + + Proof of Concept for 2 random network devices selected in BMC's Demo Appliance. + + Change History: + 2019-06-09 1.0 WMF : Created. + + """ + + overview + tags traversys, NetworkDevice, edge; + end overview; + + triggers + on nd:= NetworkDevice created, confirmed where name = "swd77"; + end triggers; + + body + if gpl_license.accept_gpl = false then + stop; + end if; + + interfaces:= search(in nd traverse DeviceWithInterface:DeviceInterface:InterfaceOfDevice:NetworkInterface where interface_name = "fc0"); + + if size(interfaces) > 0 then + interface:= interfaces[0]; + log.debug("Interface of %nd.name% = %interface.name%"); + edgeDevices:= search(NetworkDevice where name = "ais-saas-f5.calbro.com"); + if size(edgeDevices) > 0 then + edgeDevice:= edgeDevices[0]; + log.debug("Edge Device = %edgeDevice.name%"); + edgeIfaces:= search(in edgeDevice traverse DeviceWithInterface:DeviceInterface:InterfaceOfDevice:NetworkInterface where interface_name = "external"); + if size(edgeIfaces) > 0 then + edgeIface:= edgeIfaces[0]; + log.debug("Linking Interface %interface.name% to Edge Interface %edgeIface.name%..."); + // EdgeDevice:NetworkLink:EdgeClient:NetworkInterface + model.rel.NetworkLink(EdgeDevice := interface, EdgeClient := edgeIface); + end if; + end if; + end if; + + end body; + +end pattern; diff --git a/traversys_TSAK.tpl b/traversys_TSAK.tpl index 29d0ff9..26b009d 100644 --- a/traversys_TSAK.tpl +++ b/traversys_TSAK.tpl @@ -12,7 +12,7 @@ end metadata; from TSAKLicense import gpl_license 1.0; -pattern TSAK_Host 1.2 +pattern TSAK_Host 1.3 """ Author: Wes Moskal-Fitzpatrick @@ -29,6 +29,9 @@ pattern TSAK_Host 1.2 2019-05-08 1.2 WMF : Local Groups and Members powershell command. Fixed uptime typo. Added DeviceGuard policy capture. + 2019-06-04 1.3 WMF : Fixed ECA error in Linux uptime query. + Fixed ECA error with Windows users wmi query. + Updated local groups command with alternative methods. Troubleshooting Windows commands (remquery): 1) Run cmd as Administrator @@ -118,34 +121,52 @@ pattern TSAK_Host 1.2 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; + users := discovery.wmiQuery(h, 'select LastLogon, Name, UserType from Win32_NetworkLoginProfile', 'root\CIMV2'); + loggedUsers := []; + if users then + for row in users do + user:= "%row.Name%, %row.LastLogon%"; + list.append(loggedUsers, user); + end for; + h.tsak_logged_users:= loggedUsers; + end if; // Registered Owner - regOwner := discovery.registryKey(h, raw "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\RegisteredOwner"); + 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"'); + ngCmd:= raw '''FOR /F "skip=4 tokens=*" %i IN ('net localgroup') DO @echo %i'''; + groupMembers:= []; + netGroups := discovery.runCommand(h, ngCmd); + if netGroups and netGroups.result then + groups:= regex.extractAll(netGroups.result, regex "\*(.*)"); + for group in groups do + // FOR /F "skip=6 tokens=*" %i IN ('net localgroup administrators ^| findstr /vb "The command completed successfully."') DO @echo %i + ngGroupCmd:= raw '''FOR /F "skip=6 tokens=*" %i IN ('net localgroup "''' + text.rightStrip(group) + raw '''" ^| findstr /vb "The command completed successfully."') DO @echo %i'''; + users:= discovery.runCommand(h, ngGroupCmd); + end for; + else + psGroups := discovery.runCommand(h, + raw '%windir%\System32\WindowsPowerShell\v1.0\powershell.exe "Get-LocalGroup | foreach { Get-LocalGroupMember $_.Name -ErrorAction SilentlyContinue | select $_.Name, Name | Write-Host }"' + //'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 }"' + ); + if psGroups and psGroups.result then + groups:= regex.extractAll(psGroups.result, regex "@\{(.*?)=;\sName=(.*?)}"); + log.debug("Groups = %groups%"); + for group in groups do + log.debug("User / Group = %group%"); + list.append(groupMembers, group); + end for; + h.tsak_group_membership:= groupMembers; + end if; + end if; + + deviceGuard := discovery.runCommand(h, 'powershell "get-cipolicyinfo"'); if deviceGuard and deviceGuard.result then h.tsak_device_guard:= deviceGuard.result; end if; @@ -164,9 +185,9 @@ pattern TSAK_Host 1.2 // Get Host Uptime up := discovery.runCommand(h, "uptime -p"); if up and up.result matches "usage:" then - up := discovery.runCommand(h, "uptime"); + up := discovery.runCommand(h, "uptime"); + h.tsak_uptime := up.result; end if; - h.tsak_uptime := up.result; // Last Reboot lastBoot := discovery.runCommand(h, "who -b"); @@ -243,3 +264,61 @@ pattern TSAK_UID 1.1 end body; end pattern; + + +pattern Win7_2008Fix 1.0 + """ + This pattern fixes Windows Version 6.1.7601 which stands for both Windows 7 and Windows 2008 R2. + If WMI and RemQuery fails - then the OS name string is not returned. + + Change History: + 2018-05-01 1.0 WMF : Created. + + Validation Query: + search Host where os = 'Microsoft Windows [Version 6.1.7601]' + show name, type, os_version, os, age_count, #:::DiscoveryAccess.#:::DeviceInfo.os + + """ + + overview + tags Windows, Traversys; + end overview; + + triggers + on h:= Host created, confirmed where os = "Microsoft Windows [Version 6.1.7601]"; + end triggers; + + body + + if gpl_license.accept_gpl = false then + stop; + end if; + + sysInfo := discovery.runCommand(h, 'systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"OS Manufacturer"'); + regProductName := discovery.registryKey(h, raw "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName"); + + reqList := discovery.listRegistry(h, raw "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion"); + regReleaseId := discovery.registryKey(h, raw "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ReleaseId"); + + hOS:= h.os; + + if sysInfo and sysInfo.result then + hOS:= regex.extract(sysInfo.result, regex "OS Name:\s+(.*)", raw "\1"); + h.os_version:= regex.extract(hOS, regex "Microsoft Windows (.*) (Enterprise|Standard)", raw "\1", no_match:= hOS); + h.os_edition:= regex.extract(hOS, regex "Microsoft Windows (.*) (Enterprise|Standard)", raw "\2", no_match:= hOS); + elif regProductName and regProductName.value then + hOS:= regProductName.value; + h.os:= hOS; + h.os_version:= regex.extract(hOS, regex "Windows (.*) (Enterprise|Standard)", raw "\1", no_match:= hOS); + h.os_edition:= regex.extract(hOS, regex "Windows (.*) (Enterprise|Standard)", raw "\2", no_match:= hOS); + end if; + + if hOS matches "Windows 7" then + h.host_type:= "Windows Desktop"; + h.type:= "Windows Desktop"; + h._os_modified:= true; + end if; + + end body; + +end pattern; diff --git a/traversys_Win2k8Fix.tpl b/traversys_Win2k8Fix.tpl deleted file mode 100644 index 3c94d2a..0000000 --- a/traversys_Win2k8Fix.tpl +++ /dev/null @@ -1,70 +0,0 @@ -// (C) 2019 Traversys Limited -// Licensed under GPL-3.0-or-later - -tpl 1.15 module Win7_2008Fix; - -metadata - __name :='Windows 7/2008 R2 Fix'; - origin :='Traversys'; - description:='Fixes the problem where Win 7 Desktop identifies as Win 2008 R2 on WMI failure (RemQuery)'; - tree_path :='Traversys', 'Extensions', 'Windows 7/2008 R2 Fix'; -end metadata; - -from TSAKLicense import gpl_license 1.0; - -pattern Win7_2008Fix 1.0 - """ - This pattern fixes Windows Version 6.1.7601 which stands for both Windows 7 and Windows 2008 R2. - If WMI and RemQuery fails - then the OS name string is not returned. - - Change History: - 2018-05-01 1.0 WMF : Created. - - Validation Query: - search Host where os = 'Microsoft Windows [Version 6.1.7601]' - show name, type, os_version, os, age_count, #:::DiscoveryAccess.#:::DeviceInfo.os - - """ - - overview - tags Windows, Traversys; - end overview; - - triggers - on h:= Host created, confirmed where os = "Microsoft Windows [Version 6.1.7601]"; - end triggers; - - body - - if gpl_license.accept_gpl = false then - stop; - end if; - - sysInfo := discovery.runCommand(h, 'systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"OS Manufacturer"'); - regProductName := discovery.registryKey(h, raw "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName"); - - reqList := discovery.listRegistry(h, raw "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion"); - regReleaseId := discovery.registryKey(h, raw "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ReleaseId"); - - hOS:= h.os; - - if sysInfo and sysInfo.result then - hOS:= regex.extract(sysInfo.result, regex "OS Name:\s+(.*)", raw "\1"); - h.os_version:= regex.extract(hOS, regex "Microsoft Windows (.*) (Enterprise|Standard)", raw "\1", no_match:= hOS); - h.os_edition:= regex.extract(hOS, regex "Microsoft Windows (.*) (Enterprise|Standard)", raw "\2", no_match:= hOS); - elif regProductName and regProductName.value then - hOS:= regProductName.value; - h.os:= hOS; - h.os_version:= regex.extract(hOS, regex "Windows (.*) (Enterprise|Standard)", raw "\1", no_match:= hOS); - h.os_edition:= regex.extract(hOS, regex "Windows (.*) (Enterprise|Standard)", raw "\2", no_match:= hOS); - end if; - - if hOS matches "Windows 7" then - h.host_type:= "Windows Desktop"; - h.type:= "Windows Desktop"; - h._os_modified:= true; - end if; - - end body; - -end pattern;