Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added artifacts for eBPF plugin #3884

Merged
merged 1 commit into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions artifacts/definitions/Linux/Events/EBPF.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Linux.Events.EBPF
description: |
This artifact forwards EBPF events generated on the endpoint.

precondition: |
SELECT OS From info() where OS = 'linux'

type: CLIENT_EVENT

parameters:
- name: Events
description: Events to forward
type: csv
default: |
Event,Desc,Enabled
accept4,A process accepted a connection from remote,Y
bpf_attach,A bpf program is attached,Y
chdir,Process changes directory,N
fchownat,File ownership is changed,Y
file_modification,A process changes the ctime of a file,N
kill,Kill another process,Y
magic_write,Intercepts file writes to capture the header magic,N
mkdir,Process makes new directory,N
module_free,A module is unloaded from the kernel,Y
mount,A filesystem is mounted,Y
openat,A process is opening a file (noisy),N
openat2,A process is opening a file (noisy),N
sched_process_exec,A process starts,Y
sched_process_exit,A process ends,Y
security_file_open,Files are opened,Y
security_inode_mknod,A new node is created with mknod (e.g. fifo or device file),Y
security_inode_rename,File is being renamed,N
security_inode_symlink,Create a symlink,Y
security_kernel_post_read_file,Fires when the kernel reads a file (e.g. module),Y
security_socket_accept,A process accepted a connection,Y
security_socket_bind,A process bind to a local port,Y
security_socket_connect,A process is making a connection,Y
setxattr,Setting and extended attribute to a file,Y
umount2,A filesystem is being unmounted,Y
unlink,A file is deleted,Y

sources:
- query: |
LET SelectedEvents <= SELECT * FROM Events WHERE Enabled =~ "Y"

SELECT * FROM watch_ebpf(events=SelectedEvents.Event)
278 changes: 54 additions & 224 deletions artifacts/definitions/Linux/Events/TrackProcesses.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: Linux.Events.TrackProcesses
author: Andreas Misje – @misje
description: |
This artifact uses auditd and pslist to keep track of running
This artifact uses ebpfg and pslist to keep track of running
processes using the Velociraptor process tracker.

The process tracker keeps track of exited processes, and resolves
Expand All @@ -11,239 +10,70 @@ description: |
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).
NOTE: Unlike Windows.Events.TrackProcesses, the eBPF program is
already built into Velociraptor so this artifact does not depend on
external tools.

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'
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()
})
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 UpdateQuery = SELECT * FROM foreach(
row={
SELECT * FROM watch_ebpf(events=["sched_process_exit", "sched_process_exec"])
}, query={
SELECT * FROM switch(a={
SELECT System.ProcessID AS id,
System.ParentProcessID AS parent_id,
"start" AS update_type,
dict(Pid=System.ProcessID,
Ppid=System.ParentProcessID,
Name=System.ProcessName,
StartTime=System.Timestamp,
EndTime=NULL,
Username=System.UserID,
Exe=EventData.cmdpath,
CommandLine=join(array=EventData.argv, sep=" ")) AS data,

System.Timestamp AS start_time,
NULL AS end_time
FROM scope()
WHERE System.EventName =~ "exec"
}, end={
SELECT System.ProcessID AS id,
NULL AS parent_id,
"exit" AS update_type,
dict() AS data,
NULL AS start_time,
System.Timestamp AS end_time
FROM scope()
WHERE System.EventName =~ "exit"
})
})

LET Tracker <= process_tracker(max_size=MaxSize,
sync_query=SyncQuery, update_query=UpdateQuery, sync_period=60000)

SELECT * FROM process_tracker_updates()
WHERE update_type = "stats" OR AlsoForwardUpdates
29 changes: 28 additions & 1 deletion docs/references/vql.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1779,6 +1779,13 @@
plugin (see Windows.Events.DNSQueries)
type: Plugin
category: windows
- name: ebpf_events
description: |
Dump information about potential ebpf_events that can be used by the
watch_ebpf() plugin.
type: Plugin
platforms:
- linux_amd64_cgo
- name: efivariables
description: Enumerate efi variables.
type: Plugin
Expand Down Expand Up @@ -10262,6 +10269,27 @@
- linux_amd64_cgo
- windows_386_cgo
- windows_amd64_cgo
- name: watch_ebpf
description: |
Watch for events from eBPF.

This plugin uses the integrated tracee eBPF engine to stream events.

See https://github.com/Velocidex/tracee_velociraptor for more details.
type: Plugin
args:
- name: events
type: string
description: A list of event names to acquire. You can get a list of event names using the ebpf_events() plugin.
repeated: true
required: true
- name: include_env
type: bool
description: Include process environment variables.
metadata:
permissions: MACHINE_STATE
platforms:
- linux_amd64_cgo
- name: watch_etw
description: Watch for events from an ETW provider.
type: Plugin
Expand Down Expand Up @@ -10807,4 +10835,3 @@
platforms:
- linux_amd64_cgo
- windows_amd64_cgo

Loading
Loading