(originally posted on github)

The most difficult challenge with RMM detection is contextual awareness around usage to determine if it is valid or malicious.

  • if the software is not used in the environment
    • could it be legitimate by a random employee?
    • is it an attacker BYOL
    • even so, all occurrences could probably be considered suspicious
  • if it is used in the environment
    • is every use of it legitimate? Probably not
    • this also creates significant living off the land (LOL) opportunity
    • some occurrences should be considered suspicious
  • without any contextual awareness, this is an even harder problem

Under resources, there is a table of known RMM executables, as well as a raw json RMM.json for processing.

Approaches to detecting

A. Explicitly defined RMM software + behavioral (less resilient)

These rely on explicity referencing known RMM artifacts (in some way) within the logic

  1. Known RMMs
  2. Known RMM + low prevalence
  3. New executable in environment + known RMM
  4. New + RMM + suspicious activity
  5. New + RMM + alert

search

B. Dynamically and generically defining RMM + behavioral

This relies completely on common behaviors of RMM (can misidentify)

  1. Logic for generic RMM behaviors (vs pre-defined known RMMs)

Details

A1. Known RMMs

search

Two options to defining known RMM’s

Option 1: comprehensive list of identified RMM executables

Simply build a list of all known executables (see the table below). This is brittle, but more precise

process where event.type == "start" and
(
  // Windows
  (
    host.os.type == "windows" and
      process.executable : (
        "C:\\Program Files*\\*\\NinjaRMMAgentPatcher.exe",
        "C:\\Program Files*\\NinjaRMMAgent\\NinjaRMMAgentPatcher.exe",
        "C:\\ProgramData\\NinjaRMMAgent\\ninjarmm-cli.exe",
        "C:\\Program Files*\\*\\NinjaRMMAgent.exe",
        "C:\\Program Files*\\NinjaRMMAgent\\NinjaRMMAgent.exe",
        
        "C:\\Program Files*\\ATERA Networks\\AteraAgent\\AteraAgent.exe",
        "C:\\Program Files*\\ATERA Networks\\AteraAgent\\Packages\\AgentPackageNetworkDiscoveryWG\\AgentPackageNetworkDiscoveryWG.exe",
        "C:\\Program Files*\\ATERA Networks\\AteraAgent\\Packages\\AgentPackageAgentInformation\\AgentPackageAgentInformation.exe",
        "C:\\Program Files*\\ATERA Networks\\AteraAgent\\Packages\\AgentPackageSTRemote\\AgentPackageSTRemote.exe",
        "C:\\Program Files*\\ATERA Networks\\AteraAgent\\Packages\\AgentPackageFileExplorer\\AgentPackageFileExplorer.exe",
        "C:\\Program Files*\\ATERA Networks\\AteraAgent\\Packages\\AgentPackageMonitoring\\AgentPackageMonitoring.exe",
        "C:\\Program Files*\\ATERA Networks\\AteraAgent\\Packages\\AgentPackageRuntimeInstaller\\AgentPackageRuntimeInstaller.exe",
        
        "C:\\Windows\\SysWOW64\\config\\systemprofile\\AppData\\Local\\GoToAssist Remote Support Applet\\*.tmp\\GoToAssistService.exe",
        "C:\\Users\\*\\AppData\\Local\\GoToAssist Remote Support Applet\\*.tmp\\GoToAssistProcessChecker.exe",
        "C:\\Program Files*\\LogMeIn\\GoToAssist Corporate\\*\\G2AC_HostLauncher.exe",
        "C:\\Program Files*\\GoToMeeting\\*\\G2MInstaller.exe",
        "C:\\Users\\*\\AppData\\Local\\GoToMeeting\\*\\g2mcomm.exe",
        "C:\\Users\\*\\AppData\\Local\\GoToMeeting\\*\\g2mlauncher.exe",
        "C:\\Program Files*\\GoToAssist Remote Support Customer\\*\\g2ax_host_service.exe",
        "C:\\Program Files*\\GoToAssist Remote Support Customer\\*\\g2ax_comm_customer.exe",
        "C:\\Users\\*\\AppData\\Local\\GoTo Resolve Applet\\*.tmp\\GoToResolveService.exe",
        "C:\\Program Files*\\GoToAssist Remote Support Unattended\\*\\GoToAssistTools64.exe",
        "C:\\Program Files*\\GoToAssist Remote Support Unattended\\*\\GoToAssistUnattended.exe",
        "C:\\Users\\*\\AppData\\Local\\goto-updater\\pending\\GoToSetup-*.exe",
        "C:\\Program Files*\\GoToMeeting\\*\\g2mlauncher.exe",
        "C:\\Users\\*\\AppData\\Local\\GoToAssist Remote Support Applet\\*.tmp\\GoToAssistCrashHandler.exe",
        "C:\\Users\\*\\AppData\\Local\\GoToMeeting\\*\\g2mupdate.exe",
        
        "C:\\ManageEngine\\DesktopCentralMSP_Server\\jre\\bin\\java.exe",
        "C:\\ManageEngine\\ADManager Plus\\jre\\bin\\java.exe",
        "C:\\Program Files*\\ManageEngine\\PMP\\tools\\archiver\\windows\\x86-64\\7za.exe",
        "C:\\ManageEngine\\elasticsearch\\jre\\bin\\java.exe",
        "C:\\Program Files*\\ManageEngine\\PMP\\jre\\bin\\java.exe",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\bin\\7za.exe",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\bin\\wrapper.exe",
        "C:\\ManageEngine\\OpManager\\jre\\bin\\java.exe",
        "C:\\ManageEngine\\EventLog Analyzer\\jre\\bin\\java.exe",
        "C:\\ManageEngine\\ADAudit Plus\\pgsql\\bin\\postgres.exe",
        "C:\\ManageEngine\\OpManager\\Probe\\OpManagerProbe\\pgsql\\bin\\postgres.exe",
        
        "C:\\Program Files*\\Microsoft Intune Management Extension\\ClientHealthEval.exe",
        "C:\\Program Files*\\WindowsApps\\Microsoft.*\\IntuneManagementExtensionBridge\\IntuneManagementExtensionBridge.exe",
        "C:\\Program Files*\\WindowsApps\\Microsoft.*\\BridgeLauncher\\BridgeLauncher.exe",
        "C:\\Program Files*\\Microsoft Intune Management Extension\\Microsoft.Management.Services.IntuneWindowsAgent.exe",
        "C:\\Program Files*\\Microsoft Intune Management Extension\\Microsoft.Management.Clients.CopyAgentCatalog.exe",
        "C:\\Program Files*\\Microsoft Intune Management Extension\\SensorLogonTask.exe",
        "C:\\Program Files*\\Microsoft Intune Management Extension\\AgentExecutor.exe",

        "C:\\Users\\*\\AppData\\Local\\MSP Anywhere for N-central\\Viewer\\Tmp\\SWI_MSP_RC_ViewerUpdate-*.exe",

        "C:\\Program Files*\\DesktopCentral_Agent\\bin\\dcagentservice.exe",
        "C:\\Program Files*\\DesktopCentral_Agent\\bin\\DCFAService64.exe",
        "C:\\Program Files*\\DesktopCentral_Agent\\bin\\dcagentregister.exe",
        "C:\\Program Files*\\DesktopCentral_Server\\pgsql\\bin\\postgres.exe",
        "C:\\Program Files*\\DesktopCentral_Server\\bin\\wrapper.exe",
        "C:\\ManageEngine\\DesktopCentral_Server\\bin\\wrapper.exe",
        "C:\\Program Files*\\DesktopCentral_Server\\bin\\UEMS.exe",
        "C:\\Program Files*\\DesktopCentral_Server\\nginx\\dcnginx.exe",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\jre\\bin\\java.exe",
        "C:\\Program Files*\\DesktopCentral_Agent\\bin\\EMSAddonInstaller.exe",
        "C:\\ManageEngine\\DesktopCentral_Server\\jre\\bin\\java.exe",
        "C:\\Program Files*\\DesktopCentral_Server\\apache\\bin\\dcserverhttpd.exe",
        "C:\\Program Files*\\DesktopCentral_Server\\bin\\7za.exe",
        "C:\\Program Files*\\DesktopCentral_Server\\jre\\bin\\java.exe",
        "C:\\Program Files*\\DesktopCentral_Server\\bin\\dcnotificationserver.exe",
        "C:\\Program Files*\\DesktopCentral_Agent\\dcconfig.exe",
        "C:\\Program Files*\\DesktopCentral_Agent\\patches\\*-gimp-*-setup.exe",
        "C:\\ManageEngine\\AssetExplorer\\DesktopCentral_Server\\bin\\wrapper.exe",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\lib\\native\\64bit\\wrapper.dll",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\jre\\bin\\awt.dll",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\jre\\bin\\sunec.dll",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\jre\\bin\\freetype.dll",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\jre\\bin\\fontmanager.dll",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\lib\\native\\64bit\\SyMNative.dll",
        "C:\\Program Files*\\ManageEngine\\ServiceDesk\\DesktopCentral_Server\\lib\\native\\64bit\\OSDSyMNative.dll",
        
        "C:\\Windows\\Action1\\action1_remote.exe",
        "C:\\Windows\\Action1\\action1_agent.exe")
  ) or

  // MacOS
  (
    host.os.type == "macos" and
      process.executable : (
        "/Applications/NinjaRMMAgent/programfiles/ninjarmm-macagent",

        "/Applications/GoToMeeting.app/Contents/MacOS/GoToMeeting",
        "/Applications/GoToMeeting.app/Contents/Helpers/G2MUpdate",
        "/Users/*/Library/Application Support/LogMeInInc/GoToMeeting/G2MUpdate",
        
        "/Library/Intune/Microsoft Intune Agent.app/Contents/MacOS/IntuneMdmDaemon",

        "/Applications/MSP Anywhere Agent N-central.app/Contents/Resources/MSP Anywhere Service Configurator.app/Contents/MacOS/MSP Anywhere Service Configurator",
        "/Applications/MSP Anywhere Agent N-central.app/Contents/Resources/MSP Anywhere Helper")
  )
)

Option 2: resilient patterns of known RMM software

This is a more resilient approach, which looks for

  • unique patterns of the executable path
  • code signature unique to RMM software
any where event.category : ("process", "library") and event.type == "start" and
(
  // Windows
  (
    host.os.type == "windows" and (
      process.executable : ("?:\\*NinjaRMMAgent*.exe",
                            "?:\\*\\AteraAgent\\*.exe",
                            "?:\\*\\GoToAssist*\\*.exe", "?:\\*\\GoToMeeting\\*.exe", "?:\\*\\GoTo*.exe", "?:\\*\\GoToSetup*.exe",
                            "?:\\*ManageEngine\\*.exe",
                            "?:\\Microsoft Intune*\\*.exe", "?:\\IntuneManagement*\\*.exe",
                            "?:\\*\\*N-central*\\*.exe",
                            "?:\\*\\DesktopCentral*\\*.exe",
                            "?:\\*\\Action1\\*.exe") or
      dll.path : ("?:\\*NinjaRMMAgent*.dll",
                  "?:\\*\\AteraAgent\\*.dll",
                  "?:\\*\\GoToAssist*\\*.dll", "?:\\*\\GoToMeeting\\*.dll", "?:\\*\\GoTo*.dll", "?:\\*\\GoToSetup*.dll",
                  "?:\\*ManageEngine\\*.dll",
                  "?:\\Microsoft Intune*\\*.dll", "?:\\IntuneManagement*\\*.dll",
                  "?:\\*\\*N-central*\\*.dll",
                  "?:\\*\\DesktopCentral*\\*.dll",
                  "?:\\*\\Action1\\*.dll") or
      process.code_signature.subject_name : ("NinjaRMM, LLC",
                                             "Atera Networks Ltd",
                                             "LogMeIn, Inc.",
                                             "ZOHO Corporation Private Limited",  // could FP due to non-RMM software
                                             "Action1 Corporation") or
      dll.code_signature.subject_name : ("NinjaRMM, LLC",
                                         "Atera Networks Ltd",
                                         "LogMeIn, Inc.",
                                         "ZOHO Corporation Private Limited",  // could FP due to non-RMM software
                                         "Action1 Corporation")
    )
  ) or

  // MacOS
  (
    host.os.type == "macos" and (
      process.executable : ("/Applications/*NinjaRMMAgent/*",
                            "/Applications/*GoToMeeting*/*", "/Users/*/Library/*/GoToMeeting*/*",
                            "/Library/*Microsoft InTune*/*", "/Users/*/Library/*Microsoft InTune*/*",
                            "/Applications/*N-central*/*") or

      // or dll.path : () or
      // process.code_signature.subject_name : () or
      // dll.code_signature.subject_name : ()
    )
  )

  // Linux
)

A2. Known RMM + low prevalence

search

Perform one of the searches from step 1 and aggregate on:

  • hosts
  • users
  • unique executions

Look for low counts

A3. New executable in environment + known RMM

search

Create a new terms stlye rule based on step 1

  • window history of now-30d
  • base the new terms on: process.name, host.id (remove host.id for full environment prevalence)

If you do not have a new terms capability, you can perform the search in step 1 to build a list of observed RMM executables, then pivot (or join) on a search for recent exections.

A4. New executable + known RMM + suspicious activity

search

Combine step 3 with subsequent suspicious activity (such as lateral movement information gathering).

With Elastic, you could do this by:

  1. create the rule from step 3 (optionally as a building_block_rule to keep noise down)
  2. create a separate sequence based rule that looks for the new term then the suspicious activity
    • to simplify this, you can create another building_block_rule for suspicious activity
sequence by host.id, user.id, process.name with maxspan=25m
  [alert where rule.id == <new_term_rule_step3>]
  [alert where rule.id == <suspicious_rule_step4>]

A5. New executable + known RMM + alert

search

Similar to step 4 except referencing actual alerts for the second part of the sequence

sequence by host.id, user.id, process.name with maxspan=25m
  [alert where rule.id == <new_term_rule_step3>]
  [alert where true]

Leaving subquery 2 generic is a great option, since a newly occurring RMM would be suspicious in this case. It can be tightened down with a few options:

  • limiting query 2 to certain techniques or subtechniques
  • add additional logic to query 2 from the raw alert results, or even a subset of alerts
  • adding additional queries to the sequence to express a more progressed attack

B1. Logic for generic RMM behaviors

Rather than using statically defined RMM artifacts based on observations, this entails building out generic logic to identify them. This is a much greater challenge, especially due to their legitimate nature. Additional features such as ML, entity analytics, and other aggregation based searching make a significant difference here.

Once a dynamic method is defined, then steps 2-5 apply, creating a sustainable detection approach.

I think it is doable from a purely rule-based approach, but I will return to this a bit later …

Also, with the Elastic ES|QL piped language, these become much more feasible within a single rule.