Unmanaged Remote-Access and RMM Tooling on Employee Endpoints

WindowsmacOS

TTP Hunt medium DPRK IT Worker FraudFamous ChollimaLaptop Farm

A fleet-wide sweep for the consumer remote-access and RMM software DPRK IT workers install to hand control of an employer-issued laptop to an operator overseas, with a per-device product count that flags the hosts running four or more of them.

What this hunt looks for

Where an operation has not gone as far as hardware, it reaches the laptop through ordinary remote-access software. Mandiant records GoToRemote/LogMeIn, GoToMeeting, Chrome Remote Desktop, AnyDesk, TeamViewer and RustDesk on victim laptops; Unit 42 adds Splashtop; ReliaQuest ranks AnyDesk, RustDesk, VS Code tunnelling and Chrome Remote Desktop; Microsoft adds JumpConnect and AnyViewer.

The signal is not that these tools exist, since many are legitimate IT software, but that one appears where it was never sanctioned, usually within days of issue. One tool is ambiguous; DTEX rates four or more on one endpoint as warranting investigation, and Mandiant advises monitoring for multiple remote-administration tools.

Zscaler adds an AnyDesk tampering signal: operators edit pwd_hash, pwd_salt and token_salt in its configuration to set an unattended-access password without the interactive dialog. The queries cover Windows and macOS in one list; the Cortex XQL query adapts Unit 42's published sweep.

Technique
Remote Access Tools abuse (MITRE ATT&CK T1219, T1219.002) on a corporate endpoint held by a fraudulently hired employee (T1078).
Data sources
EDR process telemetry, Software inventory, Code-signing certificate metadata, macOS application bundles and launchd configuration
Last updated
2026-10-04

Indicators

The atomic values this hunt matches on, listed separately from the queries so they can be lifted into tooling that speaks none of the query languages below. Every value here is reported by one of the sources cited at the foot of this page.

TypeValueNote
Software AnyDesk, RustDesk, TeamViewer, AnyViewer, Chrome Remote Desktop, Splashtop, GoToRemote/LogMeIn, GoToMeeting, JumpConnect, ScreenConnect, VS Code dev tunnels Named across Mandiant, Unit 42, ReliaQuest and Microsoft reporting on DPRK IT-worker operations; ScreenConnect is one of the products in the Unit 42 sweep.
Chrome extension ID inomeogfingihgjfjlpeplalcfajhgai Chrome Remote Desktop extension, as matched in Unit 42's published sweep.
Chrome extension ID gbchcmhmhahfdphkhkmpfmihenigjmpp Chrome Remote Desktop extension, as matched in Unit 42's published sweep.
Signer Zhou Huabing Code-signing vendor Unit 42's query maps to RustDesk.
Signer FleetDeck Inc, SimpleHelp Ltd, NetSupport Ltd, Atera Networks, ConnectWise LLC/Inc, Splashtop Inc Signing vendors Unit 42's query uses in place of process names.
Configuration key pwd_hash, pwd_salt, token_salt AnyDesk configuration values operators set directly to enable unattended access without the interactive password dialog (Zscaler).

Logic

Every query below implements these steps, so the same hunt returns the same result in each product.

  1. Collect: process starts and file writes on Windows and macOS endpoints
  2. Match: image is a remote-access client (AnyDesk, TeamViewer, RustDesk, Splashtop, ScreenConnect, GoTo, AnyViewer, Jump Desktop, others)
  3. Match: or a Chrome Remote Desktop extension id in a profile path, or AnyDesk config (service.conf, user.conf) written by another process
  4. Exclude: devices of IT-support and managed-service staff (replace the placeholder list)
  5. Report: devices with their distinct products, most first; escalate 4 or more (DTEX)

Queries

Defender / Sentinel KQL

Written for this site, from indicators reported by Unit 42, Mandiant, ReliaQuest, Microsoft, DTEX, Zscaler

Rows are devices running any listed product, most products first; Escalate marks the DTEX threshold of four, and the ExcludedDevices list is a placeholder to fill.

// Hunt: unmanaged remote-access and RMM tooling. Names are matched without .exe, so the Windows and macOS binaries share one list.
let ExcludedDevices = dynamic([]);  // replace with the device names of IT-support and managed-service staff
let Tools = datatable(Name:string, Product:string) [
  "anydesk", "AnyDesk",
  "teamviewer", "TeamViewer",
  "teamviewer_service", "TeamViewer",
  "tv_w32", "TeamViewer",
  "tv_x64", "TeamViewer",
  "rustdesk", "RustDesk",
  "remoting_host", "Chrome Remote Desktop",
  "srservice", "Splashtop",
  "srmanager", "Splashtop",
  "splashtopstreamer", "Splashtop",
  "splashtop streamer", "Splashtop",
  "meshagent", "MeshCentral",
  "ateraagent", "Atera",
  "client32", "NetSupport",
  "pcilic", "NetSupport",
  "pcideply", "NetSupport",
  "screenconnect.clientservice", "ScreenConnect",
  "connectwisecontrol.client", "ScreenConnect",
  "screenconnect client", "ScreenConnect",
  "g2comm", "GoToMeeting",
  "gotoassist", "GoToRemote/LogMeIn",
  "lmiguardiansvc", "GoToRemote/LogMeIn",
  "lmi_rescue", "GoToRemote/LogMeIn",
  "aeroadmin", "AeroAdmin",
  "dwrcs", "DameWare",
  "supremo", "Supremo",
  "winvnc", "UltraVNC",
  "tvnserver", "TightVNC",
// optional: Quick Assist ships with Windows and is routine in support sessions
  "quickassist", "Quick Assist",
  "fleetdeck_agent", "FleetDeck",
  "simplehelpcustomer", "SimpleHelp",
  "zohoassist", "Zoho Assist",
  "action1_agent", "Action1",
  "nomachine", "NoMachine",
  "anyviewer", "AnyViewer",
  "jumpconnect", "JumpConnect",
  "jump desktop connect", "JumpConnect"
];
union
( DeviceProcessEvents
  | where Timestamp > ago(90d)
  | extend Name = replace_string(tolower(FileName), ".exe", "")
  | lookup Tools on Name
  | where isnotempty(Product)
  | project Timestamp, DeviceName, Product, Signal = "process", Evidence = FolderPath ),
( DeviceFileEvents
  | where Timestamp > ago(90d) and FolderPath has_any ("inomeogfingihgjfjlpeplalcfajhgai", "gbchcmhmhahfdphkhkmpfmihenigjmpp")
  | project Timestamp, DeviceName, Product = "Chrome Remote Desktop", Signal = "extension-file", Evidence = FolderPath ),
( DeviceFileEvents
  | where Timestamp > ago(90d) and ActionType in ("FileCreated", "FileModified") and FileName in~ ("service.conf", "user.conf")
  | where FolderPath has "anydesk" and not(InitiatingProcessFileName in~ ("AnyDesk.exe", "AnyDesk"))
  | project Timestamp, DeviceName, Product = "AnyDesk", Signal = "anydesk-config-edit", Evidence = strcat(InitiatingProcessFileName, " wrote ", FolderPath) )
| where DeviceName !in~ (ExcludedDevices)
| summarize ProductCount = dcount(Product), Products = make_set(Product),
            Signals = make_set(Signal), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by DeviceName
| extend Escalate = ProductCount >= 4
| sort by ProductCount desc, FirstSeen desc
Lower-fidelity parts (1)
  • the Quick Assist row of the Tools table — Quick Assist ships with Windows and is routine in support sessions. Remove: delete the // optional: Quick Assist comment and the row under it

Sigma

Written for this site, from indicators reported by Mandiant, Unit 42, ReliaQuest

Single-event rule for the product executables on Windows and macOS; the per-device product count is the Report step in the other queries.

title: Remote-Access Tool Executed on a Corporate Endpoint
id: b7f1ac4b-ec73-539d-b31e-619f2ec3e0d4
status: experimental
description: >
  Detects execution of the consumer remote-access and RMM software repeatedly
  named in DPRK IT-worker reporting, on Windows and macOS. On its own the
  signal is weak, since much of this software is legitimate; it becomes strong
  on a device where the tool is unsanctioned, within days of the device being
  issued, or where four or more products run on one device.
references:
  - https://cloud.google.com/blog/topics/threat-intelligence/mitigating-dprk-it-worker-threat
  - https://unit42.paloaltonetworks.com/north-korean-it-workers/
  - https://reliaquest.com/blog/threat-spotlight-identifying-north-korean-insider-threats
logsource:
  category: process_creation
detection:
  selection:
    Image|endswith:
      - '\anydesk.exe'
      - '\teamviewer.exe'
      - '\teamviewer_service.exe'
      - '\tv_w32.exe'
      - '\tv_x64.exe'
      - '\rustdesk.exe'
      - '\remoting_host.exe'
      - '\srservice.exe'
      - '\srmanager.exe'
      - '\splashtopstreamer.exe'
      - '\meshagent.exe'
      - '\ateraagent.exe'
      - '\client32.exe'
      - '\pcilic.exe'
      - '\pcideply.exe'
      - '\screenconnect.clientservice.exe'
      - '\connectwisecontrol.client.exe'
      - '\g2comm.exe'
      - '\gotoassist.exe'
      - '\lmiguardiansvc.exe'
      - '\lmi_rescue.exe'
      - '\aeroadmin.exe'
      - '\dwrcs.exe'
      - '\supremo.exe'
      - '\winvnc.exe'
      - '\tvnserver.exe'
      # optional: Quick Assist ships with Windows and is routine in support sessions
      - '\quickassist.exe'
      - '\fleetdeck_agent.exe'
      - '\simplehelpcustomer.exe'
      - '\zohoassist.exe'
      - '\action1_agent.exe'
      - '\nomachine.exe'
      - '\anyviewer.exe'
      - '\jumpconnect.exe'
      - '/AnyDesk'
      - '/TeamViewer'
      - '/RustDesk'
      - '/Splashtop Streamer'
      - '/ScreenConnect Client'
      - '/AnyViewer'
      - '/Jump Desktop Connect'
  condition: selection
falsepositives:
  - Sanctioned IT support and managed-service tooling
level: medium
Lower-fidelity parts (1)
  • the Quick Assist image — Quick Assist ships with Windows and is routine in support sessions. Remove: delete the # optional comment and the line under it

Splunk SPL

Written for this site, from indicators reported by Unit 42, DTEX

Counts distinct products per host from process events; the NOT host line is a placeholder for the IT-support exclusion.

```Placeholder: index=endpoint is your EDR process events (Windows and macOS) with process_name and host extracted.```
index=endpoint process_name=*
| eval n=replace(lower(process_name), "[.]exe$", "")
| eval product=case(
    match(n, "^(anydesk)$"), "AnyDesk",
    match(n, "^(teamviewer|teamviewer_service|tv_w32|tv_x64)$"), "TeamViewer",
    match(n, "^(rustdesk)$"), "RustDesk",
    match(n, "^(remoting_host)$"), "Chrome Remote Desktop",
    match(n, "^(srservice|srmanager|splashtopstreamer|splashtop streamer)$"), "Splashtop",
    match(n, "^(meshagent)$"), "MeshCentral",
    match(n, "^(ateraagent)$"), "Atera",
    match(n, "^(client32|pcilic|pcideply)$"), "NetSupport",
    match(n, "^(screenconnect[.]clientservice|connectwisecontrol[.]client|screenconnect client)$"), "ScreenConnect",
    match(n, "^(g2comm)$"), "GoToMeeting",
    match(n, "^(gotoassist|lmiguardiansvc|lmi_rescue)$"), "GoToRemote/LogMeIn",
    match(n, "^(aeroadmin)$"), "AeroAdmin",
    match(n, "^(dwrcs)$"), "DameWare",
    match(n, "^(supremo)$"), "Supremo",
    match(n, "^(winvnc)$"), "UltraVNC",
    match(n, "^(tvnserver)$"), "TightVNC",
    ```optional: Quick Assist ships with Windows and is routine in support sessions```
    match(n, "^(quickassist)$"), "Quick Assist",
    match(n, "^(fleetdeck_agent)$"), "FleetDeck",
    match(n, "^(simplehelpcustomer)$"), "SimpleHelp",
    match(n, "^(zohoassist)$"), "Zoho Assist",
    match(n, "^(action1_agent)$"), "Action1",
    match(n, "^(nomachine)$"), "NoMachine",
    match(n, "^(anyviewer)$"), "AnyViewer",
    match(n, "^(jumpconnect|jump desktop connect)$"), "JumpConnect",
    true(), null())
| where isnotnull(product)
| search NOT host IN ("replace-with-support-device")
| stats dc(product) AS product_count values(product) AS products min(_time) AS first_seen max(_time) AS last_seen BY host
| eval escalate=if(product_count >= 4, "yes", "no")
| sort - product_count - first_seen
| convert ctime(first_seen) ctime(last_seen)
Lower-fidelity parts (1)
  • the Quick Assist case line — Quick Assist ships with Windows and is routine in support sessions. Remove: delete the ```optional comment and the match line under it

CrowdStrike LogScale

Written for this site, from indicators reported by Unit 42, DTEX

Counts distinct products per device from ProcessRollup2; the in() exclusion holds a placeholder name.

// Hunt: unmanaged remote-access and RMM tooling. ImageFileName is a full path on both platforms.
#event_simpleName=ProcessRollup2
| !in(ComputerName, values=["replace-with-support-device"])
| case {
    ImageFileName=/(^|[\\\/])(anydesk)(\.exe)?$/i | product := "AnyDesk";
    ImageFileName=/(^|[\\\/])(teamviewer|teamviewer_service|tv_w32|tv_x64)(\.exe)?$/i | product := "TeamViewer";
    ImageFileName=/(^|[\\\/])(rustdesk)(\.exe)?$/i | product := "RustDesk";
    ImageFileName=/(^|[\\\/])(remoting_host)(\.exe)?$/i | product := "Chrome Remote Desktop";
    ImageFileName=/(^|[\\\/])(srservice|srmanager|splashtopstreamer|splashtop streamer)(\.exe)?$/i | product := "Splashtop";
    ImageFileName=/(^|[\\\/])(meshagent)(\.exe)?$/i | product := "MeshCentral";
    ImageFileName=/(^|[\\\/])(ateraagent)(\.exe)?$/i | product := "Atera";
    ImageFileName=/(^|[\\\/])(client32|pcilic|pcideply)(\.exe)?$/i | product := "NetSupport";
    ImageFileName=/(^|[\\\/])(screenconnect\.clientservice|connectwisecontrol\.client|screenconnect client)(\.exe)?$/i | product := "ScreenConnect";
    ImageFileName=/(^|[\\\/])(g2comm)(\.exe)?$/i | product := "GoToMeeting";
    ImageFileName=/(^|[\\\/])(gotoassist|lmiguardiansvc|lmi_rescue)(\.exe)?$/i | product := "GoToRemote/LogMeIn";
    ImageFileName=/(^|[\\\/])(aeroadmin)(\.exe)?$/i | product := "AeroAdmin";
    ImageFileName=/(^|[\\\/])(dwrcs)(\.exe)?$/i | product := "DameWare";
    ImageFileName=/(^|[\\\/])(supremo)(\.exe)?$/i | product := "Supremo";
    ImageFileName=/(^|[\\\/])(winvnc)(\.exe)?$/i | product := "UltraVNC";
    ImageFileName=/(^|[\\\/])(tvnserver)(\.exe)?$/i | product := "TightVNC";
    // optional: Quick Assist ships with Windows and is routine in support sessions
    ImageFileName=/(^|[\\\/])(quickassist)(\.exe)?$/i | product := "Quick Assist";
    ImageFileName=/(^|[\\\/])(fleetdeck_agent)(\.exe)?$/i | product := "FleetDeck";
    ImageFileName=/(^|[\\\/])(simplehelpcustomer)(\.exe)?$/i | product := "SimpleHelp";
    ImageFileName=/(^|[\\\/])(zohoassist)(\.exe)?$/i | product := "Zoho Assist";
    ImageFileName=/(^|[\\\/])(action1_agent)(\.exe)?$/i | product := "Action1";
    ImageFileName=/(^|[\\\/])(nomachine)(\.exe)?$/i | product := "NoMachine";
    ImageFileName=/(^|[\\\/])(anyviewer)(\.exe)?$/i | product := "AnyViewer";
    ImageFileName=/(^|[\\\/])(jumpconnect|jump desktop connect)(\.exe)?$/i | product := "JumpConnect";
    * | product := "";
  }
| product != ""
| groupBy([aid, ComputerName], function=[count(product, distinct=true, as=productCount), collect([product]), min(@timestamp, as=firstSeen), max(@timestamp, as=lastSeen)])
| escalate := if(productCount >= 4, then="yes", else="no")
| sort(productCount, order=desc)
Lower-fidelity parts (1)
  • the Quick Assist branch — Quick Assist ships with Windows and is routine in support sessions. Remove: delete the // optional comment and the line under it

Elastic

Written for this site, from indicators reported by Unit 42, Zscaler

Reads Elastic Defend process and file events; the Chrome extension and AnyDesk config-edit matches ride along in the same query.

FROM logs-endpoint.events.process-*, logs-endpoint.events.file-*
| WHERE @timestamp > NOW() - 90 days
| WHERE NOT host.name IN ("replace-with-support-device")
| EVAL tool = REPLACE(TO_LOWER(COALESCE(process.name, "")), "[.]exe$", "")
| EVAL path = TO_LOWER(COALESCE(file.path, ""))
| EVAL cfg = path RLIKE ".*anydesk.*" AND TO_LOWER(COALESCE(file.name, "")) IN ("service.conf", "user.conf") AND NOT tool IN ("anydesk")
| EVAL product = CASE(
    cfg, "AnyDesk",
    tool IN ("anydesk"), "AnyDesk",
    tool IN ("teamviewer", "teamviewer_service", "tv_w32", "tv_x64"), "TeamViewer",
    tool IN ("rustdesk"), "RustDesk",
    tool IN ("remoting_host"), "Chrome Remote Desktop",
    tool IN ("srservice", "srmanager", "splashtopstreamer", "splashtop streamer"), "Splashtop",
    tool IN ("meshagent"), "MeshCentral",
    tool IN ("ateraagent"), "Atera",
    tool IN ("client32", "pcilic", "pcideply"), "NetSupport",
    tool IN ("screenconnect.clientservice", "connectwisecontrol.client", "screenconnect client"), "ScreenConnect",
    tool IN ("g2comm"), "GoToMeeting",
    tool IN ("gotoassist", "lmiguardiansvc", "lmi_rescue"), "GoToRemote/LogMeIn",
    tool IN ("aeroadmin"), "AeroAdmin",
    tool IN ("dwrcs"), "DameWare",
    tool IN ("supremo"), "Supremo",
    tool IN ("winvnc"), "UltraVNC",
    tool IN ("tvnserver"), "TightVNC",
    tool IN ("quickassist"), "Quick Assist",
    tool IN ("fleetdeck_agent"), "FleetDeck",
    tool IN ("simplehelpcustomer"), "SimpleHelp",
    tool IN ("zohoassist"), "Zoho Assist",
    tool IN ("action1_agent"), "Action1",
    tool IN ("nomachine"), "NoMachine",
    tool IN ("anyviewer"), "AnyViewer",
    tool IN ("jumpconnect", "jump desktop connect"), "JumpConnect",
    path RLIKE ".*(inomeogfingihgjfjlpeplalcfajhgai|gbchcmhmhahfdphkhkmpfmihenigjmpp).*", "Chrome Remote Desktop",
    NULL)
| WHERE product IS NOT NULL
| EVAL signal = CASE(cfg, "anydesk-config-edit", "product-seen")
| STATS product_count = COUNT_DISTINCT(product), products = VALUES(product), signals = VALUES(signal), first_seen = MIN(@timestamp), last_seen = MAX(@timestamp) BY host.name
| EVAL escalate = product_count >= 4
| SORT product_count DESC, first_seen DESC
Lower-fidelity parts (1)
  • the Quick Assist CASE line — Quick Assist ships with Windows and is routine in support sessions. Remove: delete the CASE line that contains "quickassist"

Cortex XQL

Written for this site, from indicators reported by Unit 42 (Palo Alto Networks)

Adapted from the Unit 42 RMM sweep: it adds the per-device product count, macOS names and the AnyDesk config-edit match, and keeps the signing-vendor checks that catch renamed binaries.

// Hunt: unmanaged remote-access and RMM tooling. Signing vendors catch renamed binaries (as in the Unit 42 sweep).
config case_sensitive = false timeframe = 90D
| dataset = xdr_data
| filter (event_type = ENUM.PROCESS and event_sub_type = ENUM.PROCESS_START) or event_type = ENUM.FILE
| filter agent_hostname not in ("replace-with-support-device")
| alter signal = if(event_type = ENUM.FILE and action_file_path ~= "(?i)anydesk" and action_file_name in ("service.conf", "user.conf") and actor_process_image_name not in ("AnyDesk.exe", "AnyDesk"), "anydesk-config-edit", "")
| alter product = if(
    signal = "anydesk-config-edit", "AnyDesk",
    action_process_image_name ~= "(?i)^(anydesk)([.]exe)?$", "AnyDesk",
    action_process_image_name ~= "(?i)^(teamviewer|teamviewer_service|tv_w32|tv_x64)([.]exe)?$", "TeamViewer",
    action_process_image_name ~= "(?i)^(rustdesk)([.]exe)?$", "RustDesk",
    action_process_image_name ~= "(?i)^(remoting_host)([.]exe)?$", "Chrome Remote Desktop",
    action_process_image_name ~= "(?i)^(srservice|srmanager|splashtopstreamer|splashtop streamer)([.]exe)?$", "Splashtop",
    action_process_image_name ~= "(?i)^(meshagent)([.]exe)?$", "MeshCentral",
    action_process_image_name ~= "(?i)^(ateraagent)([.]exe)?$", "Atera",
    action_process_image_name ~= "(?i)^(client32|pcilic|pcideply)([.]exe)?$", "NetSupport",
    action_process_image_name ~= "(?i)^(screenconnect[.]clientservice|connectwisecontrol[.]client|screenconnect client)([.]exe)?$", "ScreenConnect",
    action_process_image_name ~= "(?i)^(g2comm)([.]exe)?$", "GoToMeeting",
    action_process_image_name ~= "(?i)^(gotoassist|lmiguardiansvc|lmi_rescue)([.]exe)?$", "GoToRemote/LogMeIn",
    action_process_image_name ~= "(?i)^(aeroadmin)([.]exe)?$", "AeroAdmin",
    action_process_image_name ~= "(?i)^(dwrcs)([.]exe)?$", "DameWare",
    action_process_image_name ~= "(?i)^(supremo)([.]exe)?$", "Supremo",
    action_process_image_name ~= "(?i)^(winvnc)([.]exe)?$", "UltraVNC",
    action_process_image_name ~= "(?i)^(tvnserver)([.]exe)?$", "TightVNC",
    // optional: Quick Assist ships with Windows and is routine in support sessions
    action_process_image_name ~= "(?i)^(quickassist)([.]exe)?$", "Quick Assist",
    action_process_image_name ~= "(?i)^(fleetdeck_agent)([.]exe)?$", "FleetDeck",
    action_process_image_name ~= "(?i)^(simplehelpcustomer)([.]exe)?$", "SimpleHelp",
    action_process_image_name ~= "(?i)^(zohoassist)([.]exe)?$", "Zoho Assist",
    action_process_image_name ~= "(?i)^(action1_agent)([.]exe)?$", "Action1",
    action_process_image_name ~= "(?i)^(nomachine)([.]exe)?$", "NoMachine",
    action_process_image_name ~= "(?i)^(anyviewer)([.]exe)?$", "AnyViewer",
    action_process_image_name ~= "(?i)^(jumpconnect|jump desktop connect)([.]exe)?$", "JumpConnect",
    action_process_signature_vendor = "Zhou Huabing", "RustDesk",
    action_process_signature_vendor = "FleetDeck Inc", "FleetDeck",
    action_process_signature_vendor = "SimpleHelp Ltd", "SimpleHelp",
    action_process_signature_vendor = "NetSupport Ltd", "NetSupport",
    action_process_signature_vendor = "Atera Networks", "Atera",
    action_process_signature_vendor = "Splashtop Inc", "Splashtop",
    action_process_signature_vendor in ("ConnectWise, LLC", "ConnectWise, Inc."), "ScreenConnect",
    action_file_path ~= "(?i)(inomeogfingihgjfjlpeplalcfajhgai|gbchcmhmhahfdphkhkmpfmihenigjmpp)", "Chrome Remote Desktop",
    "")
| filter product != ""
| alter signal = if(signal = "", "product-seen", signal)
| comp count_distinct(product) as product_count, values(product) as products, values(signal) as signals, min(_time) as first_seen, max(_time) as last_seen by agent_hostname
| alter escalate = if(product_count >= 4, "yes", "no")
| sort desc product_count
Lower-fidelity parts (1)
  • the Quick Assist branch — Quick Assist ships with Windows and is routine in support sessions. Remove: delete the // optional comment and the line under it

osquery

Written for this site, from indicators reported by Mandiant, Unit 42, Microsoft

Local inventory of running clients and installed macOS bundles; four or more distinct products on one device is the DTEX threshold.

-- Hunt: unmanaged remote-access and RMM tooling, running now (Windows and macOS) or installed as a macOS bundle.
SELECT 'running' AS signal, name AS detail, path
FROM processes
WHERE lower(replace(name, '.exe', '')) IN (
  'anydesk',
  'teamviewer',
  'teamviewer_service',
  'tv_w32',
  'tv_x64',
  'rustdesk',
  'remoting_host',
  'srservice',
  'srmanager',
  'splashtopstreamer',
  'splashtop streamer',
  'meshagent',
  'ateraagent',
  'client32',
  'pcilic',
  'pcideply',
  'screenconnect.clientservice',
  'connectwisecontrol.client',
  'screenconnect client',
  'g2comm',
  'gotoassist',
  'lmiguardiansvc',
  'lmi_rescue',
  'aeroadmin',
  'dwrcs',
  'supremo',
  'winvnc',
  'tvnserver',
  -- optional: Quick Assist ships with Windows and is routine in support sessions
  'quickassist',
  'fleetdeck_agent',
  'simplehelpcustomer',
  'zohoassist',
  'action1_agent',
  'nomachine',
  'anyviewer',
  'jumpconnect',
  'jump desktop connect'
)
UNION ALL
SELECT 'installed-bundle', filename, path
FROM file
WHERE path IN ('/Applications/AnyDesk.app', '/Applications/TeamViewer.app', '/Applications/RustDesk.app',
               '/Applications/Splashtop Streamer.app', '/Applications/ScreenConnect Client.app',
               '/Applications/AnyViewer.app', '/Applications/Jump Desktop Connect.app')
Lower-fidelity parts (1)
  • the quickassist entry — Quick Assist ships with Windows and is routine in support sessions. Remove: delete the -- optional comment and the 'quickassist' line under it

YARA

Written for this site, from indicators reported by Zscaler

Run over AnyDesk's service.conf or user.conf; unattended access is a legitimate setting, so the config-edit match in the other queries is what separates tampering.

rule AnyDesk_Unattended_Access_Config
{
    meta:
        description = "AnyDesk configuration carrying the password hash, password salt and token salt operators write to enable unattended access"
        reference = "https://www.zscaler.com/blogs/security-research/pyongyang-your-payroll-rise-north-korean-remote-workers-west"
    strings:
        $hash = "pwd_hash" ascii
        $salt = "pwd_salt" ascii
        $token = "token_salt" ascii
    condition:
        filesize < 64KB and all of them
}

False positives and tuning

Most of this software is legitimate, and in managed-service environments several agents are the support tooling. Run this as an inventory sweep first and alert only on what your own IT function does not deploy.

Scope to devices issued in the last ninety days and correlate whether the tool arrived before or after the endpoint agent. The process lists are not exhaustive and executable names change between versions.

IT support staff, managed-service technicians and solutions engineers legitimately accumulate remote-access tools. Exclude those roles before running the counting queries rather than raising the threshold, which discards the cases DTEX describes.

On macOS, an MDM-deployed remote-support client appears in the same application and launchd locations as an unsanctioned one, so compare against the management inventory.

Sources

Tuning required before use This hunt is a starting point. Adapt the queries to your schema, validate them against your baseline and tune them for the false positives noted above. Indicators go stale as operators rotate hosts.