These comma-separated values (CSV) files contain arguments used to run the tests, and the expected telemetry. The atomic-harness and related tools use the criteria to validate that the EDR software is providing the right telemetry.
Each CSV file is a collection of Atomic Test Validation Criteria. They have the following rows.
- Test header (e.g.
T1101.003,linux,2,some test name) - optional
ARG,!!!,FYIrows - one or more expected event rows
_E_ - lines can be empty
- lines starting with
#are comments and are ignored
T1105,linux,6,sftp remote file copy (pull)
ARG,local_file,/tmp/sftpdest-T1105_6
ARG,remote_host,$SERVER[rsync_ssh].addr
ARG,remote_port,$SERVER[rsync_ssh].port
ARG,username,$SERVER[rsync_ssh].username
ARG,remote_path,/tmp/
_E_,Process,cmdline~=sftp -P #{remote_port} #{username}@#{remote_host}:#{remote_path}
_E_,Netflow,TCP:*->#{remote_host}:#{remote_port}
_E_,File,WRITE,path=#{local_file}
The test header row needs to map directly to an Atomic Test. It has the following fields
- Technique (e.g.
T1027.001orT1003) To make it easy for you to get started with GitLab, here's a list of recommended next steps. - Platform -
linux,macos,windows. Some tests are marked to work for multiple platforms (usually linux and macos together). You will need separate validation criteria for each platform. - TestNum - a 1-based index for the test. The first test for technique
T1XXXhas TestNum == 1, the second will be 2, regardless of platform the tests are on. If the atomics file forT1027.001.yamlcontains 3 tests, one for each platform macos,windows,linux. Their numbers will be 1,2,3, respectively. - TestName - Copy this from the atomic
nameline
Every time a single Atomic Test is run, the harness passes the specifics in a JSON file. If there are ARG rows present, the runner goartrun will use these values when running the test script. Obviously, to use an ARG, it must exist in the Atomic Test yaml file.
An ARG row has the following columns:
ARG- input_argument name
- value
The Atomic yaml files allows for typed values, but here we just treat them as strings.
Apart from static values that are substituted as-is, there are some special values that the harness can provide:
- static value
$hostname: name of the host$ipaddr4: IPV4 address of host if present$ipaddr6: IPV6 address of host, if present$username: The username of current user (before running sudo for the harness)$subnet: First 3 sections of address. If$ipaddr4 == "10.0.0.5, the$subnetwill be string"10.0.0"$gateway: This is$subnet+ ".1". e.g."10.0.0.1"$netif: guess of the primary physical network interface
Values from server config file passed to harness:
$SERVER[id].addr: Hostname (if present) or the IPV4 or IPV6 addr of hostid$SERVER[id].port: If provided, specifies port number for service$SERVER[id].username: If needed, username for service$SERVER[id].password: If needed, password for service
Currently, if a test has a !!! row, it will be skipped. Use this when:
- test needs to be fixed. For example, when test hangs, needs user inputs, is missing dependency steps,etc.
- test is destructive and may delete important files
- test requires a target server that we don't have setup yet
- if test is manual, it will be skipped, so you shouldn't need this
The text on an FYI row will be printed out by the harness when the test runs. These can serve as reminders or comments.
The expected event rows have the following fields
_E_- Type (
Process,File or FileMod,Netflow,Auth,PTrace,etc.). Assume that the type is case-senstive for now SubType: ONLY forFileorNetflow- one of more
Field Match expressionsseparated by commas
NOTE: If an expression value contains a space, use double-quotes around the CSV column value. For example:
_E_,File,CHMOD,"path~=testdirwithspaceend /init "
The expressions are very simple and have a name operator value format.
Operators:
=String equals comparison~=String contains*=regex match
The ARG values can contain #{name} substitution for ARG variables. This makes it easy to copy the commands right from Atomic yaml files into an _E_,Process row. The values will be substituted before passing the criteria to the telemetry tool for validation.
The process row is mainly for matching cmdline field.
-
cmdline: created by putting theProcessargs together. NOTE: args that contain spaces will be wrapped in double-quote"like this" -
exepath: path of executable -
NOTE:
shorbashbuilt-in commands likeechowill not yieldProcessevents -
NOTE: currently, the agent does not show
pipeorfile redirectiondetails. Therefore, if a user typesecho $SOMEVAR | grep blah | sort | uniq >> /some/file, there will be 3 process events seen:grep blah,sort, anduniq. There will be aFileevent if the path is within the monitored paths, and the process writing the file will be theshell, not theuniqprocess.
Example:
_E_,Process,cmdline~=sftp -P #{remote_port} #{username}@#{remote_host}:#{remote_path}
The 3rd column (SubType) should only contain a single value. Therefore, if a file is expected to be CREATE or WRITE, just use WRITE. All File rows can match on the path field (currently that might be only one).
The Subtypes mostly align with the telemetry.proto types:
READWRITECHMOD: TODO: fields to match (mode?)UNLINKorDELETERENAME
Example:
_E_,File,WRITE,path=#{local_file}
The netflow format is protocol:local_ip:localport->remote_host:remote_port. Use * to indicate wildcard. Since some netflow records may have a dns hostname, the remote_host may be a hostname or ipaddr .
_E_,Netflow,TCP:*->#{remote_host}:#{remote_port}
The AMSI row is mainly for matching scan_content field.
scan_content: content from the AMSI scan.app_name: name of the application where the event occurred.
Example:
_E_,AMSI,scan_content~=:Get-NetTCPConnection
For windows registry event first specify the event_type as CREATEKEY/SETVALUEKEY/DELETEKEY, then if applicable enter the appropriate values of key_name and value_name
Example:
_E_,REG,event_type=SETVALUEKEY,key_name~=SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced,value_name=HideFileExt
The API row is mainly used to match function_called field . Other fields like parameter_names and parameter_values can be used to match parameter values.
Example:
_E_,API,function_called=<function_name>,parameter_names=<name_of_function_parameters>
The ETW format is: event_msg:<event message> followed by other optional fields chan_name and event_data_list
Example:
_E_,ETW,event_msg=<event_message>