30

Once a *nix system is properly configured and hardened, is it a conceivable strategy to remove all super user/root users? Are there benefits to removing root from a system altogether to prevent super-user privilege escalation exploits altogether?

Edit: More to the point: Can super user (root, uid=0 or otherwise) be replaced entirely with a capability based system?

Mike Ounsworth
  • 57,707
  • 21
  • 150
  • 207
Whome
  • 1,231
  • 11
  • 21
  • 17
    How would it boot? How would the kernel run? The root user needs to exist for a lot of the underlying operating system to function. – Mike Ounsworth Dec 11 '15 at 18:39
  • Much of a super user's abilities can be broken down into system capabilities, it's conceivable that there is no root and tasks that perform privileged operations have the specific capabilities granted to them. – Whome Dec 11 '15 at 18:50
  • 4
    Isn't this the basis of SElinux? "It has no concept of a "root" super-user" https://en.wikipedia.org/wiki/Security-Enhanced_Linux – KDEx Dec 11 '15 at 19:08
  • 1
    @Morgoroth absolutely, but there's a difference between designing a system to not have a root user, and removing the root user from a running system – schroeder Dec 11 '15 at 19:09
  • 3
    I would love to upvote an Answer to the effect of "SELinux already does this, here's how", if someone with the right knowledge would be kind enough to write one :) – Mike Ounsworth Dec 11 '15 at 19:30
  • @QueueNx am currently typing an answer that explains the different AC mechanisms of Linux and discusses which provide specific meanings for root and how those specificities can be countered. If you would like to discuss capabilities-based AC I would strongly recommend giving precise definitions, because disagreements on what capabilities mean and imply are common – Steve Dodier-Lazaro Dec 11 '15 at 19:31
  • 2
    @MikeOunsworth The bootloader and the kernel are not checking, if there is an user with uid 0 in /etc/passwd. – ott-- Dec 11 '15 at 22:12
  • See http://security.stackexchange.com/q/105150/971, http://security.stackexchange.com/q/62750/971, http://security.stackexchange.com/q/7801/971 for relevant information. – D.W. Dec 11 '15 at 22:36
  • 6
    The Romans lacked a [number 0](https://en.wikipedia.org/wiki/0_%28number%29), therefore, they had no root. – gerrit Dec 12 '15 at 10:53
  • similar question on U&L : http://unix.stackexchange.com/questions/238673/which-access-rights-cant-the-superuser-violate/238682#238682 – Archemar Dec 12 '15 at 14:15
  • 2
    @MikeOunsworth: how would the kernel run? Same as always, started by the bootloader. IDK why you think that's an issue. `/sbin/init` would be run as UID=0 by the kernel, but it could drop root privileges at some point, leaving no UID=0 processes running. (So yes, the question of "how would it boot" after starting init is an interesting question, but not obviously un-solvable). And now I just read your answer. Great point that uid=0 still has special meaning, and kernel bugs can create uid=0 processes even when there weren't any before. – Peter Cordes Dec 13 '15 at 01:55
  • @PeterCordes Yeah, in researching my answer bellow, I realized that that comment didn't make a lot of sense, but since it was already upvoted, I decided to leave it. – Mike Ounsworth Dec 13 '15 at 01:57
  • 1
    @Mike: I hate that when I wish I could correct something in a comment, other than by deleting / re-posting. >.< Too easy to turn a discussion into nonsense, though, if not used with care. – Peter Cordes Dec 13 '15 at 02:30
  • @Morgoroth that's not really the most accurate explanation. SELinux systems still have a root user, it's just that not every process running with an effective user ID of root is automatically accorded all privileges. root still has, in general, quite a bit of power over other user accounts and general system administration. – hobbs Dec 14 '15 at 04:04

4 Answers4

57

Even if you wanted to, I don't think you can remove the root user. From Wikipedia:

On Unix-like systems, for example, the user with a user identifier (UID) of zero is the superuser, regardless of the name of that account.

and a lot of the kernel code that vulnerabilities exploit does stuff like

// become root
uid = 0;
...
if (uid == 0)
    // do some protected thing

So the superuser isn't really a "user account", it's literally the number 0. If you can find an exploit to set uid = 0 then bam! your process has sudo, regardless of whether or not there's a user account named "root".

EDIT ADDRESSING COMMENTS: several flavours of linux prepend a "!" to the root's password in the /etc/shadow password file (a character that can not be generated with the password hashing function) which makes it impossible to actually log in as root. That stops some types of root-priviledge escalation attacks based on cracking the root password, but the more dangerous kind of privilege-escalations are based on buffer-overflow attacks that over-write a process' uid variable to be uid=0, at which point that process is root.

Mike Ounsworth
  • 57,707
  • 21
  • 150
  • 207
  • And what if the root line in passwd was removed? Will the kernel be aware of a UID=0 or does that user simply cease to exist (along with it's super powers?) – Whome Dec 11 '15 at 18:52
  • 9
    A line of code saying `if(uid==0)` is completely unaware of passwords or accounts, it's literally checking if an int variable is equal to 0, and letting you do stuff if it is. – Mike Ounsworth Dec 11 '15 at 18:54
  • 1
    If the root account was not present in passwd, are there ways from malicious users to assume that user id? – Whome Dec 11 '15 at 18:55
  • 7
    Yes, if you can figure out where in memory the `uid` variable is stored, you can manually set that block of memory to 0, and then your process is running as root (or any other user if you set it to non-zero). Buffer overflows are very good at overwriting memory. – Mike Ounsworth Dec 11 '15 at 18:57
  • 2
    @MikeOunsworth: You make it sound as though the main obstacle attackers face is finding where `uid` is stored in memory. – user541686 Dec 12 '15 at 08:40
  • 4
    @Mehrdad I guess another hard part is finding a buffer overflow to exploit low enough in the kernel code that it's _allowed_ to overwrite the `uid` variable, which will be in protected kernel memory. But yeah, buffer overflows don't usually give you read access, and if you start overwriting kernel memory blindly, you'll probably just crash the system. – Mike Ounsworth Dec 12 '15 at 13:25
  • 3
    @MikeOunsworth: Yeah, exactly. Even if the address of `uid` was already fixed to a known value it would barely change the story. The point is that it's in protected memory, not that it's in an unknown location. – user541686 Dec 12 '15 at 21:58
  • In my opinion, a hardened Linux could be reached if there wouldn't process existing in the system running with uid 0. Also no setuid binary should exist. All system users should have privileged access to only a small part of the system, all other privileged access should happen only by asking them as a "gateway". – peterh Mar 04 '17 at 23:48
  • @peterh That sounds good in theory, but isn't a `setuid` kernel call necessary, for example, if I ssh in as user `mike`, then want to `su` to `apache` to change a config? Also, doesn't most of the boot stuff and system-wide services like CPU scheduling need to happen with super-user privileges? Like, isn't root necessary? – Mike Ounsworth Mar 08 '17 at 16:06
  • @MikeOunsworth Right, but it can be still finetuned by securelinux. There is also a trick which was used already on the mainframes of the ancients: there was a different "root", who wasn't a "root" in our sense, it was an ordniary user with extended privileges. For example, it *wasn't allowed* to change privileges on the system. And there was another account, named "security manager" or similar. This security manager *could* change the access rights of the other user, *but* he alone couldn't do on the system anything. Until the *root* and the *security manager* were different persons, the – peterh Mar 08 '17 at 16:43
  • @MikeOunsworth system was resistant from a rogue root attack or from a misuse of the root privileges. I don't think only to this solution, I only think some similar separation of the different privileges generally bound to root should work. For example, in the case of the process doing *"su apache"*, a specific setting should somewhere exist which enables the su-ing to apache - *but only for this specific process, only to apache, and only once in his life*. The details, how could it be done, aren't well specified also in my mind. But in my opinion, it would be ideal (from security view). – peterh Mar 08 '17 at 16:46
  • @MikeOunsworth The main reason, why it isn't being done so, that the main wish of the bosses of the sysadms are around so: *"everything must be done _now_"*. Nobody bothers on security, only the knowledge that your system is "secure" doesn't worth the price of long sysadm work hours (weeks... months...). Thus, nobody will work with a super-secure distribution if it requires month of learning to use and you can do anything in 3x time with that. – peterh Mar 08 '17 at 16:48
  • @MikeOunsworth Now that containers and virtualization are more and more common, there is a new direction coming where "the server" will be actually a hird of containers and virtual machines, using eachothers as services, possibly with their different roots and separate security settings, it will be essentially the revival of that old mainframe conception. My pleasure :-) – peterh Mar 08 '17 at 16:51
  • @Mehrdad But it is at a fixed and known location. For 99% of systems running Linux out there, they are using a stock kernel, not one compiled by themselves. The location of any function can be trivially found, either by checking /proc/kallsyms, or by checking the kernel version and downloading its corresponding System.map file (which contains the locations of all the functions in that particular kernel). – anon Sep 11 '17 at 08:06
27

As argued by others, it makes no sense to "remove" the root UID (which is represented on UNIX as the UID 0). I would go even further and state that it makes no sense to freeze a system into not having any means to provide new privileges. Note that this answer is very opiniated and vague, because the topic to cover is enormous. Let's first go through what being root means on *NIX. I'm going to comment on Linux since it's the most popular *NIX and it comes with specific methods. Hopefully others can cover the BSD families. Let's distinguish what root means in the context of :

  • Discretionary Access Control
  • Linux Security Modules
  • UNIX capabilities
  • User namespaces

Note that in any case, it makes absolutely no sense to blindly apply privilege restrictions system-wide to all binaries that currently run as root. Often these privileges exist for a reason. So you should read the summary below as explaining how you can affect specific services that you run for your unprivileged users and that you want to protect from exploitation.

Discretionary Access Control

Most of permissions for accessing files on *NIX systems are mandated by the DAC model. Many kernel interfaces and IPC mechanisms are abstracted as files so this is a rather important consideration. This is the model with an owner id, a group id and read/write/execute permissions for the owner, group members and other identities. It also comes with the suid and sgid bits, but I'll keep these off for now.

By default, UID 0 always bypasses DAC checks. This is because UID 0 has the CAP_DAC_OVERRIDE UNIX capability (see below). Processes that self-remove this capability will have to obey DAC, though most system files on your distribution are owned and writable by root anyway. Removing this capability may protect user files to an extent but will not protect the system itself. It is also very likely that a root user without this capability (and without the direct means to obtain other capabilities) can modify logind, your kernel image or other key files in order to corrupt or take over your system.

Linux Security Modules

On top of DAC checks, all system calls on Linux go through a pluggable kernel module that implements the Linux Security Module interface. Those could be used to deny privileges to root.

For instance, SELinux uses the concept of roles to this end. On all distributions' default policies that I know of, your login daemon will open your root sessions with a limited role, and you'd need to explicitly switch to a role called sysadm_r before you can perform most traditional root operations. You do need to write policy to prevent root from being root-like with other roles. Still, since LSMs allow you to write a mandatory access control policy, you can effectively limit root privileges this way. The nice aspect however is that you can effectively trap user:role tuples into their roles, and you can provide roles selectively depending on how one logs in. This would allow limiting the scope of a specific root account system-wide.

UNIX capabilities

I don't want to paraphrase the man page on capabilities but essentially, capabilities allow user identities to interact with specific interfaces of the kernel. For instance, CAP_CHOWN allows you to modify the owner of a file. By default, root has most capabilities enabled (if I recall properly, CAP_MAC_ADMIN or CAP_MAC_OVERRIDE are not enabled by default) and other identities have none.

You can however remove some capabilities from your own set, so you can as a root process transform yourself into an unprivileged process, as long as you have the CAP_SET_FCAP and CAP_SET_PCAP capabilities. Note that it's been argued that many other capabilities can be used to re-gain full privileges. I cannot find the list of such capabilities right now but you should be aware that you need to seriously think about how a capability you leave to your root processes can be exploited for further compromise.

Whilst DAC controlled file accesses, capabilities, arguably, control system call access and behaviour (and the MAC LSM controls both). You must read the manuals of many calls in order to understand what each capability does.

There is criticism of the fitness of capabilities for Linux. Kerrisk has argued in "CAP_SYS_ADMIN: the new root" that some capabilities are so heavily relied upon that having them means having full powers. This suggests that you cannot just get rid of the concept of super-user alltogether. You will need to be extremely privileged at least to boot and set up your system, and to provide certain in-kernel services. In MAC systems that offer strong opportunities for confinement, you often run into the issue of needing to re-obtain a privilege (for instance, on SELinux, you might need to change role to sysadm_r to perform a maintenance operation). Likewise, if you got rid of those capabilities, would you be able to (re)start new privileged services? Would the ability to do that not be equivalent to being fully privileged?

Linux User Namespaces

Namespaces allow you, very vaguely, to provide a different view of your system to processes run inside them. You can use mount namespaces to change what files a process and its children can see and modify, or network namespaces to provide different network interfaces and system configurations. This is useful for people who provide PaaS services, for instance. User namespaces allow you to map all of the user identities inside a namespace to a single one on the outside. This means that you can have a sub-system with a root user that can do whatever it wants inside the namespace and that is mapped to an unprivileged user outside the namespace.

What's the point of that exactly? If someone had an exploit on your kernel that allows them to escalate to root, the benefits of user namespaces are moot. However, if the exploit targets a suid binary, then an unprivileged process that gains access to root privileges inside its namespace will still be unable to affect the host OS. Note that confinement solutions like namespaces merely shift your boundaries of defense. Instead of proving that all your privileged processes are flawless and cannot be exploited, you must prove that a fully privileged process inside the namespace cannot affect the host OS via the communication channels you leave open between the host OS and the namespace. Ultimately if you need a privileged service inside your namespace to have access to a resource, then compromising that service will grant access to that resource.

What now? Can we provide entirely confined UNIXes?

All these methods above allow you to confine services to specific privileges (and with specific caveats, either in combinations (DAC+caps) or alone (LSM, namespaces). You can also combine them to provide defense in depth. However, the question of whether confining everything is beneficial is very independent from how you mediate privileges and represent the concept of full privilege (CAP_SYS_ADMIN, UID 0, un-namespaced privileged user, specific concept of your LSM).

When you write an operating system and you want it to be adapatable to its users' needs, you need to provide means to update and reconfigure it, and to run new services. If system maintenance involves operations such as updating your security services, access control policies, kernel and hardware modules, and so on, then you must either provide a way for a human user to act as a fully privileged actor, or you must have a third-party system that can adapt your OS and deploy the adapted version on top of your user's data. There are high security contexts where the latter might be desirable (and very frankly this is, conceptually, as simple as running a VM). In the case of general-purpose computing by a population of users that self-maintain their systems, however, you cannot get rid of fully privileged identities.

Peter Cordes
  • 890
  • 9
  • 12
Steve Dodier-Lazaro
  • 6,798
  • 29
  • 45
  • An interesting idea for the booting problem is OpenBSD's [`securelevel`](https://man.openbsd.org/securelevel.7). Basically, it starts at 0, and everytime it is increased, some functionality is permanently locked down. It cannot be decreased, except by rebooting the system. That example is a bit crude, but could be expanded. – spectras Aug 17 '17 at 20:35
0

The init process has to run as root first. But fundamentally, the definition of root is not that it is a user with an id of 0, it is a process owner with the ability to access kernel routines. You could enforce a system where for AAA you run only commands related to the submitted jobs, but other than that there is no reason to remove the root user. The other thing is: it is not the root accounts that makes systems enticing, it is the fact that services running on the machines either have data or are able to transmit data that is the focus.

m2kin2
  • 89
  • 2
0

in fact all 'users' can be removed... kernels with just a static linked binary program in them performing one task work perfectly fine without any /etc/passwd file. ofcourse the concept of uids and euids still exists.

if your systems perform one specific task... just remove it all. file system, bootloader, libraries, the rest of the useless crap. and just run your task DIRECTLY in the kernel. (booting it from rom is a different story again ;) ofcourse if there are remote vulnerabilities in -your code- they can still gain access but there is no shell so they are limited to whatever code -they can insert- remotely.

-that being said- on -most normal systems- -most hacks- to uid0 take place not by bruteforcing passwords or by intercepting traffic... but by using all the crap built around it to -prevent that-. specifically sudo, traceroute, etc. most exploits from user 'www' to 'root' -require- a suid binary... and guess what su and sudo are.

once a system is finished... there actually is no appearant reason to keep all 'access' stuff around, after all, should there be a reason to fix things, one can update the entire image from development platform to deployment infra in flash or eeprom storage rather than 'access it' to run your editor/compiler locally or whatever.

  • the kernel doesn't know about 'user names' or 'passwords' or whatever other form of authentication you could possibly use. the kernel only knows uid numbers and gid numbers :P (the one thing that doesn't seem to work when linking directly into the kernel however, is the usual way of doing dns, as there seems to be no static version of libresolv ;) but who still needs dns anyway... servers definately don't need to know about hostnames and domains ;) – HRH Sven Olaf of CyberBunker Dec 12 '15 at 20:59
  • What do you mean by "statically linked binary **in the kernel**"? Are you talking about an embedded system where all the "work" it does is done by a kernel thread? e.g. you modify the kernel to not start anything in user-space at all? That seems worse from a security perspective. A security bug in a non-root static web server would let an attacker make TCP connections, but not raw sockets to run a packet sniffer or something. Or even to modify the server config files to affect things on the next boot. If they break into your kernel thread, then you're totally hosed. – Peter Cordes Dec 13 '15 at 02:04
  • 1
    @PeterCordes I think the point is now there's no such concept as "root", so technically you've prevented all means of privilege escalation to root? – user253751 Dec 13 '15 at 23:43