Sandboxing: Conclusion

In total I’ve written five methods for sandboxing code. These are certainly not the only methods but they’re mostly simple to use, and they’re what I’ve personally used.

A large part of this sandboxing was only possible because I built the code to work this way. I split everything into privileged and unprivileged groups, and I determined my attack surface. By moving the sandboxing after the privileged code and before the attack surface I minimized risk of exploitation. Considering security before you write any code will make a very big difference.

One caveat here is that SyslogParse can no longer write files. What if, after creating rules for iptables and apparmor, I want to write them to files? It seems like I have to undo all of my sandboxing. But I don’t – there is a simple way to do this. All I need is to have SyslogParse spawned by another privileged process, and have that process get the output from SyslogParse, validate it, and then write that to a file.

One benefit of this “broker” process architecture is that you can actually move all of the privileged code out of SyslogParse. You can launch it in another user, in a chroot environment, and pass it a file descriptor or buffer from the privileged parent.

The downside is that the parent must remain root the entire time, and flaws in the parent could lead to it being exploited – attacks like this should be difficult as the broker could would be very small.

Hopefully others can read these articles and apply it to their own programs. If you build a program with what I’ve written in mind it’s very easy to write sandboxed software, especially with a broker architecture. You’ll make an attacker miserable if you can make use of all of this – their only real course of action is to attack the kernel, and thanks to seccomp you’ve made that a pain too.

Before you write your next project, think about how you can lock it down before you start writing code.

If you have anything to add to what I’ve written – suggestions, corrections, random thoughts – I’d be happy to read comments about it and update the articles.

Here’s a link to all of the articles:

Seccomp Filters: http://www.insanitybit.com/2014/09/08/3719/

Linux Capabilities: http://www.insanitybit.com/2014/09/08/sandboxing-linux-capabilities/

Chroot Sandbox: http://www.insanitybit.com/2014/09/08/sandboxing-chroot-sandbox/

Apparmor: http://www.insanitybit.com/2014/09/08/sandboxing-apparmor/

And here’s a link to the GitHub for SyslogParse:

https://github.com/insanitybit/SyslogParser

Sandboxing: Chroot Sandbox

Sandboxing: Limited Users

This is the fourth installment on a series of various sandboxing techniques that I’ve used in my own code to restrict an applications capabilities. You can find a shorter overview of these techniques here. This article will be discussing sandboxing a program using Limited Users.

Users and Groups:

Linux Discretionary Access Control works by separating and grouping applications into ‘users’ and ‘groups’. A process in user A is, in terms of DAC, isolated from a process in user B.

There’s also user 0, the root user, which is a privileged user account.

Only a program with root, or with CAP_SETUID / CAP_SETGID can manipulate its own UID/GID. In the case of SyslogParse, we have root, and we definitely want to lose it when we can.

So, after getting the file handles we need, here’s the code for dropping to a limited user account (if you’ve read the previous articles this happens right after the chroot).


if (setgid(65534) != 0)
err(0, "setgid failed.");
if (setuid(65534) != 0)
err(0, "setuid failed.");

Very simple. So here’s a simple explanation.


if (setgid(65534) != 0)
err(0, "setuid failed.");

setgid(65534) sets the GID to 65534. This is the “nobody” group on my system. Nobody is an unprivileged user often used by programs wanting to drop privileges. If 65534 doesn’t exist, all the better – dropping to a GID that doesn’t exist is great.


if (setuid(65534) != 0)
err(0, "setgid failed.");

setuid(65534) is changing the user to 65534, which, as above, is the nobody user. Same as before, if the user doesn’t exist, that’s dandy.

Conclusion:

Dropping privileges is a hugely beneficial thing to do. By separating the code into a “privileged stuff done all at once, then never again” you can drop privileges before doing anything dangerous, and there goes an attackers ability to escalate.

Dropping root privileges is incredibly important. The attack surface and amount of post-exploitation work an attacker can do shrinks drastically.

In the case of SyslogParse, as any attacks would be for local escalation (it does no networking), an attacker would probably lose privileges by exploiting it if going from any normal compromised process. At this stage they are in a chroot with no read or write access, running in an unprivileged user/ group with no capabilities, they have access to 22 system calls and some very nice to have calls, such as read() are denied, and their only chance for getting a few capabilities is by exploiting a few lines of code that involve opening a file.

I was going to have the next section be on rlimit, but it’s really not important and also not viable unless you’ve built the application from the bottom up to never write to a file, which will typically involve a broker’d architecture.

Next Up: Apparmor

Chroots For Security

A lot of people will tell you that Chroot is not designed for security and therefor can’t be used for security. They’ll mention how simple it is to bypass Chroots.

The thing about it is, there’s actually no way to bypass a Chroot without root (not consistently.)

There is actually nothing wrong at all with using a Chroot environment in order to secure an application. You reduce visible attack surface and isolate potentially exploitable programs. I’m not saying to rely on it but as a layer it can prove valuable.

So why the nay-sayers?

Well, for some reason people think that because Chroot can’t contain root it can’t contain anything. The simple fact is that you can combine Chroot with Apparmor to avoid all known bypasses of Chroot (you can restrict admin, chroot capability, all sorts of stuff that could be used.)

So I definitely recommend using Apparmor if you make use of Chroot… but even if you don’t Chroot is pretty great. Visible attack surface within Chroot is greatly reduced – an unrestricted user program within Chroot will give a hacker a harder time than an unrestricted user program outside of a Chroot. They do still need a privilege escalation if they want to break out, and it’s more difficult to get one of those escalation exploits when you’re limited to a Chroot that provides only what’s necessary for the program to run.

So I’m going to just come out and say that Chroots are totally fine for security if they’re used right. For restricting non-root services/ programs it’s definitely fine. If you happen to use Grsec patches to harden your Chroots you can even restrict root services/ programs and remove all known capabilities that lead to a bypass. View chroot as just another tool or layer, not a full solution.

My 2 cents on the matter.