Other use cases for artifacts

While you can learn a lot about what artifacts are usually used for by looking through the hundreds of artifacts that ship with the Velociraptor binary, there are certainly many more use cases – including ones that nobody has even thought of yet!

Artifacts are a powerful mechanism for encapsulating information, including but not limited to VQL.

Wrapper Artifacts

Using the Artifact plugin, you can call other artifacts . A common use for this is to create “wrapper artifacts” which can:

  • combine multiple artifacts into a single artifact
    name: Windows.Packs.Persistence
    description: This artifact pack collects various persistence mechanisms in Windows.
    sources:
      - name: WMI Event Filters
        query: SELECT * FROM Artifact.Windows.Persistence.PermanentWMIEvents()
      - name: Startup Items
        query: SELECT * FROM Artifact.Windows.Sys.StartupItems()
      - name: Debug Bootstraping
        query: SELECT * FROM Artifact.Windows.Persistence.Debug()
    
  • add additional sources to an existing artifact
    name: Generic.Client.DiskSpace.Extra
    sources:
      - name: DiskSpace
        query: SELECT * FROM Artifact.Generic.Client.DiskSpace()
      - name: ExtraInfo
        query: SELECT * FROM ...
    
  • filter or manipulate results from other artifacts
    SELECT * FROM Artifact.Windows.Sysinternals.Autoruns()
    WHERE Category =~ "Services" AND `Launch String` =~ "COMSPEC"
    
  • provide custom parameter defaults (i.e. your own “presets”) to other artifacts
    name: Find.DotnetStartupHooks
    description: Finds DOTNET_STARTUP_HOOKS using Windows.Search.FileFinder
    parameters:
      - name: SearchFilesGlobTable
        type: csv
        default: |
          Glob
          HKEY_USERS\*\Environment\DOTNET_STARTUP_HOOKS\*
          HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\DOTNET_STARTUP_HOOKS\*
      - name: Accessor
        default: registry
      - name: Upload_File
        default: Y
    sources:
      - precondition: SELECT OS From info() where OS = 'windows'
        query: |
          SELECT * FROM Artifact.Windows.Search.FileFinder(SearchFilesGlobTable=SearchFilesGlobTable,
                                                          Accessor=Accessor,
                                                          Upload_File=Upload_File)
    
  • simplify UI parameter choices for users by only presenting them with parameters that you want them to change, while hiding and defining preset values for parameters that you don’t want them to change
    name: Find.DotnetStartupHooks
    description: Finds DOTNET_STARTUP_HOOKS using Windows.Search.FileFinder
    parameters:
      - name: SearchFilesGlobTable
        # This parameter can be customized by the user
        type: csv
        default: |
          Glob
          HKEY_USERS\*\Environment\DOTNET_STARTUP_HOOKS\*
          HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\DOTNET_STARTUP_HOOKS\*
      - name: Accessor
        # This parameter is hidden from the user
        default: registry
        type: hidden
      - name: Upload_File
        # This parameter is hidden from the user
        default: Y
        type: hidden
    sources:
      - precondition: SELECT OS From info() where OS = 'windows'
        query: |
          SELECT * FROM Artifact.Windows.Search.FileFinder(SearchFilesGlobTable=SearchFilesGlobTable,
                                                          Accessor=Accessor,
                                                          Upload_File=Upload_File)
    

Wrapper artifacts can be used as a way to limit users’ access to built-in artifact capabilities by using the above methods and then also hiding the called artifact from the GUI. In addition you could consider applying the security mechanisms described here which allow low-privilege users to only run certain “Basic” artifacts.

Utility Artifacts

The last example showed how to make an artifact that performs a very specific task by wrapping the functionality contained in the more general-purpose Windows.Search.FileFinder artifact. In that context, the called artifact serves as a utility for the calling artifact.

The calling artifact in the previous example contained much simpler logic than the called artifact, however that’s not always the case: the Windows.KapeFiles.Targets artifact is an example of a relatively complex artifact that wraps the much simpler Generic.Collectors.File utility artifact.

Another utility artifact that you may often encounter is Generic.Utils.FetchBinary. This artifact contains VQL which ensures the delivery of third-party tools to the endpoint, so you will see it called in just about every artifact that uses tools. These artifacts could easily have implemented the same logic to ensure tool delivery, but it is cleaner, more efficient, and more consistent to offload the logic to a purpose-built artifact that can be reliably reused.

Artifacts designed to be used as utilities (sometimes also referred to as “helper” artifacts) might not be intended to be collected directly, and this may influence the design of the artifact. For example, the Generic.Utils.FetchBinary artifact is not intended to be collected directly and therefore doesn’t need to be particularly user-friendly. To avoid confusing users with such artifacts you could choose to hide these artifacts , as mentioned previously. Hidden artifacts can still be called from other artifacts.

Server “Bootstrap” Artifacts

Velociraptor allows us to specify startup artifacts via it’s configuration. That is, instead of using the GUI to configure the collection of CLIENT_EVENT and SERVER_EVENT artifacts, we can preconfigure these items via the config.

The config settings which provide this are:

  • Frontend.default_server_monitoring_artifacts: specifies the initial client monitoring table that will be created. By default, Velociraptor collects endpoint CPU and Memory telemetry from all endpoints. You can remove this, or specify a different client artifact to collect.
  • Frontend.default_client_monitoring_artifacts: specifies an initial set of server event artifacts to collect.

The config also allows us to define users and orgs that will be created when the server is first run, using the following settings:

  • GUI.initial_users
  • GUI.initial_orgs

Going beyond the config options

While this may be sufficient for some server setup situations, we may want to automate many other things during setup so that we don’t have to rely on time-consuming and potentially error-prone manual configuration via the GUI.

This flexibility is provided by the config setting

  • Frontend.initial_server_artifacts

which allows us to specify one or more SERVER type artifacts that will be run when the Velociraptor server is started for the very first time. The server detects that it is being run for the first time by checking for the presence of the file config/install_time.json.db in the datastore: if the file is not found then the server assumes it’s the first time it is being run.

Since the initial_server_artifacts setting allows us to run server artifacts, this gives us access to the full capabilities of VQL in setting up the server. There are many VQL functions that can be useful when initializing a new server which don’t have equivalent config settings.

We could, for example:

  • create users and customize user profiles using the user_create and user_options functions.
  • create and start hunts using the hunt_add function.
  • create notebooks using the notebook_create function (based on custom notebook templates).
  • configure client monitoring using the set_client_monitoring function or server monitoring using the set_server_monitoring function.
  • run server artifacts which import other artifacts
  • run artifacts which define and download tools to the server’s tool inventory
    (or we could add/update tools using VQL’s inventory_add and inventory_get functions).

Because we can specify multiple server artifacts in the initial_server_artifacts setting, we might choose to have several artifacts where each one addresses a particular aspect of server initialization, or we could have one larger “bootstrap” artifact that does everything we want.

These artifacts are just normal server artifacts which can be developed and tested by running them in the “Server Artifacts” screen in the GUI (obviously on a non-production/development server!).

These initial server artifacts can also call other artifacts (either built-in or custom) to aid in the setup process.

Custom artifacts, as well as the “bootstrap” artifacts themselves, can be embedded in the config or loaded from a folder .

Client startup artifacts

Sometimes we may want the client to do something very early on, as soon as it starts and potentially even before client enrollment.

Such startup tasks could be, for example:

  • copying a file from the network
  • cleaning up some old files
  • setting up or starting a VPN client (perhaps to enable the client to connect to the server)
  • adding an anti-malware exclusion (see for example Windows.Utils.DefenderExclusion )

The Client.additional_event_artifacts configuration item allows us to do this by specifying artifacts that should run when the client starts. Although these artifacts are run as event artifacts (never expected to terminate), they can contain any valid client-side VQL.

These artifacts will run every time the client starts, even before enrollment. Because client artifacts are normally delivered from the server – and in this case the client might not have enrolled with the server yet – this setting generally requires the artifacts to be included in the client config’s autoexec.artifact_definitions section.

If these artifacts are run before enrollment then the data produced will be queued and delivered to the server after enrollment, as event queries. To ensure that the server has a corresponding event queue to receive these events, you’ll also need to also add the artifact to the server’s artifact repository.

Sourceless Artifacts

Artifacts can have ZERO or more sources. It may seem strange at first to think about having artifacts with no sources, however this allows for some interesting use cases.

We have already seen that notebook templates are a special use case for artifact definitions. While notebook templates do have sources, these contain templates for notebook cells rather than queries.

Furthermore, if you’ve spent any time looking through the list of built-in artifacts, you may have noticed several that have little to nothing but an artifact name. The purpose of such artifacts is to establish event queues on the server, which intercept and queue messages from clients and from the server itself. These artifacts can have sources, which would typically do something with the event messages, but they aren’t required to have sources (for example, other artifacts may be created to act on the event queue’s messages).

no parameters!no sources!just an event queue.
Server.Internal.ClientDelete establishes a server event queue

Thats all it contains
Thats all it contains

Artifacts without sources cannot be directly launched via the GUI and are also filtered out from all the preset filter views on the Artifacts screen, except for the filter category “Include Empty Sources”. This filter will show all artifacts including those that don’t have sources. This aspect is useful because it means you can define sourceless artifacts without them being collectible, and therefore such artifacts don’t clutter artifact selection lists or confuse users.

Export-only artifacts (sharing VQL via export-imports)

An artifact with no sources and an export section can be used:

  • for defining shared variables or “constants”
  • for defining shared custom functions and plugins

This can help ensure consistency across artifacts and simplify artifacts that have large sections of generically reusable code. In particular, artifacts that include binary parser profiles can be difficult to read because you first have to scroll past the potentially very long profile definition to get to the VQL. Putting such lengthy blocks into a sourceless artifact’s export section and then importing it when needed makes the latter artifact much more user-friendly.

name: Windows.Forensics.Shellbagsdescription: ...parameters:- name: SearchSpecs...sources:- query: |...imports:- Windows.Forensics.Lnkname: Windows.Forensics.JumpListsdescription: ...parameters:- name: Globs...sources:- query: |...imports:- Windows.Forensics.Lnkname: Windows.Forensics.Lnkdescription: ...export: |LET Profile = '''[["ShellLinkHeader", 0, [["HeaderSize", 0, "uint32"],["__LinkClsID", 4, "String", {"length": 16,"term": ""}],["LinkClsID", 0, "Value", {"value": "x=>format(format='%x',args=x.__LinkClsID)"}],["LinkFlags", 20, "Flags", {"type": "uint32","bitmap": {"HasLinkTargetIDList": 0,"HasLinkInfo": 1,"HasName": 2,"HasRelativePath": 3,"HasWorkingDir": 4,"HasArguments": 5,"HasIconLocation": 6,"IsUnicode": 7,"ForceNoLinkInfo": 8,"HasExpString": 9,"RunInSeparateProcess": 10,"HasDarwinID": 12,"RunAsUser": 13,"HasExpIcon": 14,"NoPidlAlias": 15,"RunWithShimLayer": 17,"ForceNoLinkTrack": 18,"EnableTargetMetadata": 19,"DisableLinkPathTracking": 20,"DisableKnownFolderTracking": 21,"DisableKnownFolderAlias": 22,"AllowLinkToLink": 23,"UnaliasOnSave": 24,"PreferEnvironmentPath": 25,"KeepLocalIDListForUNCTarget": 26}}],["FileAttributes", 24, "Flags", {"type": "uint32","bitmap": {"FILE_ATTRIBUTE_READONLY": 0,"FILE_ATTRIBUTE_HIDDEN": 1,"FILE_ATTRIBUTE_SYSTEM": 2,"FILE_ATTRIBUTE_DIRECTORY": 4,"FILE_ATTRIBUTE_ARCHIVE": 5,"FILE_ATTRIBUTE_NORMAL": 7,"FILE_ATTRIBUTE_TEMPORARY": 8,"FILE_ATTRIBUTE_SPARSE_FILE": 9,"FILE_ATTRIBUTE_REPARSE_POINT": 10,"FILE_ATTRIBUTE_COMPRESSED": 11,"FILE_ATTRIBUTE_OFFLINE": 12,"FILE_ATTRIBUTE_NOT_CONTENT_INDEXED": 13,"FILE_ATTRIBUTE_ENCRYPTED": 14,}}],...
Reusing VQL can improve artifact legibility

Ultimately when the importing artifact is collected the imports are resolved and the compiled artifact is sent to the client which includes the imported VQL, so there is no saving in terms of network bandwidth. It just improves legibility and code consistency.

Event queues

An artifact with no sources can be used to define server and client event queues .

These may have sources, but can still be useful without them, as demonstrated by the Server.Internal.ClientDelete artifact shown above.

Documentation

Artifacts with no sources and only informational fields can be used to store internal documentation; particularly since the description field supports Markdown and is indexed and searchable in the GUI.

You could perhaps use it to store Velociraptor SOP documentation or other DFIR-related information that could be useful to the team working on your server.

As mentioned above, artifacts without sources cannot be directly launched via the GUI and are also filtered out from all the preset filter views on the Artifacts screen, which means that you can create such artifacts without them being collectible, and without them appearing on artifact selection lists where they might confuse users.

Artifacts-as-documentation
Artifacts-as-documentation

Standalone Tool definitions

It is possible to use a single sourceless artifact to store all your tool definitions, which can then be referred to (using only the name and optionally a version number) in other artifacts that use those tools.

In fact Velociraptor does this already with the built-in Server.Internal.ToolDependencies artifact.

If you define the artifact as a SERVER artifact then running it will download the tools from the URLs specified in the tool definitions. This provides a quick way to ensure that your server’s tools inventory is populated with all the tools your artifacts will need before you try to collect those artifacts. You can additionally use such an artifact as one of your “bootstrap artifacts ”, as described above.

Manually collecting such an artifact also serves as a way to update all the tools defined in the artifact.