7

First of all, let me mention that I’m assuming a configuration as set up by current Linux desktop distributions (e. g. Debian, Fedora). I’m sure that there are methods which, if implemented, would mitigate the issues described here. What I’m interested in is the security “out of the box”.

It seems to me that the fact that shells execute files like ~/.profile or ~/.bashrc, which allow complete manipulation of a user’s execution environment and are owned by the user, destroys any hope that a program like sudo can be run securely. The problem is that any malicious program running as the user can edit these files to, for example, modify the PATH environment variable to include a fake sudo executable, such as PATH="$HOME/.evil:$PATH", where the malicious program also created a file $HOME/.evil/sudo. Then, the next time the user types sudo in a shell, the fake sudo will be run instead and can record the typed password. Thus, the fake sudo can obtain root privileges even though the original malicious program only had user privileges.

In fact, the default .profile file created by my installation of Ubuntu includes the following lines:

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

so there is no need to even modify .profile – just create $HOME/bin/sudo and it’s already first on the PATH!

My point is not that it is already “too late” when arbitrary malicious code is run or that this attack could be noticed by the user (I suppose it is similar to a phising attack). I expect that a malicious program running as a user can do anything that the user could. What I would not expect is, however, that it can do more than that user (root privileges).

My question is, in essence:

  1. Is it true that the system sudo executable can be circumvented in this way?
  2. Why are desktop Linux systems, by default, set up in such an easily exploitable way? Shouldn’t the default way to invoke sudo make sure that it is, in fact, the executable provided by the system (nobody is going to type /usr/bin/sudo every time)? Since sudo performs system-critical security operations, the possibility to shadow its location using the PATH variable seems to bring a lot of risk with little benefit. In such an environment, it seems that using sudo is fundamentally insecure and one would be better off enabling login as root and logging in on a separate TTY.
Socob
  • 215
  • 1
  • 5
  • 1
    welcome to sec.se ... if you run non-trusted piece of code on your box, its not your box anymore. `~/.bashrc`, `~/.profile`, `~/bin` are not the problem and even if they didnt exist you would still have a problem that an arbitrary malicious piece of code could modify `$PATH` which is a concept that exists on Mac, Windows, and Linux. TLDR: dont run untrusted code on your box. – CaffeineAddiction Jun 11 '18 at 01:34
  • @CaffeineAddiction “if you run non-trusted piece of code on your box, its not your box anymore.” Yes, this is repeated often. However, you cannot verify all the code running on your machine. For example, every time you visit a webpage, untrusted JavaScript code is running in your browser. That shouldn’t mean that it is “not your box anymore”. This is the whole point of having different levels of privileges and isolating between them. My question is specifically about the problem that this isolation seems pointless when a user uses `sudo` to elevate to `root`. – Socob Jun 11 '18 at 11:53
  • `However, you cannot verify all the code running on your machine. For example, every time you visit a webpage, untrusted JavaScript code is running in your browser.` can and do ... I have a Chrome addon called ScriptSafe that blocks all Javascript till I enable it. And I only enable it if it is coming from a domain I trust. – CaffeineAddiction Jun 11 '18 at 12:20
  • @CaffeineAddiction Well, sure, but why do you trust ScriptSafe, or even Chrome for that matter, whose source code you cannot inspect? My point is, if it were feasible to only run code that is *really* trusted and isolation between different levels of privilege were ineffective, there would be no point in having different layers of security and one could just run everything as `root`. – Socob Jun 11 '18 at 13:01
  • Why can't you inspect Chrome's source code? It's 99.999% identical to the open source Chromium. – forest Jun 11 '18 at 13:10
  • @Socobbecause they are both trusted pieces of code. One is put out by Google and has been vetted by thousands of security annalists, and the other has been approved by Google to be in there webstore and vetted / recommended by several reputable sources. Similarly the packages I download via apt-get, homebrew, or choco have all been reviewed by the people who manage those repos. – CaffeineAddiction Jun 11 '18 at 13:18
  • @forest The 0.001% which is different from Chromium cannot be inspected. The fraction of unknown code may be small, but that doesn’t change the qualitative statement. – Socob Jun 11 '18 at 13:26
  • 1
    The 0.001% is small enough that manual static analysis can reveal what it does. Just a nitpick. – forest Jun 11 '18 at 13:29

2 Answers2

7

Anything you can do on a compromised account, an attacker can do as well.

Fundamentally, this is because Linux providers isolation between users, not between individual processes running as the same user. Any process running as a given user is considered to have equivalent capabilities as any other processes running under that user.

Is it true that the system sudo executable can be circumvented in this way?

Yes, and in other ways as well. If you elevate privileges to root on a compromised unprivileged account, you compromise root. If you drop privileges from root using su to an unprivileged account, you also compromise root! You can never safely elevate privileges on an untrusted account. While it's possible to exploit the system using PATH, it's also possible to hijack the bash process itself to sniff key input. Disabling execution with noexec is further not useful because interpreters (bash, python, perl, etc) will still run. The noexec option is not and has never been designed as a security feature, despite it being regularly peddled as such.

An incomplete list of ways an attacker could hijack the use of sudo or su:

  • Using the LD_PRELOAD variable on the parent process (e.g. bash).

  • Hooking the parent process with ptrace() or process_vm_writev().

  • Sniffing or injecting keystrokes into the terminal emulator using the X11 protocol.

  • Creating aliases or functions to wrap the actual sudo executable.

I explained these in more detail on my answer to another question.

Why are desktop Linux systems, by default, set up in such an easily exploitable way?

Elevating privileges on an untrusted account is not something you are supposed to do. Not to mention, desktop Linux is an afterthought in the grand scheme of the general *nix architecture. It is a failure of security theater incessantly repeating the same bad advice, not a failure of the security architecture of Linux itself. People repeatedly say to use sudo for root because many new users will instead run everything as root, even their browsers! In this case, it is better to be using sudo. It is harmful in the case where the user is already smart enough not to use root for everything.

Note that sudo is highly configurable and can be designed to allow only certain commands. This is where it really shines. You can configure sudo to only allow you to run apt-get update as root (with or without a password), and deny everything else. That would additionally restrict an attacker from doing anything other than... well... doing a software update.

It's important to remember that, even if you configure it to only allow running certain commands as root, you can still shoot yourself in the foot if you whitelist programs that are not designed to run as root via an untrusted user. I saw a real-life example of someone trying to run VeraCrypt in this way and explained why it is insecure. The idea was that VeraCrypt is safe to run as root, so it should be safe to use sudo to elevate it to root as an untrusted, unprivileged user. It turns out the idea is flawed, and allows trivial privilege escalation!

Shouldn’t the default way to invoke sudo make sure that it is, in fact, the executable provided by the system (nobody is going to type /usr/bin/sudo every time)?

Typing the full path will not protect you! You can easily create a function that contains a leading /, and it will override the real executable. Even if the executable did make sure that it is genuine and attempted to defeat sniffing, a malicious process could hijack the bash process and sniff keystrokes independently of sudo, making it impossible to detect from its point of view.

$ function /usr/bin/sudo { echo 'hijacked!'; }
$ /usr/bin/sudo id
hijacked!

In such an environment, it seems that using sudo is fundamentally insecure and one would be better off enabling login as root and logging in on a separate TTY.

This is always the case. Note that even logging into another TTY is not perfectly safe. You should use SAK, the Secure Attention Key combination, to ensure that you are interacting with a genuine login session (agetty or logind, for example). SAK is a key combination that the kernel listens for (and thus cannot be repressed by userspace). When it detects it, it will kill every process in the current TTY, triggering the login prompt to appear. If you have switched to a genuine, uncompromised TTY, then it will only cause the prompt to disappear and reappear. If you are on a hijacked TTY, it will kill the malicious process and bring back the genuine login prompt.

Glorfindel
  • 2,235
  • 6
  • 18
  • 30
forest
  • 64,616
  • 20
  • 206
  • 257
  • Thank you for the detailed answer. I have a few follow-up questions. Concerning your list of ways to hijack `sudo`: “*Using the `LD_PRELOAD` variable on the parent process*” – how would this work? I thought a child process cannot affect the environment of the parent process? “*Sniffing or injecting keystrokes into the terminal emulator using the X11 protocol*” – this would be prevented by using Wayland, correct? “*Creating aliases or functions to wrap the actual sudo executable*” – OK, but this would require the use of (e. g.) `.profile` again, so basically the same as my approach? – Socob Jun 11 '18 at 12:50
  • “*Typing the full path will not protect you! You can easily create a function that contains a leading /, and it will override the real executable.*” Once again, it seems that by eliminating `.profile` et al. as an attack vector (or “hard-coding” `sudo` as a system service in some way), this would be prevented. Essentially, I’m surprised/worried that current desktop Linux has so many areas which are insecure-by-default, when there are seemingly simple ways around these issues. – Socob Jun 11 '18 at 12:50
  • @Socob `LD_PRELOAD` would poison the environment that `bash` itself runs in, meaning that anything you run from it cannot be trusted. `LD_PRELOAD` is a variable that causes a library to automatically be loaded. Wrt the X11 protocol, yes in theory Wayland should protect from that. – forest Jun 11 '18 at 12:58
  • Eliminating `.profile` and such would only go so far. There's a dozen other files that your shell will look for. Even if it does not see any files, a malicious process (after all, your threat model begins with a malicious actor who has code execution privs) can hijack the running bash process. – forest Jun 11 '18 at 12:59
  • Maybe I misunderstood. I meant that if a user normally starts (e. g.) `bash`, `LD_PRELOAD` will not be set. Starting another program from `bash`, even if it is malicious, will not affect the `bash` process itself (unless system calls like you mentioned are used). Although arguably more difficult, I’d also expect desktop distros to use AppArmor or SELinux to prevent such system calls. What bothers me is that elevation using `sudo` is treated like “running just another userspace program” instead of a secured, system-critical procedure, as it is (e. g., as far as I understand) on Windows. – Socob Jun 11 '18 at 13:21
  • 1
    Well rather than using AppArmor, they use something called the Yama LSM which attempts to block it. It's still not perfect though. And you are right to be bothered about that. It's not a secured procedure like Windows' UIPI for UAC is (supposed to be). Desktop Linux security is in a sad state. – forest Jun 11 '18 at 13:22
0

First, changing .profile will not automagically achieve privilege escalation. The user affected must already have sudo rights.

1 - sudo is not being circunvented. You are running something else in place of it. You could change .profile and add alias sudo=~/.evilsudo and achieve the same.

2 - You think about the lazy way of configuring sudo. On a desktop environment, that would be the case, but not on a server environment. On a server environment, /etc/sudoers should grant the user only the commands he will need to run to execute his task. You would expect the Oracle admin to run sudo service oracle, so that would be on sudoers. Not oradmin ALL=(ALL:ALL) ALL for example.

And it's already too late if someone runs code on your account. Anybody changing your .profile could start another shell capturing every single key press, and you lose not only your password, but everything else you type on it. Remote ssh passwords, database passwords, ftp passwords, anything. If your .profile is compromised, it's game over.

If you really want to protect the user against this, mount every single user-writable directory as noexec. This way ~/bin or /tmp or whatever else will not have permission to execute anything. You marginally increase security and dramatically decrease convenience.

ThoriumBR
  • 50,648
  • 13
  • 127
  • 142
  • I'm not sure how `noexec` will help with this _at all_. You could still run arbitrary code with interpreters like Python and hook the bash process to intercept keystrokes. In particular, I've hijacked a system when the user ran `sudo` without ever needing the `exec` mount flag. – forest Jun 11 '18 at 02:56
  • You stated "...fake sudo executable, such as PATH=$HOME/.evil:$PATH". With `noexec`, nothing would execute from $HOME/.evil. And you hijacked the system when you compromised his account, when you got `sudo` the system was already compromised. – ThoriumBR Jun 11 '18 at 03:00
  • OP stated that as an example. It's still possible to use a modified profile to hijack a user which uses `sudo` without needing to execute an executable. – forest Jun 11 '18 at 03:03
  • That's why I said it would marginally increase security. You can use `alias` for that. And again, as soon as you compromise the account of a privileged user, it's game over. Compromise the account of a Windows Domain Admin, and it's over. Compromise the account of a zOS RACF Special user, and it's over. There's no protection against that. – ThoriumBR Jun 11 '18 at 03:07
  • I'm not sure how it marginally increases security any more than patching `bash` to look for `.profile2` in hopes that a hardcoded exploit will not find it is marginally increasing security. – forest Jun 11 '18 at 03:09
  • `chown root /home/user/.{,bash_}profile` – ThoriumBR Jun 11 '18 at 03:14
  • Not sure how that would help. Since the parent directory is writable, an attacker could just change the permissions back, or rename it and create a new file in its place. – forest Jun 11 '18 at 03:16
  • Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/78709/discussion-between-thoriumbr-and-forest). – ThoriumBR Jun 11 '18 at 03:18