Nzitf Velociraptor
Nzitf Velociraptor
Hunting Evil!
● Google’s GRR
● Facebook’s OSQuery
● Google’s Rekall
https://docs.velociraptor.velocidex.com/
https://github.com/Velocidex/velociraptor
Velociraptor workshop
What will we do today?
Send Chan
Client Front
Recv Chan End
GUI
File Data
Store store
Main components - all in one binary
Frontend GUI
When Velociraptor acts as a client, it simply runs VQL queries and relays them to
the server.
You can also just run VQL queries directly - for the first part today we will do that
Basic concepts
Scope:
LET Expressions
+--------------+---------+-------+-------------------+------+---------+
| IP_address | HW_type | Flags | HW_address | Mask | Device_ |
+--------------+---------+-------+-------------------+------+---------+
| 192.168.0.4 | 0x1 | 0x0 | 00:00:00:00:00:00 | * | enp6s0 |
| 192.168.0.16 | 0x1 | 0x2 | 6c:29:95:ca:c4:e8 | * | enp6s0 |
| 192.168.0.10 | 0x1 | 0x2 | 34:6b:46:96:f9:85 | * | enp6s0 |
+--------------+---------+-------+-------------------+------+---------+
Example: wmi() plugin.
VQL plugin wmi() takes two args - the query and the namespace
Developing WMI based Artifacts
WMI is very powerful - exposes so much host state.
Regex
operator
VQL Operators and protocols
1. VQL plugins return arbitrary objects - not just simple primitives.
2. Protocols are a way to define how operators interact with arbitrary objects.
3. For example does the following expression make sense?
LHS is string, RHS is int -> Does not make sense -> return a NULL object.
+--------------------+
| Parent.NOSUCHFIELD |
select Parent.NOSUCHFIELD from pslist() +--------------------+
| null |
Output type discovery
In order to determine what data is available from a plugin:
● Materialized - Expands the query into memory then each evaluation operates
on the same cached result set.
glob() timestamp()
upload() now()
wmi() upload()
yarascan()
Exercise:
Archive all files in User’s home directory that were changed in the last day.
VQL Plugins:
There are many VQL plugins that read files. Most also take an accessor
parameter. This allows all plugins to work on files as well as reg keys etc.
Filesystem Access
Ultimately everything is a VQL query, but since glob and upload are so useful,
there is direct command line access. This provides raw NTFS access:
It is also a good way to practice globbing
Use the artifact to collect files in the windows temp directory which have been
changed in the last hour.
Chaining artifacts
● Artifacts encapsulate a VQL Query:
○ Ideally we don't need to understand how an artifact is collected, simply the columns which are
returned.
● This allows us to define artifacts as building blocks to other artifacts.
○ It is possible to run an artifact from within a VQL query. The “Artifact” plugin is an artifact
runner:
Clients
Web GUI
Admin Server
Client-Server communications
● Full encrypted communications over HTTP
○ Each deployment creates a CA
○ Server key is signed by CA
● Keys are embedded in the client’s config file.
○ CA public key is embedded in the client’s
○ Client will only trust server certificate signed by the embedded CA
○ Server will only communicate with clients that present the deployment nonce (shared secret).
● Velociraptors comms is based on GRR’s protocol.
○ Main aim is to have zero registration clients - no a-priori knowledge of clients.
○ When clients are installed they generate private key then are enrolled by the server.
Deploying velociraptor
1. Creating an initial configuration:
$ export VELOCIRAPTOR_CONFIG=server.config.yaml
$ velociraptor config client > client.config.yaml
We can embed the client’s configuration in the binary - this makes it easier to
distribute - One file to rule them all!
$ my_velociraptor.exe client
NOTE: you can not run 2 clients on the same machine at the same time! If you try,
one will back off with a conflict message. Try to stop the service if this happens.
Installing the service
The binary is copied to its final location, and the service is created.
Develop the relevant VQL queries and then add to the server’s config file under
the Flows.interrogate_additional_queries section.
Solution
Flows:
interrogate_additional_queries:
- Name: Listening ports
VQL: SELECT * FROM Artifact.Windows.Network.ListeningPorts()
The Virtual File System (VFS)
● Contains information about the client
● Only reflects information already collected by the server.
● Top level is the VFS accessor:
○ File - access files on the client by file APIs
○ NTFS - access files on the client using raw NTFS parsing.
○ Registry - access the registry using the OS APIs
○ Monitoring - access the client’s monitoring subsystem (more on this later).
Exercise: Detect runkey persistence using PS
We are concerned about persistence through powershell run keys.
Write an artifact which collects the user’s NTUSER.dat if they are likely to have
such a backdoor.
Velociraptor
Monitoring
VQL: Event Queries
● Normally a VQL query returns a result set and then terminates.
● However some VQL plugins can run indefinitely or for a long time.
○ These are called Event VQL plugins since they can be used to generate events.
An Event query does not complete on its own - it simply returns partial
results until cancelled.
Rows
Partial Result
Sets
● Wait time Query VQL plugin
● Max rows
Example: Monitor event logs for certain events.
● The Velociraptor wait_evtx() VQL plugin can wait on an event log for new
events.
● The log file is checked periodically for new events, which are emitted by the
plugin.
● The events can be filtered by the normal VQL filters.
● Result sets are emitted in accordance with wait_max and max_rows.
● Wait_max: The maximum length of time we wait before emitting partial
results.
● Max_rows: The max number of rows we allow in one result set.
Let’s detect service installation
systemLogFile = C:/Windows/System32/Winevt/Logs/System.evtx
winpmem.exe -L
Winpmem loaded a kernel driver
from the temp directory … Very
suspicious!
Detect running a command using PsExec
● Sysinternals PsExec is a common way to run a command remotely
● It works by copying a service binary to the Admin$ share and then starting the
service.
● Try it locally - e.g. get a system shell:
○ PsExec.exe -s -i cmd.exe
● You should be able to see an event generated by the above artifact:
WMI Event sources: Process Execution
Another popular VQL event plugin is the wmi_events() plugin.
Registers a WMI event listener and passes the event data to VQL filters.
SELECT timestamp(epoch=atoi(string=Parse.TIME_CREATED) / 10000000 - 11644473600 ) as Timestamp,
Parse.ParentProcessID as PPID,
Parse.ProcessID as PID, Unfortunately the WMI
Parse.ProcessName as Name, { event does not provide
SELECT CommandLine the full cmdline so we
FROM wmi(
query="SELECT * FROM Win32_Process WHERE ProcessID = " +
need to run a second
format(format="%v", args=Parse.ProcessID), subquery for the PID on
namespace="ROOT/CIMV2") each emitted row.
} AS CommandLine
FROM wmi_events(
query="SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process'",
wait=5000000,
namespace="ROOT/CIMV2")
Event artifacts
● Just like regular artifacts, Event Artifacts are a way to encapsulate Event VQL
queries.
● Event Artifacts never terminate - they just continue to generate events.
Create an event Artifact which records the total amount of CPU used by the
Velociraptor client every minute. Also record the client’s memory footprint.
We can now go back and see what was the load footprint of the client on the
endpoint at any time in the past.
Proactively detecting
attackers
The Mitre Att&ck framework
● Mitre maintains a valuable resource to collect information about attacks seen
in the wild. The Mitre Att&ck framework.
Enumerate all Scheduled tasks
Scheduled tasks
● Modern systems deprecated at.exe
● Create a new scheduled task to run
notepad.exe:
○ schtasks /create /S testcomputer /st 05:28
/tr notepad.exe /tn gaming /sc once
● This works by invoking the Create method of the Win32_Process WMI class.
● This is very suspicious. Lets implement an Event Artifact to detect this.
○ SELECT * FROM MSFT_WmiProvider_ExecMethodAsyncEvent_Pre
WHERE ObjectPath="Win32_Process" AND MethodName="Create"
sources:
- precondition:
SELECT OS from info() where OS = "windows"
queries:
- LET users <= SELECT Name, UUID FROM Artifact.Windows.Sys.Users()
- SELECT basename(path=dirname(path=FullPath)) as SID, {
SELECT Name FROM users WHERE UUID = basename(path=dirname(path=FullPath))
} As UserName,
Name as Binary,
timestamp(winfiletime=binary_parse(
string=Data.value, target="int64").AsInteger) as Bam_time
FROM glob(globs=bamKeys + "\\*", accessor="reg")
WHERE Data.type = "BINARY"
WMI Event consumer backdoor
Install WMI Event subscription
$instanceFilter = ([wmiclass]"\\.\root\subscription:__EventFilter").CreateInstance()
$instanceFilter.QueryLanguage = "WQL"
$instanceFilter.Query = "select * from __instanceModificationEvent within 5 where targetInstance isa
'win32_Service'"
$instanceFilter.Name = "ServiceFilter"
$instanceFilter.EventNamespace = 'root\cimv2'
$result = $instanceFilter.Put()
$newFilter = $result.Path
$instanceConsumer = ([wmiclass]"\\.\root\subscription:LogFileEventConsumer").CreateInstance()
$instanceConsumer.Name = 'ServiceConsumer'
$instanceConsumer.Filename = "C:\Users\Log.log"
$instanceConsumer.Text = 'A change has occurred on the service: %TargetInstance.DisplayName%'
$result = $instanceConsumer.Put()
$newConsumer = $result.Path
$instanceBinding = ([wmiclass]"\\.\root\subscription:__FilterToConsumerBinding").CreateInstance()
$instanceBinding.Filter = $newFilter
$instanceBinding.Consumer = $newConsumer
$result = $instanceBinding.Put()
$newBinding = $result.Path
Remove WMI Event Subscription
([wmi]$newFilter).Delete()
([wmi]$newConsumer).Delete()
([wmi]$newBinding).Delete()
Refs:
● https://learn-powershell.net/2013/08/14/powershell-and-events-permanent-wmi-event-subscriptions/
● https://www.fireeye.com/content/dam/fireeye-www/services/pdfs/sans-dfir-2015.pdf
Try this event subscription! It is similar to what we did earlier with Velociraptor :-).
Write a Velociraptor artifact to list all such bindings.
● The event subscription writes a log file when a service is started/stopped.
● Start off with listing the WMI filter to consumer binding.
● Extract the consumer name and event names and their types.
● Query the other WMI classes for these
Solution
LET FilterToConsumerBinding = SELECT parse_string_with_regex(
string=Consumer,
regex=['((?P<namespace>^[^:]+):)?(?P<Type>.+?)\\.Name="(?P<Name>.+)"']) as
Consumer,
parse_string_with_regex(
string=Filter,
regex=['((?P<namespace>^[^:]+):)?(?P<Type>.+?)\\.Name="(?P<Name>.+)"']) as Filter
FROM wmi(
query="SELECT * FROM __FilterToConsumerBinding",
namespace=namespace)
Solution
SELECT {
SELECT * FROM wmi(
query="SELECT * FROM " + Consumer.Type,
namespace=if(condition=Consumer.namespace,
then=Consumer.namespace,
else=namespace)) WHERE Name = Consumer.Name
} AS ConsumerDetails,
{
SELECT * FROM wmi(
query="SELECT * FROM " + Filter.Type,
namespace=if(condition=Filter.namespace,
then=Filter.namespace,
else=namespace)) WHERE Name = Filter.Name
} AS FilterDetails
FROM FilterToConsumerBinding
Conclusions
Velociraptor is an open source project
(Apache License)
https://docs.velociraptor.velocidex.com/
https://github.com/Velocidex/velociraptor