 Welcome everyone to this talk. Welcome to everyone who is watching on the live stream or listening It's great to see you in this big hall Our next guest is fave a fave is a security consultant security consultant He's also the co-founder of the company code blau. It's a specializing in security concepts and Fever belongs to this CCC inventory kind of like the downtime of the wiki For those who are not from Germany FIFA has a little blog in Germany a Little and pretty really really tiny really tiny not many people read that or Can we change the subject please I? Do want to say though that this blog is the only website that comes up when you and you when you go into the Berlin up on in the metro. So this is the fastest loading time of all websites And fave I will talk today about programs that send box themselves and why that is a good idea So in this talk check your privileges how to drop more of your privileges to reduce attack surface Please help me welcome fave Good morning everyone. Thanks for showing up So this talk is about How you can write your own programs? So even if they are exploited because you have the bug in them the damage is still limited and The idea for this is pretty old. It's probably older than then when I blogged it in 2007, but this is the first mention of it. I found in my own blog So I've been I've been working on this for a while or at least thinking about it And now the the building blocks have come into place so I can show you how to do this now But before we start let me make one thing clear This is not something you do instead of making your code good in the first place This is something you do after you make sure the code is good. It's It's like an insurance. It can save your ass But if you're not negligent, then they won't pay all right, so Basically, I'm trying to to show The the problem I'm trying to solve first so basically when you plan software you think of it like this and When it's written, it's more like this Basically we depend on lots of code with bugs in our daily lives and many of those bugs are security bugs and If and if someone tries to attack something, it's usually something that has more access rights than the attacker in the first place and When the attack succeeds the attacker has gained some privileges in the system So how how can we solve this problem and the the obvious idea is that well make sure there are no bugs in the code It's not that simple. It turns out The second obvious idea is to reduce exposure of your code Make sure it's only in the intranet as a typical thing people used to say for a while Make sure it's only reachable via HTTPS after authentication. So, you know only people with accounts can attack you which may not Lesson the burden a lot if you're saying email provider because you know everyone can have an account or Maybe it's an internal microservice and it's not visible from the internet Or you know, it's behind seven proxies Or you know people can come up with pretty wild scenarios But no matter what you do, you all can do is reduce probability of a hack You don't rule it out entirely. So even if you do all this You can still get exploited So what can we do to make exploitation harder? This is where most of the research right now is focused You can have non executable stack, which is pretty standard these days You can have cookies on the stack. You can have a hardened heap. All those are standard too SLR and position dependent executables Rob protection is kind of the new thing that people are trying to Make a standard You can ban dangerous API. So just a good idea. You can train developers Can have a bug bounty that is a good idea too if you have them cash lying around You can run the code on some architecture that you hope nobody knows how to exploit But in the end of the day, it's just the reduction of the risk. It's not actually you can't really sleep sound and The idea I'm going to talk about today is that maybe you can put your code in in a straight jacket and drop privileges So much that even if someone can find the bug and exploit it the access they gain is minimal or nonexistent Basically the less the code can do the less the attacker can gain by attacking it However, there's a massive difference between what the code can do and what the code actually does So I'm talking about what the code can do This is not about well, I'm not I'm not writing files anywhere. So I should be safe No, if someone gets code execution in your process and that process can write somewhere then that's a problem So this is not about what your code actually tries to do But what it could do with the privilege level it's running as in the operating system The post-exploitation attacker is not limited by what your code was trying to do. This is very important to understand Basically if you run something like say ping it's a set you add your roots program on your next Then the service or like an HTTP demon or any any system service basically it's usually running as super user traditionally and The super user has all the access in the system. So this is really bad The obvious first step is to reduce this a bit. So this is what the super user can do The next step is you drop privileges. So you run as a normal user in the system and you still have a lot of privileges But it's better and this talk is about maybe we can drop privileges some more and The service can only really do very tiny things in the system. That's the idea common patterns for achieving this are The app drops privileges and then you do all the the really hard and dangerous stuff in the beginning Then you drop privileges and you hope that the bug that the attacker will find is in the code after you drop privileges And this may be a sound assumption, but it may not be so this is kind of risky But it's a common it's a common way to approach this The next way to approach this I'm going to talk about all of this in detail It's called privilege separation when you split up your process and you move the dangerous part in in a separate process and make sure that process can't really do anything and Another thing that's usually done is if you're really helpless because the you can't trust the app And it's really big you put it in a VM or maybe a container or a jail and you hope that these mechanisms will constrain the explosion of it But maybe the app can confine itself to and and this is an idea that's pretty new I think It's only been gaining traction in the last few years as far as I know Oh, and there's a broker service, which is a common common idiom You split up your your process and you make sure for example the left half of the process Can't open files But it can talk to the right half and the right half can open files And if the left half wants to open and file it asks the right half and this is very small piece of code So it can we can be more sure that it's safe Dropping privileges is generally understood as dropping them for good So the idea is you can only go down in privileges. You cannot go up again in practice. That's not as easy as you would think so Traditionally what we did is we only look at dropping privileges for privilege processes We say well if it's running as some user ID, we don't care. That's already pretty safe So this is where traditionally the idea of dropping privileges comes from that you ID programs or programs starting as root and Common examples of this are ping because it needs raw socket access and that's restricted to the super user and The X server used to be running set you a D route nowadays There's other ways to do this because it needs access to the raw graphics hardware and the third is X term Which used to be set your ID route because it needs to create a TTY and not only the super user should be allowed to do this Basically the idea again is to do the privilege stuff first and then drop privileges and hope that all the attacker can do is Attack you after that Privilege separation. I think the term comes from the open SSH people or basically the open BSD Community has has Imprinted this term They invented the concept of as far as I know The idea is to split up your process So let's say you have this hugely complex crypto and parsing code that does the SSH low-level protocol parsing And you don't you think it's safe, but you're not really sure so you put this in a separate process and that process is confined to a small empty part in the file system and You you make sure it can't do anything except parsing the protocol and then if anything blows up It's only that part that blows up and not the whole thing the whole thing can do diagnostics and say oh someone tried to hack me The the other idea was the the admin confining in app in in a jail container or VM And basically this works on a on a whole system level It can be more granularity But usually what you do is you take the whole thing and put it in some kind of Environment restricted environment and this is done by the admin not by the app itself The problem is if you have some kind of rule set there's several implementations for this that I'm going to show if you have a rule set This program can do this and this and this but nothing else. How do you get that rule set? this is surprisingly difficult if it's not a trivial program and For easy for simple processes that can be done and it's it's reasonably easy But that's not the ones we're worried about right so we think about stuff like Firefox also In my opinion you can't expect the admin to come up with a set of rules to confine a program It's not the admins job to understand what every eventuality Every error code path in this app does you don't even know if you used all the regular functionality in the program usually Are you sure you clicked on every button in Firefox in your lifetime? And you would have to do that to make sure that your profile is complete So usually what happens in this kind of scenario is that there's some obscure error path You haven't seen yet that the program would have been able to handle gracefully for example disc full or memory allocation fails and then suddenly the program behaves differently And that's a violation of your profile and the whole thing blows up. So this is it's very hard to come up with this profile That's why I think it's a it's a misguided idea to do this. You can still do this on top of Actually having the program sandbox itself. It's a it's an orthogonal idea But I don't think this should be the only thing we do to constrain applications The the other idea is that well, maybe not the admin is doing this but the distro guy You know the Debian package maintainer does this and and I don't think that's a good idea, too You can't really expect them to do this. They're basically, you know students doing this in their spare time How would they have a year to study Firefox and come up with a profile? So the the the central idea of my talk is the the app confining itself Basically think it's a werewolf chaining itself to the wall before full moon to make sure that even if something happens You know, I'm still confined here and don't do damage So basically what you do is you make sure there's a little part in the file system only the stuff You really need and you can only access that part. There's several ways to do this. I'm going to talk about them You cannot open files outside this part of the file system Or maybe you can't open any files at all if you don't need to ping doesn't need to open files You would think but it turns out it does for DNS lookup So it's all the devil's in the details here. It's not it's easier to talk about it than to actually do it Another thing that's usually overlooked is that even if you can't access the file system There's still lots of stuff you can do system 5 IPC. It's its own namespace for example Which means you could access shared memory from other processes if they use system 5 IPC or you can send signals just killed processes or You could use ptrace which is the Unix debug API to attach yourself as a debugger to some process outside of your environment So it's it's not just it's not enough to limit the file system access. There's more stuff you can do so the the main Thing you should take away from this is that you probably have to restructure your application the way it works You limit what the main application can do to reduce the part You really have to be sure about to the broker service and the broker service gets messages from the main program Stuff like I want to open this file For reading or I want to open that file for writing and the broker service can do additional checking Aside from what the operating system is doing anyway And to make this worthwhile You have to make sure that the main process does not have any way to actually or any any access rights to access The file system itself and there are several ways to do this. I'm going to talk about the problem is that sometimes there's ways for The the main program to trick the broker So if you do if you just do a separate process and it's running under the same user ID For example, then you could attach a debugger to it one the main program if it's being hacked could just use ptrace to Overwrite the code of it code execution flow in the broker and just make it do anything at once So it's this is more tricky than I'm letting on here So let's get to the dirty details First the old-school way. This is what ping is supposed to do or like in let's let's say in the 90s This is what we used to do in the 90s. Basically what you have is you have two UIDs in the process Data structure in the operating system. It's like some struct somewhere in the kernel and it says well you have the the real UID and we have the effective UID and If the the program is run is set UID then the effective user ID is The one that the binary is set UID to so that means if the program does anything the kernel doesn't actually look at the real UID it looks at the effective UID So let's say you understand this and you want to drop your privileges then you could just say set effective UID to get UID to drop back to The the actual the real user ID and you would think that's enough, right? And it turns out no, it's not enough because at some point there's a third UID that allows you to go back even after someone tried to drop privileges and This is at some point the the various versions of Unix and BSD Diverged on this point. So it was for a time. It was pretty hard to write code that does it right At some point a new API was invented. It's called set res UID You can set all three user IDs with this and that's actually okay. That's a good way to draw privileges however, it's not enough to do this you need to check the return value and If you don't things can go badly also, it may not be enough to to Reset the user ID. There may be group IDs that are privileged to So you know the devil is all in the details here So what can happen if I'm the super user and I want to set res UID to some user ID? How can this ever fail? There is system-wide limits resource limits for UID So there could be a limit that there can only be 10 processes for a given UID and If that UID already has 10 processes running and root is trying to drop privileges to that UID then that will fail And if you don't check the return value at that point, you might as well not have drug privileges in the first place So if you do any of this be very careful to Understand all side effects and things you have to watch out for It actually used to be even worse than that because there was a different call set Re UID that looked like it does the right thing, but it doesn't and in many programs today you find Backwards compatibility code if said res UID is not found by configure and in many cases that code path is pretty bad So my advice is if you if someone tries to build your program on a system that doesn't have said res UID then just fail the build We need to get this everywhere. There's no way even so well. Let me give you an example This is an from an Apple security advisory a while ago It says basically the issue was that the the set read GID system called fail to drop privileges Well, that's that's what it's there for right so very careful with this actually test that works and Make sure you check all the return values So but have we actually dropped privileges let's say we are ping and We get a raw socket in the beginning and then we drop privileges and then someone attacks us successfully then maybe we're not running as rude anymore, but What is what happens if all the attack I wanted was the raw socket we still have that so dropping privileges more than then going back to a UID also The concept of well we do the dangerous stuff first may be more difficult than it looks like So for example, what about parsing command line arguments? You can have bugs there actually the extra where you serve a bug there and they said well We have to do that first and then we do the hardware stuff and then we drop privileges So this this is dangerous to parsing command line arguments and what if if the attacker is using environment variables What if the bug is in the dynamic linker there were examples of this too So that's before even your main is running. So dropping privileges is It's a harder concept than it looks like and if all the attack I wanted as I said is the raw socket Then there's not much you can do the code still has to be good So let's talk about privilege separation Let's say you have web servers and it wants to convert uploaded images to let's say create thumbnails or Make sure it's all a jpeg without metadata or whatever want to remove xif something like that But the way to do that would be to support all these image formats and nobody wants to write that code So what people do is download libraries to do that and those are big pieces of code Many of them have had security problems in the past. There's basically not many reasons to trust them now So that might be a good idea For privilege separation you move that in a separate process and that process has no privileges And it doesn't have to access the file system in any way Because it gets the image over some socket or pipe or whatever and it gives you the result back of another socket So this could be locked down There's a difference between using all the libraries directly and using some kind of wrapper around them Which is even more popular at something like image magic In any case no matter how you do it. It's a huge code base that shouldn't really be trusted So if if you do this at some point that might be a good idea to think about privilege separation So the idea is to move all that image manipulation stuff in a separate process and lock that process down so by locking down what do we mean by that and So the obvious things are the file system access obviously your system 5 IPC other processes Interprocess communications make sure No new channels of IPC can be opened only the ones you gave the process when you created it can still be used You want to limit network access because if the attacker can't get a shell Then maybe it wants to create a little shell on a network socket Even if it doesn't have access to bin shell then that might still be bad that you need that needs to go away Maybe there's a routing problem So the service is only supposed to be a microservice that's visible from your one host in the DMZ But it has a default route somewhere that doesn't need to be there. So maybe that that could be locked down, too Except many ideas what you could try to lock down common approaches for this is either namespaces or a prison in a guard so the namespace ideas that you put together some kind of fake file system that Looks like a real file system, but only has the parts in it that the process really needs and That fake file system then becomes the actual file system that that process sees this is one of the ways you can do this and usually stuff like ETC hosts or ETC resolve comm stuff like that could be used if you're the process you're trying to lock down uses DNS Lookups for example, so these kind of files you would need in your fake file system, too, and If your fake file system is on a var jail one you would have a file like var jail one ETC hosts The namespace concept can also be used for UIDs and PIDs so the the difference here would be if you have something like a container and in that container there's an init running would that in it have the PID one or not if you have more than one jail, can you have more than one PID one? So this is a detailed question that may not matter Maybe you don't even need an init in your in your jail but if you have a namespace and every every container has its own PID namespace then there is no risk that any interaction like kill or any signals any Petrace anything that takes a PID could ever affect anything outside that jail The other approach is to have some kind of prison The the BST free BST came up with the name jail for this You have some kind of UNIX permission checks during open. This is done on windows the same way This is an old concept if you can do open you get a file descriptor back And when you do read and write on that file descriptor even if you at that point You couldn't do the open again Because your drop privileges if you have file descriptor you can still do what you were allowed to do at the time Of the open so all the access checks are actually done at open and not at read or write all Read or write checks is if the open asked for read or write permission So the idea would be that you disallow the open in the first place In the part you want to restrict and then you have some kind of guard And if the code that you want to restrict needs an open it can talk to the guard and the guard or the broker service Says well this open Yeah, okay ETC hosts for reading. That's okay, but ETC hosts for writing. That's not okay So this is the other way to do this you can do pretty much the same thing for for sockets and As long as the end results is a file descriptor it can be passed between processes using UNIX domain sockets So the script are passing The concept is easy, but how to do it is actually pretty crafty And I would have advised against trying to do this yourself Go find some code that doesn't for example, you can use mine It's it's available in this library. This is pretty hairy. You can look at it It's like an if death desert. It's really horrible I mean you can try but you probably won't run on some kind of operating system You never heard of and it's bad. So this these it's it's just three lines of code basically But it's different three lines of codes for almost every flavor of UNIX out there. So it's a pretty hairy But if we abstract that away then it should be okay So how do we restrict file system access? The old solution is called change route What you do is you create an empty route on read only directory var jail or var empty or whatever you want to call it and Then in the service you say change dear to that route that empty directory then you close all the open files You say change routes to the same directory and then you drop privileges because if you drop privileges first change route cannot be done Change would needs super user privileges So this is part of the stuff that needs to be done before Dropping privileges. So let's say you do this and then the process tries to open foo Then this foo will be relative to the current path That's is obvious. But if you try to open dot dot slash foo The dot dot slash doesn't work because that's the one thing change route make sure it doesn't work Or if it's a symbolic link that contains dot dot slash that also doesn't work So that you can't escape from this part of the file system unless you have an open descriptor that already points outside the file system So that sounds pretty peachy. It's all rainbows and unicorns But no, it's not you can escape a change route jail if you are route yourself Because then change route doesn't does not nest on unix So if you do a different change route while holding a file descriptor to your change route You're out This is the code that doesn't just so you have seen it once So if your process inside the change route environment can or can obtain It has or can obtain a handle or descriptor to a directory outside the jail. It can escape the change routes Either with change here or f change there in this case. So that's the second f change there is the second way Change route itself does not change there you have to do both If you don't do both then it's ineffective and You need to check the return values again Even if you are confined to a change route jail all that does is limit file system access sockets and and Signals and stuff still works. So it's not a good solution. It only is for file system. It's not comprehensive You need to do more more trouble with change route is that Library functions might access their files without telling you first the most notorious is the DNS API's get host by name Depending on the operating system. They may try to open a ton of files like Resolve.com resolve conf.conf NS dot whatever So you have to look at what the the libc you're using actually tries to open here to and make sure those files are in the change route jail to Particularly troublesome for this is if the the program you're trying to jail isn't written in in a compiled language But say Pearl and Pearl may try to open some other like modules If the program starts with use something something some kind of per module Then Pearl will try to load that or Python is the same thing. So scripting languages are pretty tricky You would have to have all this pearl code in the jail in the change route environment, too So Pearl can load it and at that point you risk that someone in the jail could modify those files right, so the file permissions have to be carefully watched and Even worse usually the way to put the files in the jail is to heart link them So if you do a heart link and someone modifies the the file in the change route jail that also modifies the file outside the jail So even if they don't manage to leave the jail They might still compromise your system. So you have to be very careful about this So let's get to the the solutions different operating systems have for this One of the first ideas and I think it's a pretty good idea is the BSD secure level so it basically the same same idea as I Talked about inside a process you do the dangerous stuff first like mounting file systems and doing a file system check Those need to be able to access a raw disk device a block device But after you you do file system check, maybe you don't need it anymore It's a production server So you might as well turn off the the capability in the whole system to open raw block devices And this secure level can do this basically you can only increase it only root can increase it and nobody can decrease it Without rebooting. That's the idea. That also means you have to just allow access to def k-mem and stuff like that And secure level does that too Then I talked about change route jail is something like change route on steroids A jail has their own file system route and additionally can set IP addresses for different jails So in the end you can have a root user in the jail But without the problems that a root user in a change route environment has So the route in the jail isn't actually considered route in the whole system It's like a middle thing and there is some kind of namespace stuff. This is still in in progress jails are being extended In right now basically, so keep keep a watch on the the capabilities of jails. They're still being worked on The admin that sets up those jails can specify for example if system 5 IPC access is allowed or raw sockets are allowed and Things like that. So this is a pretty good thing and it has been used for building a container style hosting on on free BST for a while now The one of the problems with jails. Well, maybe it's not a problem But it's it's it makes me feel a bit uneasy is that there's no actual namespaces. It's it's like a flag on the process They extended the the struct in kernel for a process to say this is relative to jail 5 so Theoretically you could still say kill PID 5 and PID 5 is outside your jail But there is a check for that But it still means there has to be a check at every place Where you do something with PIDs in the kernel. So that's I think it's a bit risky But apparently it's pretty stable and I'm not aware of any issues they had there PID 1 is always in it in the the host not in any of the jails if you try to kill PID 1 inside a jail it fails because PID 1 does not belong to that jail. That's how it works. So it's it's like a namespace light. You could say maybe but it means if if There is two processes in different jails. They can't have the same PID That's like a slight infolique. No, it's not clear how much of a problem that is but you know just to understand how that works So let's get to the API's to restrict what a process can do Capsicum is the free BSD way for this and this is actually a pretty neat API the whole idea is that you split off a Broker service and you use Capsicum to make sure that all global namespace accesses like Open file or or create socket fail and the only way to do get descriptors to files. You want to open is by going through the broker To make sure that the there's some more restrictions actually in Capsicum. So for example, you can say P trace it's not allowed or You can say socket operations Are only the only these socket operations are allowed so you can have some more Fine-grained control, but it's not completely fine grained You can't say for example MF is does it out if you wanted to Open BSD came up with an API. I called tame The idea is similar to To Capsicum, but it restricts some some more My problem with this API is that they have these flags that they need it And if you need some other way to restrict the process, you can't the all you have is the the flags that they Provide for you. So it's not it's not programmable. You could say it's not as flexible as Linux But if all you need is those flags and for most people it should be enough then it's actually not that bad The problem is that these are defines So if you want to support different versions of open BSD, then you have an FDF hell If if this flag is available then use it otherwise not so it's Portability is a bit bad. It feels a bit like a clutch to me and The open BSD people agreed so they have a new API now. It's called pledge and What you do with pledges you basically the same as the flags, but you put it in a string and That string is then passed by the kernel and if you try to Pledge something that the kernel doesn't understand then there is no if death hell. However, the kernel needs to parse strings now Which is also dangerous so I'm not sure if this is actually an advancement over Tame, but you know and it's there. There is one pretty good idea in pledge That is in no other system. You can also give a list of paths and file system accesses will only Succeed if the file name you're trying to open is in one of those paths So you don't need to set up a jail or a change route environment. You can say, you know ETC hosts is okay Otherwise, you know my home directory is okay But all others TMP is okay. I give that kind of list But my program never needs to look into you know user bin For example, you could say that in pledge. That's a pretty neat thing. I would like to see in the other APIs too So let's come to Linux Linux as a pretty early concept of capabilities that was from the time when we didn't think about restricting more than Dropping privileges so the idea with capabilities is instead of dropping privileges. We make sure we don't give you privilege You don't need in the first place. It never really took off So the idea was you could have a ping that doesn't really have super user privileges It just has the part it needs to create raw sockets. It couldn't for example access The disk device or something Never really got anywhere as far as I know There's a combined thing that's available in open BST and Linux is called sys trace. It's also pretty old The ideas that you have a system-wide profile that says for example LS can do open dear read your read link These are system calls and right Because it needs to write the output to standard out But if it tries to do anything aside from that an alarm is raised That's the idea with sys trace However, the profile does not come with a program and the program cannot set its own profile This is something the admin provides or that's provided at installation time. This is what a profile looks like in practice You don't need to read the fine print just to show you basically What kind of what to expect it's it's it's a text file So sys trace the problem is where does the profile come from? So in the answer as well the admin has some kind of training training mode and I talked about the problems with that earlier I I don't think that's a good solution because you don't Getting coverage from a probe program your road yourself is already hard and most people can never get full coverage with their unit tests How do you expect the admin that doesn't know the code to do it? So I think it's a it's a bad idea then there is a Colonel patch series called gr security that offers features That are conceptually similar to sys trace. It's not part of the stock colonel. So I'm not advocating it here I think if you want to have this kind of of thing it should be in the stock system and Not need any external stuff and it cannot be used to self sandbox Then there's se linux. That's also pretty well known. It's conceptually the same as this trace a little more powerful But again can't be used to sandbox yourself App armor is a little it's another not invented here type of thing does a similar thing also not used for self sandboxing and The actual API for linux you would use to sandbox yourself is called seccom filter It's based on seccom and this is a startup business model from 2005 where someone said well you could sell your spare CPU cycles for say scientific computing and Cloud computing or something, but since you can't trust foreign code will make sure that the foreign code can't do anything and I didn't catch on but on this basis They invented mode to or second filter and it uses Berkeley packet filters with who here knows what a Berkeley packet filter is Okay, pretty much for more than I expected It's a bytecode VM. Basically. It's really horrible It's a stack machine very limited instruction set there is tooling, but you have to look for it and it's still pretty horrible But the linux kind of recently got a jit for it. So they figured it's fast. We should use it more this is what a program looks like in in TCP dump, which is what it was actually intended for if you say port 22 Then there's a little bytecode compiled that looks at a packet and says okay. This is IP This is TCP or UDP and there is a port 22 So it's pretty gross and The idea with second filter Second mode to a second filter is that instead of a packet you give a memory buffer that contains the the syscall number and All the arguments to the syscall and then you can write a little program or bytecode that looks at these arguments and says No, this is called number is not allowed There's some more details going on But if it boils down to this you have some it's macro hell and it's really horrible But I thought you should see it at least once You would do something like a louse is called open allows is called exit and that's it This is the easy mode when you don't look at the arguments there's some trickery that Was a security problem in second filter initially where you would have a platform that allows different kinds of binaries 32 bit and 64 bit so you have to do an additional check, but never mind that here and Then you construct a program like this You have all these BPF jump is or BPF a statement You see BPF LD for example is a load and BPF jump is a conditional jump BPF red says okay program is finished here and you set it up with PR control Which is a as far as I know a linux specifics is gone The plus side is that it works and if you abstract it away. It doesn't even smell that bad It's actually quite efficient because of the jits and it's reasonably powerful on On the contra side What the hell were they thinking I? Mean if you expect people to write code like this then the complexity of the checking code Shouldn't approach the complexity of the code. You're trying to lock down. Otherwise, you know, there will be bugs in there There's all kinds of warts if you try to use it because for historic reasons There's different ways to do many things for example exit versus exit group or MEP on MEP to All kinds of stuff and in the end what you usually do is you allow both even if only one of them is called because they They do the same thing, but it's all the stuff. You need to know to use second filter And for MEP there's an actual there's the worst problem because MEP has more arguments than there were free registers on 386 So the first MEP version of this first version of the MEP sis call didn't actually use the the registers But it used a pointer to a buffer and you can't inspect that buffer from second filter So if someone uses the old MEP there's no way to To use second filter to restrict that look at the argument. So this is bad. Unfortunately, GDPC hasn't used this in a while So you should be okay If you want to inspect arguments, it looks like this So in this case we have open and we want to make sure only open for reading is allowed so I mean, it's pretty ugly you can see that but you can you can Attempt to abstract that away So let's say I want to allow open but only for ETC resolve comm which is a common thing you might want to do Can't be done with second filter because you can't inspect memory and You may be asking why why don't they allow that and even if it could be done would be still be insecure and you think of this scene if You do the check first and say okay This is ETC resolve comm and then you allow the open sis call to happen Then there's a time between your check and the open where another thread of the same process could change the buffer So even if they allowed this check this wouldn't work. So you can't inspect buffers With second filter and it's a good thing if you need to do that you need to do a broker service basically So you could there's some things you could attempt so for example, you could lock down a map and say It has to be a read only page for the argument or only this address is allowed And when I set up the second filter and then only that address is allowed as an argument But it gets really hairy and I wouldn't advise for it So if we think about this for example and protect would be so this is called to change a read only map to a read Right map so you would have to disallow that too But you would have to make sure that if someone calls an unmap on an overlapping area That doesn't work. So it gets really hairy really fast. So let's say don't do this. However Fortunately Linux is not Unix and doing this in the broker is comparatively easy Because you can just do an open in the broker and then look at the full path of the file via the proc file system So that that would be one way to do it basically or you knew his namespaces which is probably the better way So yeah, basically This is how you would do it with a broker You have to ask yourself the question. Have we really locked anything down if we do all this trouble because let's say in the end you have something like Firefox and There's a save as Function in Firefox and the idea of that is to allow writing anywhere in the file system. How do you lock that down? So even if you even if you put that on the broker service Someone who attacks Firefox could still Well, it couldn't write but it can ask the broker service for writing and since it's the idea to allow writing everywhere The broker service will allow it or let's say not save as but open local files You you are allowed to do to say open and give a file to Firefox So the broker would have to allow opening files and that means even files that may not be Suitable for Firefox like your SSH private key Firefox can open those right so even if you lock down Firefox and Firefox is just a Metaphor here for complex processes. Let's say my sequel is the same thing my sequel Should have permissions to open files because it's needed for some functionality you may be able to lock that away in special cases when you don't need it, but You can't just do that, you know for everyone. So It's a it's a problem that may you may be able to lock down more if you know more details about your application And that's one of my arguments because the admin usually doesn't the programmer does Then the big elephant in the room is kernel bugs We have a high-profile kernel bug around every six to twelve months and If we rely on some security mechanism like namespaces or a second filter The next vulnerability might be in there. It's complex code complex code has bugs, right? So the expectation is most unfound bugs are in obscure places So my example for this would be x25 socket handling because nobody uses that anymore There are probably still bugs in there because nobody cares if we lock that away We gain something so there is a value not just in restricting permissions, there's also value on top of that in restricting kernel APIs that are visible to the program and locking away APIs that might have a problem in the future that is also a win even if we don't Gain anything tangible now. It's insurance against the future So the first rule of second filter is block future calls to second filter So as an example, I tried to lock down my ping implementation to get a handle on all this Functionality and so the first thing you do is you get a raw socket and you drop privileges And after that you want down want to lock down what the attacker can do So before you do command line parsing, right? So you lock that down the documentation says if you apply two filters with second filter and then both are applied So I thought oh, that's good I can do several stages first stage drop stuff. I never need But file system access I can only block after I did the DNS look up and that I can only do after I pass the command line So I have more privilege than I really need during the time. I passed the command line So I did several calls to second filter and I found out that It didn't work as advertised. So this is a caveat That you should know I could install a filter that disallowed Further calls to second filter twice. So it obviously didn't get applied So check your have a unit test for your Lockdown mechanisms to on windows that theoretically you can do this But it's so hard That I would recommend against it if you are really dead set on trying to do this on windows Go read the chrome sandbox implementation. It's open source. It's really hairy and I wouldn't feel safe if I had any of that code to be honest in my project So if you if you can at all to avoid windows for that for this You might with the way to do this might be to use their app lock down Then it's not your fault if the lockdown isn't good But trying to do this yourself is it's not a good idea. I think So to sum it up I Think we're in a pretty good place from the functionality because we can do most of the stuff we we want to do On on linux 3bc and open bc at least Find grained lockdown is possible, but it's very hard in fidgety On the other hand if we write code that code is usually also hard in fidgety So I don't think that's much of an argument If you are a paranoid software paranoid software author You can sacrifice some performance to gain more security the trail blazer here is open SSH and Their sandbox source code is should be something you you study if you want to Find out how to do this Personally, I feel I can sleep well at night knowing that I locked down my code with this stuff and tested that the lockdown actually works Your mileage may vary Closing words Use this in your own code. I think this should be the shipping or deployment equivalent of having unit tests Everyone should have this if your process is too big to apply this reasonably then split it up We I think we shouldn't in we should strive for a future in 10 years or something where nobody ship software that hasn't Doesn't have some kind of lockdown mechanism like this If your code fails after updates because you locked down tightly and it needs more permissions now then you were doing it, right? Because that means your lockdown was very precise. That's how it should be So this is there's work involved. Don't get me wrong This is hard work and you need to be very concentrated and you need to check whether you actually Achieved what you wanted, but you can do it and I think you should do it Any questions I think we only have five minutes. So we have about eight minutes You can always send me an email or I would be available here in the in front. Let's start with an question from the internet Okay, the first question from the internet is if you see saw the talk on cloud a bi and what are your thoughts on this? On what I forgot the talk on cloud a bi Oh cloud API, I didn't actually see the talk. I'm sorry, but I will look the video I think they're basically using the same mechanisms. I still wouldn't trust the Announcement they make that you can run untrusted code if you lock it down I wouldn't go that far, but basically what they do is the same thing They use these mechanisms to lock down and that's the way you have to go if you do cloud computing micro-inspirator So what was your exact criticism of these second to? Is it the design of the virtual machine the instruction set or the fact that you have to use these macros to write your code? Well, actually it turns out you don't need to use the macros There's a library that abstracts it but since the whole reason to use this stuff is because you don't trust your libraries I didn't mention it. I think you shouldn't be using libraries so abstract as a way My criticism is that you need too too much context to use it So the open BST API is pretty good in this respect you have it's very easy to use and there's not much you can fuck up And I would I was hope I would hope that there's some way to do this more easily in Linux 2 Micro 2 what is your take on xcg app for application sandboxing? On which xcg app the one the Knoe project is doing for larger applications that normally don't run as route But as a normal user, I haven't actually looked at the details there. I don't know. Sorry, okay Microphone for please so my question is all these Privileged dropping happens at runtime. You have to code it into the binary yourself now. There are some Processes tools where you know that right from the beginning you don't need to certain kinds of accesses wouldn't it make sense to have Kind of like the sac comp binary code be in a special section in the ELF binary and have loaded by the kernel right from the beginning Yeah, that would be awesome, but we don't have the tooling yet. So if someone would hack that that would be nice Another question from the internet, please. Yes, the question is What do you think about running a target application in like hardened Docker with like LSM sac comp and C groups? Yeah, I mean that's it's a good idea. However How do you know that? I mean Docker doesn't really lock down everything. They use namespaces, which is good But if you have a kernel bug, there's more you can do To to avoid it. I mean not in all cases, but I don't feel as safe with Docker Then I would feel with Docker and an application that also does second filter to restrict itself more Microphone free Everything you explained looks like I need to call all these features from C Is there some way to call those restriction APIs from some high-level type safe memory safe languages? Probably however, you need insight in what the runtime of those languages does and that's a whole undercut kind of worms Usually from high-level more high-level languages, you can always call C code in some way or other. So it should be possible Microphone to please Yeah, my question kind of Relates to the previous one. So we have mentioned resolve conf being Red during names our name lookup so is there any attempts to kind of make this modular when you have a library and You at least need to document or specify in some way what? This and that call needs in terms of operating system services so you can't I'm not aware of any of those but Most operating systems document this in some way or other in their own documentation However, if you write software you usually want it to be more portable then, you know, it works with this version of lip see So there is a trade-off here to be more precise in your blocking or To be more portable and I think that's a bad thing to have it gives the wrong incentive And in question from the internet, please Yes, it's not really from the internet from one of the angels down here So I'm going to hand him the microphone Yeah So you mentioned that apartment Yeah, you mentioned using broker services to actually hand off opening files and how it doesn't help with Sorry with Processes that might need to open arbitrary files Something we are doing with apartment is we are working on using broker services where it's actually the broker service Which prompts a user for which file need to be open which avoids Having the service lie about needing to open the file When I say broker service I didn't mean it in a way that the operating system starts something But I meant it that the application forks in the beginning and then one of the Two processes is the broker for the other half So I don't mean it I think if you want the admin to install anything so your app is more secure You shouldn't rely on that because there will be mistakes made and you want your app to be secure in any event So you should do it yourself as the programmer Microphone 8, please Hey so Isn't it a problem that most of these privilege dropping mechanisms require you to have Super user privileges doesn't that create an additional time of vulnerability for a program that never Actually needs super user privileges, but would like to lock itself down I don't think most of the the API is to require super user So second filter doesn't I think tame and pledge don't I'm not sure about capsicum But I don't think it does change root as in jail does because those are meant for different things but if you write something like ping and And you have an exterior mechanism to get your raw socket and you don't need to run as route Then you can use most of these APIs Without being rude Thank you very much and fever. Thank you very much for this talk