-
Notifications
You must be signed in to change notification settings - Fork 212
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
artifacts for identifying RMM tools on windows
uses LOLRMM data for identifying Remote Management and Monitoring (RMM) software on Windows systems
- Loading branch information
Showing
2 changed files
with
140 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
name: Server.Utils.LabelRMMs | ||
author: Herbert Bärschneider | ||
description: | | ||
This (server monitoring) artifact tags systems with the RMM tools present on them. | ||
The artifact is dependent on the artifact Windows.Detection.RMMs (found on the Artifact Exchange) | ||
After activating this monitoring artifact on the server, run the (client) artifact on systems of interest. | ||
The (server monitoring) artifact itself produces no relevant output. It should lead to the clients being tagged with the names of present RMM tools. | ||
type: SERVER_EVENT | ||
|
||
parameters: | ||
- name: LabelBasedOnNetworkIndicators | ||
type: bool | ||
default: false | ||
description: Activate tagging of systems based on network indicators for RMMs; please consider that these are more likely to create false positives | ||
|
||
sources: | ||
- name: WindowsInstalledPrograms | ||
query: | | ||
LET rmm_findings = SELECT * FROM watch_monitoring(artifact="System.Flow.Completion") | ||
WHERE Flow.artifacts_with_results =~ "Exchange.Windows.Detection.RMMs/InstalledPrograms" | ||
SELECT * FROM foreach( | ||
row=rmm_findings, | ||
query={ | ||
SELECT * FROM foreach( | ||
row={ | ||
SELECT RMM FROM source(artifact="Exchange.Windows.Detection.RMMs/InstalledPrograms") | ||
GROUP BY RMM -- cheap deduplication | ||
}, | ||
query={ | ||
SELECT label(client_id=ClientId, labels=RMM, op="set") FROM info() | ||
}) | ||
}) | ||
- name: WindowsResolvedDomains | ||
precondition: | ||
SELECT OS From info() Where LabelBasedOnNetworkIndicators | ||
query: | | ||
LET rmm_findings = SELECT * FROM watch_monitoring(artifact="System.Flow.Completion") | ||
WHERE Flow.artifacts_with_results =~ "Exchange.Windows.Detection.RMMs/ResolvedDomains" | ||
SELECT * FROM foreach( | ||
row=rmm_findings, | ||
query={ | ||
SELECT * FROM foreach( | ||
row={ | ||
SELECT RMM FROM source(artifact="Exchange.Windows.Detection.RMMs/ResolvedDomains") | ||
GROUP BY RMM -- cheap deduplication | ||
}, | ||
query={ | ||
SELECT label(client_id=ClientId, labels=RMM, op="set") FROM info() | ||
}) | ||
}) |
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,84 @@ | ||
name: Windows.Detection.RMMs | ||
author: Herbert Bärschneider | ||
description: | | ||
This artifact searches for RMMs present in the environment, based on data from the LOLRMM project. | ||
It is meant to create awareness of the RMM tools present in the environment. The results are also meant to be used for tagging the systems appropriately. | ||
Attackers like using RMM tools for persistence. These can be either brought in by the attacker or already present ones. Organizations are also often unaware which RMM tools they currently use in their environment. | ||
The finding of RMMs depends on data from the LOLRMM project, which is normally downloaded from the internet on demand; this data can also be served locally, if systems do not have unrestricted internet access. | ||
The artifact shows RMM tools present as installed programs as well as resolved domain names. If no output comes back, this might be due to the following | ||
+ the organization uses no RMM tools | ||
+ the data from the LOLRMM project is not sufficient to identify the RMM tools present in the environment | ||
The output of this artifact is of informational nature. | ||
You have to speak with the persons responsible for the systems to check if identified RMM tools are legitimate. | ||
Not all RMM tools are properly installed on a Windows machine; as such, they will not show up in the data sourced for their identification by this artifact. | ||
Furthermore, RMM tools that manage their own DNS cache will not be detected by the query utilizing the Windows DNS cache. | ||
reference: | ||
- https://lolrmm.io/ | ||
- https://attack.mitre.org/techniques/T1219/ | ||
|
||
type: CLIENT | ||
|
||
tools: | ||
- name: OverviewLOLRMMs | ||
url: https://lolrmm.io/api/rmm_tools.csv | ||
|
||
parameters: | ||
- name: ReallyDoIt | ||
type: bool | ||
default: false | ||
description: Please consider that this artifact downloads over 250KB on each client which might overload the organizations internet access | ||
|
||
sources: | ||
- name: InstalledPrograms | ||
precondition: | ||
SELECT OS From info() Where ReallyDoIt | ||
query: | | ||
LET CsvFile = SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="OverviewLOLRMMs", IsExecutable=FALSE) | ||
LET LOLRMMInfo <= SELECT * FROM parse_csv(filename=CsvFile[0].FullPath) -- typical name stored under "Name" and typical installation files stored as comma-separated list under "InstallationPaths" | ||
LET InstalledPrograms = SELECT * FROM Artifact.Windows.Sys.Programs() | ||
SELECT * FROM foreach( | ||
row={SELECT Name AS RMM, InstallationPaths FROM LOLRMMInfo}, | ||
query={ | ||
SELECT *, RMM, InstallationPaths FROM InstalledPrograms | ||
WHERE InstallationPaths != "" AND InstallLocation != "" -- removes matches on empty stuff | ||
AND ( DisplayName =~ RMM | ||
OR InstallLocation =~ regex_replace(source=regex_replace(source=regex_replace(source=regex_replace(source=regex_replace(source=InstallationPaths,re=", ",replace="|"),re="\\\\\\|",replace="|"),re="\\\\",replace="\\\\"),re="\\.",replace="\\."),re="\\*",replace=".*") -- turning the multiple elements in the InstallationPaths string into a cheap regex; depends on the function "regex_replace" doing global replacements, which was true during testing with velociraptor v0.73.3 | ||
-- replacements (to build the regex): | ||
-- - turn the comma-separator between the elements into regex "Or" separators | ||
-- - removing trailing "\" for installation paths, because the RMM data ends directories with a slash but the installed programs does not always list directories with a trailing slash | ||
-- - replace single slashes with double slashes, so that path dividers are properly escaped for usage in a regex | ||
-- - escape dots (".") so that they do not match any character, but rather only the specific dot character | ||
-- - replace astrisks ("*") with a variant that properly expresses the "match anything" semantic in regex | ||
) | ||
}) | ||
- name: ResolvedDomains | ||
precondition: | ||
SELECT OS From info() Where ReallyDoIt | ||
query: | | ||
LET CsvFile = SELECT FullPath FROM Artifact.Generic.Utils.FetchBinary(ToolName="OverviewLOLRMMs", IsExecutable=FALSE) | ||
LET LOLRMMInfo <= SELECT * FROM parse_csv(filename=CsvFile[0].FullPath) -- typical name stored under "Name" and typical network indicators stored as array under "Artifacts.Network", with each array element having a field "Domains" containing an array of strings of domain names | ||
LET ResolvedDomains = SELECT * FROM Artifact.Windows.System.DNSCache() | ||
SELECT * FROM foreach( | ||
row={SELECT Name AS RMM, `Artifacts`.Network AS NetworkIndicators FROM LOLRMMInfo}, | ||
query={ | ||
SELECT * FROM foreach( | ||
row={SELECT * FROM NetworkIndicators}, | ||
query={ | ||
SELECT * FROM foreach( | ||
row=Domains, -- need to use the field "Domains" directly, as a simple query would not allow me to access the unnamed elements in the field using "_value" | ||
query={ | ||
SELECT *, RMM, _value AS NetworkIndicatorValue FROM ResolvedDomains | ||
WHERE Name =~ regex_replace(source=regex_replace(source=_value,re="\\.",replace="\\."),re="\\*",replace=".*") -- turning the string into a cheap regex; depends on the function "regex_replace" doing global replacements, which was true during testing with velociraptor v0.73.3 | ||
-- replacements (to build the regex): | ||
-- - escape dots (".") so that they do not match any character, but rather only the specific dot character | ||
-- - replace astrixes ("*") with a variant that properly expresses the "match anything" semantic in regex | ||
}) | ||
}) | ||
}) |