Using BPF to Transform SSH Sessions into Structured Events
gravitational.com
gravitational.com
From "BPF Performance Tools" by Brendan Gregg:
"Extended BPF is often abbreviated as eBPF, but the official abbreviation is still BPF, without the "e," so throughout this book I use BPF to refer to extended BPF. The kernel contains only one execution engine, BPF (extended BPF), which runs both extended BPF and "classic" BPF programs."
So far we have gotten positive feedback. While this feature does not protect against root doing something malicious, it does allow admins to capture what root was doing up until they did something malicious and link that information to an identity (if using SSO).
Along with this feature we rolled out a Workflow API [1] that can be used to request role elevation. Once you add in session termination (which we are aiming for in the next release), you will have a powerful set of features that will allow you to start users out with limited access to your cluster with the ability to request more privileges and potentially automatically termination your session (and user) if you're found to be doing some malicious.
That means we don't just provide information about what's executing, but also what files are being opened and TCP connections being established. Other avenues of expansion you may see this feature venture into: how were files changed, support for other protocols, support for other events (bind, listen, accept).
However we are not claiming this approach is not subvertable, but we do want to raise the bar for attackers and make it easier for cluster administrators to understand what is happening within their system.
execv("/path/to/binary", (char *[]){"binary", NULL});
And here's a way to do that without exec: (((int (*)(int, char **))dlsym(dlopen("/path/to/binary", RTLD_LAZY), "main")))(1, (char *[]){"binary", NULL});
A bit uglier, but not all that much harder.Doesn't that just end up calling open() and mmap()? Might not have access to the args passed through at that point, but that's going to leave a trail and of course anything interesting the mapped program does will end up going through syscalls(opening other "files").
Without a syscall? Perhaps to open()..
Just a quick note that 19.04 Ubuntu reached EOL on Jan 23rd, 2020. Ubuntu has several releases that support 4.18+ kernels [0]. I recommend using 19.10, but you can also use a more recent HWE kernel for the 18.04 LTS [1].
Is writing valid BPF programs really that "hard"? E.g., does one often have to rewrite programs bc. the verifier wouldn't accept them? Do you see a need to extend BPF with more capabilities? (bounded loops have been added in Kernel 5.3, but maybe something else)
Thank you.
Very interesting post. Thanks for sharing.