C2 powered by dinosaurs
research
Reminder on Velociraptor
A short intro to those that have yet to learn about Velociraptor outside of their childhood:
Velociraptor is a live forensics / incident response tool for large scale investigations. It is a well-known, state-of-the-art defense / blue team tool. It supports a client-server-architecture and allows data collection and parsing, limited only by your creativity (and willingness to implement it in the Velociraptor Query Language).
C2 worthiness of Velociraptor
Note: we will focus on Velociraptor as it is shipped by the developers - we will not go into possibilities achievable by modifying the source code of Velociraptor.
The Velociraptor executables for Windows and Mac are signed with certificates from trusted certificate authorities (DigiCert CA on Windows, Apple CA on Mac). This gives Velociraptor a higher default trust on these operating systems. The Velociraptor binaries for Linux and FreeBSD are unsigned (likely due to the ELF format missing an agreed upon way of signing binaries).
Velociraptor has a client-server-architecture by design, with the server defining tasks and the client executing them. These tasks are defined in its custom language - Velociraptor Query Language (VQL) - and most often saved as "artifacts". The following typical C2 functions are covered:
C2 functionality | Velociraptor functionality | Comments |
---|---|---|
Program Execution |
artifact Generic.Client.VQL artifact Windows.System.PowerShell artifact Windows.System.CmdShell artifact Linux.Sys.BashShell | Most artifacts end up using the plugin execve under the hood Linux.Sys.BashShell is not just limited to Linux operating system - it works on any system that has the executable /bin/bash available |
Retrieve Files from target | artifact System.VFS.DownloadFile artifact Generic.Collectors.File | - |
Searching files | artifact Windows.Search.FileFinder artifact MacOS.Search.FileFinder artifact Linux.Search.FileFinder | Search by filename, pattern and or YARA rule Also includes the option to directly retrieve found files |
Push files to target | plugin http_client artifact Generic.Utils.FetchBinary | Generic.Utils.FetchBinary caches the file on disk |
Communication channels | HTTPS Websocket Secure | - |
Updating Configuration | artifact Admin.Client.UpdateClientConfig | - |
"Ransom" / Denial of Service | artifact Windows.Remediation.Quarantine artifact Linux.Remediation.Quarantine | Isolates the client from the network except for connections to the Velociraptor server |
Beacon Hiding / Sleeping | - | No such functionality exists |
VQL allows for a lot of flexibility. But interaction with the low level API of the kernel is limited to specific functionality exposed by Velociraptor - no unrestricted access is implemented.
Running Velociraptor on a target system requires the binary, a config file and local admin privileges. This makes Velociraptor unusable with low-privileged user accounts. Velociraptor can either be run on demand or persistent. Persistence is achieved by creating a service - the config file defines the service name and the location, where the files related for the service are stored. While Velociraptor includes a way to embed its config file into the binary, this is currently only usable for one time executions (called "offline collectors") and not for running the program for long time periods.
The client/server communication can be secured using mTLS, if configured. The implementation for mTLS uses the same certificate for each client, meaning specific clients cannot be differentiated based on the client certificate.
The Velociraptor multi-frontend functionality allows having multiple server instances that a client can connect to but all such server instances need to be defined in the config file upfront. Each client then chooses a server instance to connect to at random. As such, this is a way of defining backup domains that can easily be defeated by peeking into the config file.
Beyond the extensibility of VQL, Velociraptor itself can also be easily modified to support new functionality. As an example, we implemented local authentication as well as Pass-the-Hash functionality for the smb plugin of Velociraptor and successfully used it in an environment. To use the modified Velociraptor, we only needed to change the binary running on the client - the unmodified server communicated with the modified client without problems.
Spying on the blue team
Velociraptor allows monitoring of activities on the clients and automated reactions (be it triggered by the client directly or orchestrated by the server). Such monitoring is dependent on your needs and things of interest. We investigated the following points, focusing heavily on Windows systems (as these tend to be focused by attackers in our experience):
- Installation of new services on Windows systems: Some tools used in incident response need to be installed as a service on Windows (e. g. Velociraptor when using a persistent mode or some EDR tools). In general, a service installation signals new components added to a system, potentially creating a new attack surface. Thankfully, Velociraptor already ships with an artifact enabling this kind of monitoring: Windows.Events.ServiceCreation
- Process Creations: Beyond new services, the processes run on a system are of interest. These can either be collected in general or filtered for incident response tooling known to be used in the environment (e. g. kape.exe, Collector_velociraptor.* or thor*).
Velociraptor already ships with an artifact enabling this kind of monitoring: Windows.Events.ProcessCreation - the output of this artifact can be improved by enabling data enrichment, either via Sysmon (if it is already present on the system or we are willing to install it - Windows.Events.TrackProcesses) or via regular polling of running processes (Windows.Events.TrackProcessesBasic). The artifact Windows.Events.ProcessCreation creates regular WMI queries, which might alert the blue team that things are fishy. So we were interested in alternative options.
As Velociraptor has recently (Version v0.74) added support for ETW kernel providers, we implemented a client monitoring based on it:
name: Windows.Events.ETWProcesses
author: Herbert Bärschneider, SEC Consult
description: |
This artifact is meant for monitoring processes on Windows clients.
It uses Kernel ETW providers to notice process creations and terminations.
Requirements:
- Velociraptor Client and Velociraptor Server need version v0.74 or newer (or else the feature is just not supported and won't work at all)
type: CLIENT_EVENT
sources:
- query: |
SELECT *, atoi(string=EventData.ProcessId) AS Pid, atoi(string=EventData.ParentId) AS Ppid
FROM watch_etw(guid='kernel', kernel_tracer_type=['process'])
We also tinkered with monitoring processes using the generic pslist() plugin of Velociraptor, creating a client monitoring for process creations that runs on every operating system supported by Velociraptor:
name: Generic.Events.Processes
author: Herbert Bärschneider, SEC Consult
description: |
This artifact is meant for monitoring processes on clients. It is usable on every operating system supported by Velociraptor.
It periodically queries the existing processes and emits lines for differences (new processes and missing/removed ones).
Processes are tracked and compared based on the following elements: process ID, parent process ID, SID of the process owner, username, process name, executable associated with the process, commandline of the process
type: CLIENT_EVENT
parameters:
- name: Period
default: 2
type: int
description: how many seconds the artifact waits between checking processes for changes
sources:
- query: |
LET RunningProcesses = SELECT *, format(format="%v %v %v %v %v %v %v", args=[Pid, Ppid, OwnerSid, Username, Name, Exe, CommandLine]) AS DiffKey FROM pslist()
LET EventQuery = SELECT * FROM diff(query=RunningProcesses, period=Period, key="DiffKey")
SELECT * FROM EventQuery
- Account Logons on Windows systems: In every environment, there are accounts that interest you. As such, it is valuable to learn when such an account logs into any system you control.
Velociraptor already ships with an artifact enabling monitoring of account logins, including a filter for the account you care about: Windows.Events.Trackaccount (companion server monitoring artifact: Server.Alerts.Trackaccount).
Beyond just simple logons, we were also interested in logons with high privileges. These are interesting targets for account takeover. We created the following Velociraptor artifact to enable this kind of monitoring:
name: Windows.Events.HighPrivilegedLogon
author: Herbert Bärschneider, SEC Consult
description: |
Artifact to detect logons that get special privileges assigned. The artifact monitors for security event id 4672.
This is useful to see where accounts with high privileges are being actively used.
Be aware, there is lots of noise from NT_AUTHORITY\SYSTEM and the machine account of a system. These are filtered out for you.
type: CLIENT_EVENT
parameters:
- name: eventLog
default: C:\Windows\system32\winevt\logs\Security.evtx
- name: PrivilegesRegex
type: regex
description: Regex for the privileges you care about
sources:
- precondition:
SELECT OS From info() where OS = 'windows'
query: |
LET files = SELECT * FROM glob(globs=eventLog)
SELECT timestamp(epoch=System.TimeCreated.SystemTime) As EventTime,
System.EventRecordID as EventRecordID,
System.EventID.Value as EventID,
System.Computer as SourceComputer,
EventData.SubjectUserName as SubjectUserName,
EventData.PrivilegeList as PrivilegeList,
System,
EventData,
Message
FROM foreach(
row=files,
async=TRUE,
query={
SELECT *
FROM watch_evtx(filename=OSPath)
WHERE System.EventID.Value = 4672
AND EventData.PrivilegeList =~ PrivilegesRegex
AND NOT ((EventData.SubjectUserName =~ "SYSTEM" AND EventData.SubjectDomainName =~ "NT AUTHORITY") OR EventData.SubjectUserName =~ "\$$")
})
Note: In the above example, we only showed the client side of the monitoring - creation of server monitoring artifacts that consume the results from the client monitoring and trigger alerts and or reactions is left as an exercise for the motivated reader.
Detecting Velociraptor (mis-)usage
Velociraptor on endpoints:
As both default ways of running Velociraptor need a config file and binary on disk, searching for those is a simple way to find usage of Velociraptor. While searching for file names is a good start, we also created some Yara rules to help us:
rule velociraptor_client_config {
meta:
author = "Herbert Bärschneider, SEC Consult"
date = "2025-05-21"
description = "Detects a Velociraptor client config file"
reference = "https://docs.velociraptor.app/docs/deployment/references/"
strings:
$s1 = "server_urls:" ascii
$s2 = "ca_certificate:" ascii
$w1 = "writeback_darwin:" ascii
$w2 = "writeback_linux:" ascii
$w3 = "writeback_windows:" ascii
$w4 = "level2_writeback_suffix:" ascii
condition:
(all of ($s*)) and (any of ($w*))
}
rule velociraptor_binary {
meta:
author = "Herbert Bärschneider, SEC Consult"
date = "2025-05-21"
description = "Detects a Velociraptor binary"
reference = "https://docs.velociraptor.app/downloads/"
strings:
$s1 = "velociraptor" ascii
$s2 = "velocidex" ascii
$vql1 = "precondition:" ascii
$vql2 = "query:" ascii
$vql3 = "hunt_flows(" ascii
$x1 = "protobuf" ascii
condition:
4 of them
}
Running external programs or commands through Velociraptor results in either binaries being dropped to disk or shell executions or unmasked process executions. Files dropped on disk are scanned by AV / EDR and will trigger alerts. Shell executions and unmasked process executions can be matched with signatures for malicious activity, but are also scanned by AV / EDR and trigger alerts. When running artifacts that have the Velociraptor program itself do malicious actions, the AV did not trigger alerts but the EDR from our tests did alert on it.
Note: testing of AV and EDR detections was done with Windows Defender (non cloud enabled) and a widely used EDR vendor product.
Beyond endpoints, Velociraptor can also be identified on the network:
Velociraptor keeps a consistent network connection between each client and its server. This connection is TLS encrypted, using either HTTPS or Websocket Secure. Figure 1 shows the start of such TLS session:
Figure 1: TLS session captured in Wireshark
Velociraptor uses a hard-coded Servername in the certificate identifying the server against the clients (Note: this can be changed in the source code in constants.go, modifying PinnedServerName). A weaker indicator is client to server communication via TLS on port 8000, requesting h2 and http/1.1
alert tls $HOME_NET any -> $EXTERNAL_NET any (msg:"TLS CLIENT HELLO requesting connection to a Velociraptor Server"; flow:established,to_server; tls.sni; content:"VelociraptorServer"; nocase; sid:1030403; rev:1;)
alert tls $HOME_NET any -> $EXTERNAL_NET 8000 (msg:"TLS CLIENT HELLO possible Velociraptor Server"; flow:established,to_server; tls.alpn; content:"h2 http/1.1"; requires: version >= 8; sid:1030401; rev:1;)
(Note: these rules assume an externally hosted Velociraptor server; this could also be matched "any to any" for a wider net, potentially catching an internally running Velociraptor server)
We also looked at fingerprinting the network communication of the Velociraptor client (Windows and Linux, amd64 clients from the tagged versions of the last twelve months), specifically the JA3 and JA4 hashes (fingerprint of the TLS Client Hello messages):
JA3 and JA4 hashes change between versions of Velociraptor (but not every version) and are partially the same between Windows and Linux. These hashes seem to be unique (though the database we checked against is not too big) and are semi-stable, meaning the creation of an overview might be worth to enable detection of Velociraptor clients.
Velociraptor clients, Linux amd64 and Windows amd64, for the tagged versions v0.73.1 till v0.74.1 shared the following hashes:
- JA3: f616cc2741a43765279c0838d9333742
- JA4: t13d1313h2_f57a46bbacb6_9249cab70c77
Potential for DLL-Hijacking, especially for Offline Collectors
Because Velociraptor needs to be started as Administrator/SYSTEM, it is a prime target for DLL-Hijacking. DLL-Hijacking occurs when an application tries to load a DLL which does not exist and can be created by an attacker; or when an attacker replaces a legitimate DLL with a malicious copy. This can be used to escalate privileges and execute malicious code from within an otherwise benign application.
When Velociraptor is started without arguments, it tries to load the following DLLs from the folder where the Velociraptor executable is located:
- dbghelp.dll
- tdh.dll
- dbgcore.dll
- amsi.dll
Figure 2: Process Monitor output
Depending on which artifacts are executed, even more DLLs might be loaded from this folder. We performed a one-shot analysis, where we executed almost all artifacts, including ones which use third-party tools, and found more potential DLL Hijacks:
Figure 3: Potential DLL hijacking
Loading DLLs from the folder where the executable is located is a fixed part of the Windows DLL Search Order and can not be altered. In contrast, loading from the current working directory could be prevented by using SetDllDirectory. Just for fun, we ripped out the DLL imports for dbghelp.dll , tdh.dll and dbgcore.dll from the Velociraptor executable and it still started without problems. Only the loading of amsi.dll can not be removed/prevented.
Our experience shows that some fast and lightly prepared deployments of Velociraptor use default temporary folders for staging the executable and config file. This creates the opportunity for a malicious actor to place manipulated DLLs in those default folders. Due to the Windows DLL Search Order, these manipulated DLLs may then be run in parallel with a Velociraptor deployment.
If the default DLL search order can not be altered, what can you do? Simple!
Only install and start Velociraptor from a trusted folder with controlled content!
Conclusion
There are better alternatives for a C2 than Velociraptor. While the added bonus of being a blue team tool is nice, Velociraptor is not designed to be stealthy. It is also not excluded by default from AV / EDR scrutiny.
Also, make sure to only run it from a trusted folder.