In modern IT environments, the need for implementing least-privilege access is often driven because of a combination of tightening security and regulatory compliance:
- The need to get rid of authentication with shared accounts due to lack of traceability.
For example, traditionally in most environments, UNIX system administrators have full access to the root account of the systems they manage. Unbridled access to the system root account prevents or severely complicates the requirement of traceability: as multiple system administrators know the root password, it is not possible to differentiate between who did what using the shared root account. As the root account provides full system access, this creates a huge gap in security.
This requirement does not limit itself to the root account; application users often access systems with a shared account, which has the same consequences for traceability.
- The desire to implement access according to least privileges.
Application users and consultants usually need access to a well-defined subset of commands that need to be run as a shared application account. Giving them the ability to run any command as the target application account may open up a path of potential abuse; not only by the user that is granted these permissions themselves, but any intruder that manages to compromise the account of this target user.
It may even be desired to limit the list of commands that a user can run, beyond what the operating system considered privileged commands (i.e. entries in the sudoers file); For example, to reduce the attack surface of an unprivileged user's shell, or maybe to prevent users with limited UNIX knowledge from inflicting damage on all user-writable files.
The standard tool to address the above concerns on Unix/Linux operating systems is sudo; The sudo package allows enforcement of a policy, defined in /etc/sudoers, that contains entries specifying users with access to specific commands, which can then be run with pre-defined privileges ('the runas credentials'). Centrify provides its own tools that supports the same functionality as sudo, as well as a range of features that sudo does not provide.
Each time a user runs a command with sudo, it is being recorded in the system's log. Keylogging and screen output capture can be enabled by specifying the log_output sudo option in the sudoers file. This records input and output data into various files in a tree-like structure in the local filesystem.
Proper implementation of the log_output data in a large environment is not for the faint-hearted, nor is querying the keyboard input or screen output (input is recorded as raw scan codes). To get a complete picture, enabling log_output would commonly need to be combined by logging of system calls with the audit daemon (auditd) and centralisation using remote syslog and storage into a backend database or search server like ElasticSearch and/or SIEM solution.
Centrify makes implementation of auditing requirements much easier, through its DirectAudit component, part of Centrify Server Suite Enterprise Edition. However, in this article the focus does not lie on DirectAudit; instead the core functionality of sudo, that allows implementation of least privileges, is explored in-depth.
Centrify provides its own sudo-like tool, called dzdo, which provides full command-line compatibility with sudo, but differs substantially from sudo in certain key areas:
- dzdo allows centralisation of least-access policies without needing LDAP extensions in Active Directory, nor the implementation of additional systems with high availability. dzdo takes advantage of the high-availability nature of Active Directory and stores all least-access policies in the native Active Directory schema.
- dzdo can be configured to require multi-factor authentication, on a per-command definition basis.
- dzdo allows implementation of least privileges through role-based access control (RBAC), where roles are represented as Active Directory groups without the need for a UNIX identity. This differs from sudo, which can only be used with users and groups on the local system, and thus requires groups to have a UNIX identity. As a result, usage of dzdo in large environments where large and complex policies for managing least privileges are in place, reduces the amount of UNIX group identities greatly, and reduces the administrative burden of the security policies..
- Tight integration between dzdo and the above-mentioned DirectAudit component; access to privileged commands can be coupled to availability of the auditing subsystem. In this scenario, if an attacker or power outage would take down the auditing subsystem, execution of specific privileged commands can be denied.
- dzdo can work with regular expressions as command definitions. Unix system engineers are often familiar with the power and versatility provided by regular expressions; now they can leverage this knowledge when implementing the security policies, for example to quickly and accurately define the various parameters that may be passed to a binary, part of a privileged command right definition.
- dzdo rights can be added to Centrify Role definitions that are effective only during certain hours of the day, and/or certain days of the week
- dzdo can be used to run a validation script prior to allowing access to a privileged command. This allows for implementation of advanced features that are then evaluated at run-time, such as recording of a ticket number when logging workflow process information, or dynamic security rules.
- dzdo can be used to tighten security beyond privileged command execution; Centrify provides a special shell wrapper called dzsh, referred to as the 'Restricted Shell', that filters all commands that are run on the command line in a user's shell. When using this feature, an unprivileged user is only allowed to run those binaries that they're explicitly allowed to run, and can include the specific parameters that are allowed for each binary.
- dzdo can be used with multi-factor authentication.
- A further advantage of dzsh is that it can be used to detect a user wanting to run a privileged command, without requiring the user to explicitly run dzdo/sudo with the proper target user and group options. This feature improves the usability of least privileges for users that are not already very familiar with sudo.
Various information has previously been released on the first four bullet-points. For example:
In this article we'll explore the Restricted Shell further. When organisations mention regulatory compliance for least-privilege, and use terms like 'whitelisting' and 'blacklisting' in combination with unprivileged accounts, usage of the Restricted Shell comes into play. The terms blacklisting and whitelisting commonly are used as follows:
Whitelisting refers to the fact that by default, no command is allowed, except for a specific list of commands, which is the so-called 'whitelist'.
Whitelisting is the basic operation of dzsh; without any command definitions in place, dzsh allows a user only to run the built-in shell commands (for a complete list of built-in shell commands on a Linux distribution, run 'man bash' and search for the section 'SHELL BUILTIN COMMANDS').
Blacklisting refers to the ability of denying access to specific commands that would otherwise be allowed. This can be used in two ways:
- to reduce the scope of a whitelist, commonly used to disallow running a command with specific command line parameters, while running the command with other parameters is allowed.
- to allow all commands by default, except for the commands in the blacklist.
During my work, the second blacklisting scenario has been brought up several times. Unfortunately, implementation of this type of blacklisting on linux does not translate into any meaningful security, but may require some examples to show why this is the case.
Suppose an unprivileged user is allowed to run any command, except '/bin/ls'.
- While the user cannot run the /bin/ls command, they can copy the command to a user-writeable location, such as their home directory, and even name it differently if needed.
Next, access to the '/bin/cp' command is denied too.
- This still does not prevent the user from copying ls and running it under a different name, as there are plenty of other methods of copying the file, such as vi, cat, nano, emacs. In short, just about any command that can read files and has a 'save as' option, or that allows reading a file to /dev/stdout, which can then be re-directed on the shell to a file with a different name.
In a further step, suppose all user-writeable paths on the system are eliminated.
- In this scenario, if the user still has access to compile tools (gcc), they could pipe code for the 'ls', 'cp' or any other denied program from a remote host on the network to the local compiler, and execute it without writing it to disk.
...This list could go on almost endlessly with methods to bypass the blacklist alternated by more severe restrictions to prevent the bypass method. In short, it's a very time-consuming game of catch-up, that will never be able to fully stop insistent and creative UNIX user with shell access, from performing those actions that administrators are trying to deny.
While dzdo does not allow identifying binaries through file hash or signature (for signed code), these features would not help in the above blacklisting examples either. Signature data can easily be stripped, and strings in a file can be modified, resulting in a different hash value of the binary.
Instead of following this fruitless approach of blacklisting, in an environment where by default all commands are allowed, a better approach has previously been mentioned:
- All commands that an unprivileged user need access to, should be explicitly defined in a whitelist for the Restricted Shell. The blacklisting functionality could then be used to reduce the scope of commands in the whitelist. With a whitelist of finite and limited size, the amount of possibilities of bypassing the blacklist is greatly reduced, and with some care can even be fully eliminated.
Using the Restricted Shell
To use the restricted shell, first add a new Centrify Role definition to the target Centrify zone. This role definition can be named accordingly, e.g. 'UNIX Restricted Shell'. In the System Rights tab, make sure the following options are set:
- Password and non-password (SSO) login are allowed
- Non-password (SSO) login is allowed
- User is visible.
Note to make sure that 'Login with non-Restricted Shell' has NOT been checked.
Now click on OK to confirm the new Role Definition.
Right-click the new Role definition, and select Add right... ; now add the ssh and sshd PAM access rights, allowing the users to access target machines through SSH.
You can now assign this role definition like any other, either through zone-wide Role Assignments, or through Computer Roles.
Next, to allow a user to run any binaries in addition to the built-in shell commands, you'll need to create explicit command rights.
For example, you can grant a user access the right to run the dzinfo command, which shows the Centrify authorization data on the machine on which they have access. This allows users of the restricted shell to see what exactly they can run.
In the Restricted Shell tab, make sure that the Can be used in a restricted role option has been checked, and that the Run this command as data is set to the User running the command (unless you want to define a privileged command in the restricted shell, i.e. similar to what the Run As tab does for dzdo commands in a regular shell).
In the Run As tab, disable the option Can be used by dzdo; if you don't do this, you'll grant any user that has been granted permission to run the dzdo command, the ability to run the unprivileged command as root (this is the default setting when you create a new command right). This step is extremely important, as the pam access right to the dzdo PAM facility is implicitly granted to all users; there are no further barriers in place, other than having to allow the users to run the dzdo binary (it is a bad idea to grant users access to the dzdo command in the restricted shell, as you can run privileged commands by setting a different user in the Restricted Shell tab of the command right definition. Combining the dzdo tab with the restricted shell in one command right definition leads to poor visibility of the effective rights, and can easily lead to accidentally granting more access than desired).
Now add the newly defined command right for use in the Restricted Shell to the Role definition that grants access to the Restricted Shell.
For examples on how to limit the scope of the whitelist by adding certain command line parameters to the blacklist, I'd suggest you to look at the example in the blog post of my colleague Fabrice.
Note that careful attention needs to be paid to any command that has the ability to spawn child processes and run arbitrary code. For example, even a text editor such as 'vi' can be used to run shell commands. For this reason, the Allow nested command execution option in the Attributes tab should be disabled, unless explicitly required; and in that case, it should be enabled only after careful validation that the target program cannot run arbitrary user-specified code in the child processes.