This artifact uses auditd and pslist to keep track of running processes using the Velociraptor process tracker.
The process tracker keeps track of exited processes, and resolves process call chains from it in memory cache.
This event artifact enables the global process tracker and makes it possible to run many other artifacts that depend on the process tracker.
auditd is used to track processes, and it must be installed on the system. If InstallAudit is enabled, the artifact will install it using apt-get (which only works on Debian-like operating systems, like Debian and Ubuntu).
When the artifact starts, it will insert audit rules that track the syscalls execve, exit and exit_group. These rules are removed when the event artifact is disabled. However, in case they are not removed automatically, for instance if velociraptor were to crash, the following commands (which must be run as root) will remove then:
auditctl -d exit,always -F arch=b64 -S execve -k procmon
auditctl -d exit,always -F arch=b32 -S execve -k procmon
auditctl -d exit,always -F arch=b64 -S exit,exit_group -k procmon_exit
auditctl -d exit,always -F arch=b32 -S exit,exit_group -k procmon_exit
Remember to replace the keys if you used keys other than the defaults.
Note that processes that are killed or do not shut down properly will note get their exit timestamps registered.
name: Linux.Events.TrackProcesses
author: Andreas Misje – @misje
description: |
This artifact uses auditd and pslist to keep track of running
processes using the Velociraptor process tracker.
The process tracker keeps track of exited processes, and resolves
process call chains from it in memory cache.
This event artifact enables the global process tracker and makes it
possible to run many other artifacts that depend on the process
tracker.
auditd is used to track processes, and it must be installed on the
system. If InstallAudit is enabled, the artifact will install it
using apt-get (which only works on Debian-like operating systems,
like Debian and Ubuntu).
When the artifact starts, it will insert audit rules that track
the syscalls *execve*, *exit* and *exit_group*. These rules are removed
when the event artifact is disabled. However, in case they are not
removed automatically, for instance if velociraptor were to crash,
the following commands (which must be run as root) will remove then:
```
auditctl -d exit,always -F arch=b64 -S execve -k procmon
auditctl -d exit,always -F arch=b32 -S execve -k procmon
auditctl -d exit,always -F arch=b64 -S exit,exit_group -k procmon_exit
auditctl -d exit,always -F arch=b32 -S exit,exit_group -k procmon_exit
```
Remember to replace the keys if you used keys other than the defaults.
Note that processes that are killed or do not shut down properly will
note get their exit timestamps registered.
precondition: SELECT OS From info() where OS = 'linux'
type: CLIENT_EVENT
required_permissions:
- EXECVE
parameters:
- name: InstallAudit
type: bool
default: False
description: Run apt-get update and apt-get install to ensure that auditd is installed
- name: AuditKeyExecve
default: procmon
description: Key to use for execve syscalls. Change to match an existing key if you are already using audit to track processes.
- name: AuditKeyExit
default: procmon_exit
description: Key to use for exit syscalls. Change to match an existing key if you are already using audit to track processes.
- name: RemoveRules
type: bool
default: True
description: Remove rules when removing the event artifact
- name: AlsoForwardUpdates
type: bool
description: Upload all tracker state updates to the server
- name: MaxSize
type: int64
description: Maximum size of the in-memory process cache (default 10k)
- name: AddEnrichments
type: bool
description: Calculate hashes on process binaries
- name: AuditCtlExe
description: Path to the auditctl binary
default: /sbin/auditctl
sources:
- query: |
/* Test whether the auditctl binary exists at the expected path: */
LET AuditInstalled = SELECT *
FROM stat(filename=AuditCtlExe)
LET _ <= SELECT *
FROM if(
condition=NOT AuditInstalled
AND InstallAudit,
then={
SELECT *
FROM chain(
a_update={
SELECT
log(
message='Updating package index before installing auditd',
level='INFO')
FROM execve(argv=['apt-get', '-y', 'update'])
},
b_install={
SELECT log(message='Installing auditd using apt-get', level='INFO')
FROM execve(
argv=['apt-get', '-y', '-o', 'Debug::pkgProblemResolver=yes', '--no-install-recommends', 'install', 'auditd'])
})
})
LET AuditCtl(action, syscalls, key) = SELECT *
FROM if(
condition=AuditInstalled,
then={
SELECT *
FROM foreach(
row=('b64', 'b32', ),
query={
SELECT *
FROM execve(
argv=['auditctl', action, 'exit,always', '-F', 'arch=' + _value, '-S', syscalls, '-k', key])
WHERE AuditInstalled
})
})
LET _ <= SELECT *
FROM AuditCtl(action='-a',
syscalls='execve',
key=AuditKeyExecve)
LET _ <= SELECT *
FROM AuditCtl(action='-a',
syscalls='exit,exit_group',
key=AuditKeyExit)
LET _ <= atexit(
query={
SELECT *
FROM if(
condition=RemoveRules,
then={
SELECT
log(
message='Removing audit rules',
level='INFO')
FROM chain(
r1={
SELECT *
FROM AuditCtl(action='-d',
syscalls='execve',
key=AuditKeyExecve)
},
r2={
SELECT *
FROM AuditCtl(action='-d',
syscalls='exit,exit_group',
key=AuditKeyExit)
})
})
})
LET Users <= memoize(
query={
SELECT
Uid AS UID,
User
FROM Artifact.Linux.Sys.Users()
},
key='UID')
LET UpdateQuery = SELECT *
FROM foreach(
row={
SELECT *
FROM audit()
WHERE AuditKeyExecve IN Tags OR AuditKeyExit IN Tags
},
query={
SELECT *
FROM switch(
start={
SELECT
Process.pid AS id,
Process.ppid AS parent_id,
'start' AS update_type,
dict(
Pid=Process.pid,
Ppid=Process.ppid,
Name=Process.name,
StartTime=timestamp(
string=Timestamp),
EndTime=NULL,
Username=get(
item=Users,
field=User.ids.uid).User,
Exe=Process.exe,
CommandLine=join(
sep=' ',
array=Process.args),
CurrentDirectory=get(
item=Process,
member='CWD'),
TerminalSessionId=Session,
User=User,
Process=Process) AS data,
timestamp(
string=Timestamp) AS start_time,
NULL AS end_time
FROM scope()
WHERE AuditKeyExecve IN Tags
},
end={
SELECT
Process.pid AS id,
NULL AS parent_id,
'exit' AS update_type,
dict() AS data,
NULL AS start_time,
timestamp(
string=Timestamp) AS end_time
FROM scope()
WHERE AuditKeyExit IN Tags
})
})
LET SyncQuery = SELECT
Pid AS id,
Ppid AS parent_id,
CreateTime AS start_time,
dict(
Name=Name,
Username=Username,
Exe=Exe,
CommandLine=CommandLine) AS data
FROM pslist()
LET Tracker <= process_tracker(
max_size=MaxSize,
sync_query=SyncQuery,
update_query=UpdateQuery,
sync_period=60000,
enrichments=if(
condition=AddEnrichments,
then=['''x => dict(Hashes=hash(
path=x.Data.Exe))'''],
else=[]))
SELECT *
FROM if(
condition=AuditInstalled,
then={
SELECT *
FROM process_tracker_updates()
WHERE update_type = 'stats' OR AlsoForwardUpdates
},
else={
SELECT
log(
message='auditd is not installed, and it is either set not to be installed or failed to install, aborting',
level='INFO')
FROM scope()
})