RMM Software Installation from an Internet-Originated MSI

Last updated a month ago on 2026-09-18
Created 3 months ago on 2026-08-07

About

Identifies a Windows Installer package (MSI) originating from the internet, which when executed, installs a recognized RMM product. Attackers use RMMs commonly in social engineering campaigns to gain access and control over the victim's system. This rule does not establish that the origin, installer, or RMM product is inherently malicious. It also excludes installations covered by the companion rule "RMM Software Installation from a Commonly Abused Web Service".
Tags
Domain: EndpointOS: WindowsPlatform: WindowsRule Type: ES|QLUse Case: Threat DetectionTactic: Defense EvasionTactic: Command and ControlData Source: Elastic DefendLanguage: esql
Severity
low
Risk Score
21
MITRE ATT&CK™

Command and Control (TA0011)(external, opens in a new tab or window)

Defense Evasion (TA0005)(external, opens in a new tab or window)

False Positive Examples
Authorized IT or managed service provider deployment of remote monitoring and management software through vendor, internal, or other software distribution infrastructure can produce this behavior.
License
Elastic License v2(external, opens in a new tab or window)

Definition

Integration Pack
Prebuilt Security Detection Rules
Related Integrations

endpoint(external, opens in a new tab or window)

Query
text code block:
/* Correlate three events on the same host: an internet-originated MSI outside the curated web-service set, the same user running that MSI with msiexec within 10 minutes, and msiexec creating a known RMM executable within 5 more minutes. Keep the MSI download event as the alert. */ FROM ( FROM logs-endpoint.events.file-* METADATA _id, _version, _index | WHERE KQL("event.action: creation") AND TO_LOWER(file.extension) == "msi" AND file.origin_url IS NOT NULL | EVAL Esql.sequence_stage = "origin" | URI_PARTS Esql.origin = file.origin_url | EVAL Esql.origin.domain = TO_LOWER(Esql.origin.domain) // Complement the curated tier. | WHERE NOT ( // Source code and developer artifact hosting. Esql.origin.domain LIKE ( "api.bitbucket.org", "bitbucket.org", "api.github.com", "gist.githubusercontent.com", "github.com", "github-releases.githubusercontent.com", "objects.githubusercontent.com", "raw.githack.com", "raw.githubusercontent.com", "rawcdn.githack.com", "release-assets.githubusercontent.com", "gitlab.com", "*.gitlab.com", "notabug.org", "sourceforge.net", "*.sourceforge.net" ) OR // AWS S3 object storage. Esql.origin.domain LIKE ( "s3.amazonaws.com", "*.s3.amazonaws.com", "s3.*.amazonaws.com", "*.s3.*.amazonaws.com", "s3-*.amazonaws.com", "*.s3-*.amazonaws.com", "*.s3express-*.amazonaws.com" ) OR // Azure, Cloudflare R2, Discord, and Dropbox. Esql.origin.domain LIKE ( "*.azurewebsites.net", "*.azurestaticapps.net", "*.azurecontainerapps.io", "*.blob.core.windows.net", "*.blob.storage.azure.net", "*.web.core.windows.net", "*.web.storage.azure.net", "*.file.core.windows.net", "*.azurefd.net", "*.azureedge.net", "*.r2.dev", "cdn.discordapp.com", "dropbox.com", "*.dropbox.com", "dropboxusercontent.com", "*.dropboxusercontent.com" ) OR // Firebase Storage, Google Drive, and Cloud Storage. Esql.origin.domain LIKE ( "*.googleusercontent.com", "content-storage.googleapis.com", "firebasestorage.googleapis.com", "docs.google.com", "drive.google.com", "drive.usercontent.google.com", "storage-download.googleapis.com", "storage.googleapis.com", "*.storage.googleapis.com", "www.googleapis.com" ) OR // OneDrive, SharePoint, Onehub, OnlyOffice, pCloud, Slack, Supabase, and Wasabi. Esql.origin.domain LIKE ( "api.onedrive.com", "files.1drv.com", "*.files.1drv.com", "onedrive.live.com", "*.onedrive.live.com", "sharepoint.com", "*.sharepoint.com", "storage.live.com", "*.storage.live.com", "onehub.com", "*.onehub.com", "onlyoffice.com", "*.onlyoffice.com", "pcloud.com", "*.pcloud.com", "files.slack.com", "slack-files.com", "*.supabase.co", "s3.wasabisys.com", "*.s3.wasabisys.com", "s3.*.wasabisys.com", "*.s3.*.wasabisys.com" ) OR // Developer tunnels, reverse proxies, automation, and webhooks. Esql.origin.domain LIKE ( "devtunnels.ms", "*.devtunnels.ms", "localtunnel.me", "*.localtunnel.me", "n8n.cloud", "*.n8n.cloud", "*.ngrok.app", "*.ngrok.dev", "*.ngrok-free.app", "*.ngrok-free.dev", "*.ngrok.io", "*.ngrok.pizza", "*.ngrok.pro", "pagekite.me", "*.pagekite.me", "serveo.net", "*.serveo.net", "trycloudflare.com", "*.trycloudflare.com", "webhook.site" ) OR // File-sharing and transfer services. Esql.origin.domain LIKE ( "4shared.com", "*.4shared.com", "*.4sync.com", "bashupload.com", "*.bashupload.com", "catbox.moe", "*.catbox.moe", "easyupload.io", "*.easyupload.io", "file.io", "filebin.net", "filecloud.me", "files.fm", "*.files.fm", "filetransfer.io", "*.filetransfer.io", "gofile.io", "*.gofile.io", "limewire.com", "*.limewire.com", "mediafire.com", "*.mediafire.com", "mega.co.nz", "*.mega.co.nz", "mega.nz", "*.mega.nz", "pixeldrain.com", "*.pixeldrain.com", "send.cm", "*.send.cm", "send.now", "*.send.now", "sendit.sh", "*.sendit.sh", "sendspace.com", "*.sendspace.com", "share.riseup.net", "temp.sh", "tempsend.com", "transfer.sh", "ufile.io", "*.ufile.io", "upload.ee", "*.upload.ee", "we.tl", "wetransfer.com", "*.wetransfer.com", "*.wetransfer.net", "workupload.com" ) OR // CDN, paste, and public hosting services. Esql.origin.domain LIKE ( "*.alwaysdata.net", "blogspot.com", "*.blogspot.com", "b-cdn.net", "*.b-cdn.net", "cdnmegafiles.com", "*.cdnmegafiles.com", "infinityfreeapp.com", "*.infinityfreeapp.com", "free.keep.sh", "*.netlify.app", "paste.ee", "publicvm.com", "*.publicvm.com", "*.vercel.app", "*.*.workers.dev" ) OR // Decentralized and content-addressed storage. Esql.origin.domain LIKE ( "ar.io", "*.ar.io", "arweave.net", "*.arweave.net", "ic0.app", "*.ic0.app", "icp0.io", "*.icp0.io", "dweb.link", "*.dweb.link", "gateway.pinata.cloud", "ipfs.io", "*.ipfs.io", "mypinata.cloud", "*.mypinata.cloud", "nftstorage.link", "*.nftstorage.link", "storjshare.io", "*.storjshare.io", "web3.storage", "*.web3.storage" ) ) ), ( FROM logs-endpoint.events.process-* METADATA _id, _version, _index | WHERE host.os.type == "windows" AND KQL("event.type: start") AND process.name.caseless == "msiexec.exe" | EVAL Esql.sequence_stage = "execute" | KEEP @timestamp, host.id, process.args, user.id, _id, _version, _index, Esql.sequence_stage ), ( FROM logs-endpoint.events.file-* METADATA _id, _version, _index | WHERE KQL("event.action: creation") AND process.name.caseless == "msiexec.exe" | EVAL file.name.caseless = TO_LOWER(file.name) | WHERE file.name.caseless IN ( // Acronis "acroniscyberprotectconnectagent.exe", // AeroAdmin "aeroadmin.exe", // AnyDesk "anydesk.exe", // APC "apc_admin.exe", "apc_host.exe", // Atera "ateraagent.exe", // AweSun "awesun.exe", // BarracudaRMM "cagservice.exe", // BeyondTrust "b4-service.exe", "basupsrvc.exe", "bomgar-scc.exe", "remote support.exe", // CloudRadial "cloudracmd.exe", "cloudrasd.exe", "cloudraservice.exe", // ConnectWiseAutomate "agentmon.exe", "ltsvc.exe", "ltsvcmon.exe", "lttray.exe", // Devolutions "remotedesktopmanager.exe", // Domotz "domotz-windows-x64-10.exe", "domotzagent.exe", // DWService "dwagsvc.exe", "dwrcc.exe", "dwrcs.exe", "dwrcst.exe", // GetScreen "getscreen.exe", // GoTo "g2aservice.exe", "gotoassistservice.exe", "gotohttp.exe", "gotoresolveprocesschecker.exe", "gotoresolveremotecontrol.exe", "gotoresolveservice.exe", "gotoresolveterminal.exe", "gotoresolveunattended.exe", // HelpWire "helpwire.exe", // ImmyBot "immyagent.exe", "immybot.agent.ephemeral.exe", "immyupdater.exe", // Impero "imperoclientsvc.exe", "imperoserversvc.exe", // ISLOnline "isllight.exe", "isllightclient.exe", // JumpCloud "jumpcloud-agent.exe", // Kaseya "saazapsc.exe", // Komari "komari-agent.exe", "komari.exe", // Level "level.exe", "lvagent.exe", // LogMeIn "lmi_rescue_srv.exe", "lmi_rescue.exe", "lmiignition.exe", "logmein.exe", // Lunixar "lunixar.exe", "lunixarremote.exe", "lunixarupdater.exe", // ManageEngine "manageengine_remote_access_plus.exe", // MeshCentral "meshagent.exe", // Mikogo "mikogo-service.exe", // Nezha "nezha-agent.exe", // NinjaOne "ninjarmm-cli.exe", "ninjarmmagent.exe", "ninjarmmagentpatcher.exe", // Parsec "parsec.exe", // PDQ Connect "pdq-connect-agent.exe", "pdq-connect-updater.exe", // Pulseway "pservice.exe", // QuickAssist "quickassist.exe", // Radmin "r_server.exe", "radmin.exe", "radmin3.exe", "rserver3.exe", // RealVNC "romserver.exe", "romviewer.exe", "vncserver.exe", "vncviewer.exe", "winvnc.exe", // Remotely "remotely_agent.exe", "remotely_desktop.exe", // RemotePC "remotepc.exe", "remotepcdesktop.exe", "remotepcservice.exe", // RemoteUtilities "rfusclient.exe", "rutserv.exe", "rutview.exe", // RPCSuite "rcclient.exe", "rcservice.exe", "rpcsuite.exe", // Rsupport "rcengmgru.exe", "rcmgrsvc.exe", "remoteview.exe", "rvagent.exe", "rvagtray.exe", // RustDesk "rustdesk.exe", // SimpleHelp "simplegatewayservice.exe", "simplehelpcustomer.exe", // Splashtop "smpcview.exe", "spclink.exe", "splashtop-streamer.exe", "splashtopsos.exe", "spsrv.exe", "sragent.exe", "srmanager.exe", "srserver.exe", "srservice.exe", "strwinclt.exe", // SuperOps "rmm.agent.exe", // Supremo "supremo.exe", "supremoservice.exe", // Syncro "syncro.app.runner.exe", "syncro.installer.exe", "syncro.overmind.service.exe", "syncro.service.exe", "syncrolive.agent.exe", "syncrolive.agent.runner.exe", "syncrolive.service.exe", // TacticalRMM "tacticalrmm.exe", // Tailscale "tailscale.exe", "tailscaled.exe", // TeamViewer "teamviewer_desktop.exe", "teamviewer_service.exe", "teamviewer.exe", // Techinline "tsclient.exe", // Tiflux "tiagent.exe", "ticlientcore.exe", // TightVNC "tvn.exe", "tvnserver.exe", "tvnviewer.exe", // ToDesk "todesk_service.exe", // ToolsIQ "toolsiq.exe", // Twingate "twingate.exe", // Velociraptor "velociraptor.exe", // ZohoAssist "session_win.exe", "za_access.exe", "za_connect.exe", "zaservice.exe", "zmagent.exe", "zohomeeting.exe", "zohotray.exe", "zohours.exe", "zohoursservice.exe" ) OR file.name.caseless LIKE ( // AnyAssist "aa_v*.exe", // AweSun "aweray_remote*.exe", // FleetDeck "fleetdeck_commander*.exe", // ScreenConnect "connectwisecontrol*.exe", "screenconnect*.exe", // UltraViewer "ultraviewer*.exe", // UltraVNC "ultravnc*.exe" ) // Keep the executable name paired with its creation time through the host-level aggregation. | EVAL Esql.sequence_stage = "install", Esql.install_candidate = CONCAT(TO_STRING(@timestamp), "|", file.name) | KEEP @timestamp, host.id, _id, _version, _index, Esql.sequence_stage, Esql.install_candidate ) | WHERE host.id IS NOT NULL // Attach known RMM executable creation candidates to all rows on the same host. // Retain only download and execution candidates from hosts with at least one such creation. | INLINE STATS Esql.install_count = COUNT(*) WHERE Esql.sequence_stage == "install", Esql.install_candidates = VALUES(Esql.install_candidate) WHERE Esql.sequence_stage == "install" BY host.id | DROP Esql.install_candidate | WHERE Esql.sequence_stage IN ("origin", "execute") AND Esql.install_count > 0 // Lowercase the downloaded path and every msiexec argument, remove the :Zone.Identifier marker, // and keep values ending in .msi as the shared path key. | EVAL Esql.candidate_path = CASE( Esql.sequence_stage == "origin", file.path, process.args ), Esql.actor_user_id = user.id | MV_EXPAND Esql.candidate_path | EVAL Esql.artifact_path = REPLACE(TO_LOWER(Esql.candidate_path), ":zone.identifier", "") | WHERE Esql.artifact_path LIKE "*.msi" AND Esql.actor_user_id IS NOT NULL // Match the origin event and msiexec start using host, MSI path, and user SID. | INLINE STATS Esql.execute_count = COUNT(*) WHERE Esql.sequence_stage == "execute", Esql.execute_times = VALUES(@timestamp) WHERE Esql.sequence_stage == "execute" BY host.id, Esql.artifact_path, Esql.actor_user_id | WHERE // Keep the real origin event as the alert document. Esql.sequence_stage == "origin" AND Esql.execute_count > 0 // Require the matching msiexec process to start within 10 minutes after the MSI download. | MV_EXPAND Esql.execute_times | EVAL Esql.origin_to_execute_s = DATE_DIFF("second", @timestamp, Esql.execute_times) | WHERE Esql.origin_to_execute_s >= 0 AND Esql.origin_to_execute_s <= 600 // On the same host, require any msiexec process to create a known RMM executable // within 5 minutes after the matched start. | MV_EXPAND Esql.install_candidates | EVAL Esql.install_time = TO_DATETIME(MV_FIRST(SPLIT(Esql.install_candidates, "|"))), Esql.rmm_file_name = MV_LAST(SPLIT(Esql.install_candidates, "|")), Esql.execute_to_install_s = DATE_DIFF("second", Esql.execute_times, Esql.install_time) | DROP Esql.install_candidates | WHERE Esql.execute_to_install_s >= 0 AND Esql.execute_to_install_s <= 300 // Select one concrete origin row per host, MSI path, and user, preferring the // earliest RMM executable creation when second-level durations tie. | SORT Esql.execute_times ASC, Esql.origin_to_execute_s ASC, Esql.execute_to_install_s ASC, Esql.install_time ASC, Esql.rmm_file_name ASC, _id ASC | LIMIT 1 BY host.id, Esql.artifact_path, Esql.actor_user_id | RENAME Esql.execute_times AS Esql.execute_time | KEEP @timestamp, _id, _index, _version, event.action, event.category, event.type, event.created, event.ingested, data_stream.dataset, data_stream.namespace, host.id, host.name, user.id, user.name, process.entity_id, process.name, process.executable, process.command_line, file.name, file.path, file.extension, file.origin_url, file.origin_referrer_url, file.size, file.hash.sha256, Esql.origin.domain, Esql.artifact_path, Esql.execute_time, Esql.install_time, Esql.rmm_file_name, Esql.origin_to_execute_s, Esql.execute_to_install_s

Install detection rules in Elastic Security

Detect RMM Software Installation from an Internet-Originated MSI in the Elastic Security detection engine by installing this rule into your Elastic Stack.

To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(external, opens in a new tab or window).