Working With UAC

In my last blog post, I covered Systemd timers and some of the forensic artifacts associated with them. I’m also a fan of Thiago Canozzo Lahr’s UAC tool for collecting artifacts during incident response. So I wanted to add the Systemd timer artifacts covered in my blog post to UAC. And it occurred to me that others might be interested in seeing how to modify UAC to add new artifacts for their own purposes.

UAC is a module-driven tool for collecting artifacts from Unix-like systems (including Macs). The user specifies a profile file containing the list of artifacts they want to collect and an output directory where that collection should occur. Individual artifacts may be added to or excluded from the list of artifacts in the profile file using individual command line arguments.

A typical UAC command might look like:

./uac -p ir_triage -a memory_dump/avml.yaml /root

Here we are selecting the standard ir_triage profile included with UAC (“-p ir_triage“) and adding a memory dump (“-a memory_dump/avml.yaml“) to the list of artifacts to be collected. Output will be collected in the /root directory.

UAC’s configuration files are simple YAML configuration files and can be easily customized and modified to fit your needs. Adding new artifacts usually means adding a few lines to existing configuration files, or rarely creating a new configuration module from scratch. I’m going to walk through a few examples, including showing you how I added the Systemd timer artifacts to UAC.

Before we get started, let’s go ahead and check out the latest version from Thiago’s Github:

$ git clone https://github.com/tclahr/uac.git
Cloning into 'uac'...
remote: Enumerating objects: 5184, done.
remote: Counting objects: 100% (943/943), done.
remote: Compressing objects: 100% (284/284), done.
remote: Total 5184 (delta 661), reused 857 (delta 630), pack-reused 4241
Receiving objects: 100% (5184/5184), 32.29 MiB | 26.11 MiB/s, done.
Resolving deltas: 100% (3481/3481), done.
$ cd uac
$ ls
artifacts bin CHANGELOG.md CODE_OF_CONDUCT.md config CONTRIBUTING.md DCO-1.1.txt lib LICENSE LICENSES.md MAINTAINERS.md profiles README.md tools uac

The profiles directory contains the YAML formated profile files, including the ir_triage.yaml profile I referenced in my sample UAC command above:

$ ls profiles/
full.yaml  ir_triage.yaml  offline.yaml

The artifacts directory is an entire hierarchy of dozens of YAML files describing how to collect artifacts:

$ ls artifacts/
bodyfile  chkrootkit  files  hash_executables  live_response  memory_dump
$ ls artifacts/memory_dump/
avml.yaml  process_memory_sections_strings.yaml  process_memory_strings.yaml

Modifying Profiles

While the default profiles that come with UAC are excellent starting points, you will often find yourself needing to tweak the list of artifacts you wish to collect. This can be done with the “-a” command line argument as noted above. But if you find yourself collecting the same custom list of artifacts over and over, it becomes easier to create your own profile file with your specific list of desired artifacts.

For example, let’s suppose were were satisfied with the basic list of artifacts in the ir_triage profile, but wanted to make sure we always tried to collect a memory image. Rather than adding “-a memory_dump/avml.yaml” to every UAC command, we could create a modified version of the ir_triage profile that simply includes this artifact.

First make a copy of the ir_triage profile under a new name:

$ cp profiles/ir_triage.yaml profiles/ir_triage_memory.yaml

Now edit the ir_triage_memory.yaml file and make the changes shown below in bold:

name: ir_triage_memory
description: Incident response triage collection.
artifacts:
  - memory_dump/avml.yaml
  - live_response/process/ps.yaml
  - live_response/process/lsof.yaml
  - live_response/process/top.yaml
  - live_response/process/procfs_information.yaml
[... snip ...]

You can see where we added the “memory_dump/avml.yaml” artifact right at the top of the list of artifacts to collect. It is also extremely important to modify the “name:” line at the top of the file so that this name matches the name of the YAML file for the profile (without the “.yaml” extension). UAC will exit with an error if the “name:” line doesn’t match the base name of the profile file you are trying to use.

Now that we have our new profile file, we can invoke it as “./uac -p ir_triage_memory /root“.

Adding Artifacts

To add specific artifacts, you will need to get into the YAML files under the “artifacts” directory. In my previous blog posting, I suggested collecting the output of “systemctl list-timers --all” and “systemctl status *.timers“. You’ll often be surprised to find that UAC is already collecting the artifact you are looking for:

$ grep -rl systemctl artifacts
artifacts/live_response/system/systemctl.yaml

Here is the original systemctl.yaml file:

version: 1.0
artifacts:
  -
    description: Display all systemd system units.
    supported_os: [linux]
    collector: command
    command: systemctl list-units
    output_file: systemctl_list-units.txt
  -
    description: Display timer units currently in memory, ordered by the time they elapse next.
    supported_os: [linux]
    collector: command
    command: systemctl list-timers --all
    output_file: systemctl_list-timers_--all.txt
  -
    description: Display unit files installed on the system, in combination with their enablement state (as reported by is-enabled).
    supported_os: [linux]
    collector: command
    command: systemctl list-unit-files
    output_file: systemctl_list-unit-files.txt

It looks like “systemctl list-timers --all” is already being collected. Following the pattern of the other entries, it’s easy to add in the configuration to collect “systemctl status *.timers“:

version: 1.1
artifacts:
  -
    description: Display all systemd system units.
    supported_os: [linux]
    collector: command
    command: systemctl list-units
    output_file: systemctl_list-units.txt
  -
    description: Display timer units currently in memory, ordered by the time they elapse next.
    supported_os: [linux]
    collector: command
    command: systemctl list-timers --all
    output_file: systemctl_list-timers_--all.txt
  -
    description: Get status from all timers, including logs
    supported_os: [linux]
    collector: command
    command: systemctl status *.timer
    output_file: systemctl_status_timer.txt
  -
    description: Display unit files installed on the system, in combination with their enablement state (as reported by is-enabled).
    supported_os: [linux]
    collector: command
    command: systemctl list-unit-files
    output_file: systemctl_list-unit-files.txt

Note that I was careful to update the “version:” line at the top of the file to reflect the fact that the file was changing.

As far as the various file artifacts we need to collect, I discovered that artifacts/files/system/systemd.yaml was already collecting many of the files we want:

version: 2.0
artifacts:
  -
    description: Collect systemd configuration files.
    supported_os: [linux]
    collector: file
    path: /lib/systemd/system
    ignore_date_range: true
  -
    description: Collect systemd configuration files.
    supported_os: [linux]
    collector: file
    path: /usr/lib/systemd/system
    ignore_date_range: true
  -
    description: Collect systemd sessions files.
    supported_os: [linux]
    collector: file
    path: /run/systemd/sessions
    file_type: f
  -
    description: Collect systemd scope and transient timer files.
    supported_os: [linux]
    collector: file
    path: /run/systemd/transient
    name_pattern: ["*.scope"]

I just needed to add some configuration to collect transient timer files and per-user configuration files:

version: 2.1
artifacts:
  -
    description: Collect systemd configuration files.
    supported_os: [linux]
    collector: file
    path: /lib/systemd/system
    ignore_date_range: true
  -
    description: Collect systemd configuration files.
    supported_os: [linux]
    collector: file
    path: /usr/lib/systemd/system
    ignore_date_range: true
  -
    description: Collect systemd sessions files.
    supported_os: [linux]
    collector: file
    path: /run/systemd/sessions
    file_type: f
  -
    description: Collect systemd scope and transient timer files.
    supported_os: [linux]
    collector: file
    path: /run/systemd/transient
    name_pattern: ["*.scope", "*.timer", "*.service"]
  -
    description: Collect systemd per-user transient timers.
    supported_os: [linux]
    collector: file
    path: /run/user/*/systemd/transient
    name_pattern: ["*.timer", "*.service"]
  -
    description: Collect systemd per-user configuration.
    supported_os: [linux]
    collector: file
    path: /%user_home%/.config/systemd

The full UAC configuration syntax is documented in the UAC documentation.

But what if I made a mistake in my syntax? Happily, UAC includes a “--validate-artifacts-file” switch to check for errors:

$ ./uac --validate-artifacts-file ./artifacts/live_response/system/systemctl.yaml
uac: artifacts file './artifacts/live_response/system/systemctl.yaml' successfully validated.
$ ./uac --validate-artifacts-file ./artifacts/files/system/systemd.yaml
uac: artifacts file './artifacts/files/system/systemd.yaml' successfully validated.

In this case my changes only involved modifying existing artifacts files. If I had found it necessary to create new YAML files I would have also needed to add those new artifact files to my preferred UAC profile.

Sharing is Caring

If you add new artifacts to your local copy of UAC, please consider contributing them back to the project. The process for submitting a pull request is documented in the CONTRIBUTING.md document.

1 thought on “Working With UAC”

Comments are closed.