Exposure to privilege escalation
Some functions require special privileges to run correctly, or are only able to be run by certain users or members of certain groups, such as local administrators. Other functions require the user's account to have specific privileges enabled, for instance to obtain access to a system resource. For example, in a network service, super-user privileges are often required to allocate a privileged TCP or UDP port, which a normal user can't do.
Although elevated privileges may be needed only temporarily, many programs never drop the elevated privileges and continue to run with unnecessary root privileges.
To drop privileges, a process needs to set its effective user and group IDs to those of the less privileged user or group using the seteuid() and setegid() system calls to drop them temporarily, or setuid() and setgid() to drop them permanently.
When a low-privileged program needs to perform a high-privileged operation, such as opening a privileged file, the program needs to elevate privileges using setuid. The setuid feature allows executables launched as a user to run with root privileges. Again, it's common that the program fails to revert to its lower privileges at soon as it finishes performing the high-privileged operation.
The SV.USAGERULES.PERMISSIONS checker finds instances of calls for privilege elevation to setegid(), seteuid(), setuid(), setregid(), and setreuid(), as well as AddAccessAllowedAce() or AddAccessAllowedAceEx(), and flags them for review.
Vulnerability and risk
To reduce the possibility of unauthorized code being able to get control, the system should run with the least privilege necessary. Applications that need to call functions that require special privileges can leave the system open to attack by hackers. Running with extra privileges can disable the normal security checks in the operating system or environment, and pre-existing weaknesses turn into security vulnerabilities during operation at raised privileges. Applications should be designed to run with elevated privileges only for short periods of time and should inform the user of the security implications involved.
Mitigation and prevention
The first step in establishing which type of account your application needs to run under is to examine the resources the application will use and the privileged APIs it will call. You may find that the application, or large parts of it, doesn't need administrator privileges. Writing Secure Code, by Michael Howard and David LeBlanc, offers an excellent description of how to carry out this assessment, and is highly recommended.
For less exposure to malicious attack, use the following approaches:
- Run under an account with less privilege whenever possible, raising privileges as late as possible and lowering them as soon as possible. One way to do this is to use PrivilegeCheck to determine what privileges are enabled in a token. If the available privileges are not adequate for the current operation, you can disable that code and ask the user to log in to an account with administrator privileges.
- Make sure users are authenticated adequately by user name and password. You can authenticate the user by calling CredUIPromptForCredentials (GUI) or CredUICmdLinePromptForCredentials (command line) to obtain user name and password.
- Impersonate the user. A process that starts under a highly privileged account like the system can impersonate a user account by calling ImpersonateLoggedOnUser or similar impersonate functions to reduce the privilege level. A call to RevertToSelf is injected into the thread to return the process to the original system privileges.
- Isolate privileged code. Break functions that need administrator permissions into separate applications.
- Drop privileges with the correct revocation order. In the case of setuid and setguid programs, it's important to drop the group-level privileges and then the user-level privileges.
Make sure elevated privileges are dropped successfully. It is important to check the return values from the following calls:
When the program is manipulating privileges, a call to any of these functions failing may result in privileges not being reduced. If the return value isn't checked and appropriate action taken, the program may continue operation as the privileged account.
- CERT POS02-C: Follow the principle of least privilege
- CERT POS36-C: Observe correct revocation order while relinquishing privileges
- CERT POS37-C: Ensure that privilege relinquishment is successful
- CWE-250: Execution with Unnecessary Privileges
- CWE-269: Improper Privilege Management
- CWE-273: Improper Check for Dropped Privileges
- CWE-732: Incorrect Permission Assignment for Critical Resource
- OWASP A1:2021 Broken Access Control
- OWASP A4:2021 Insecure Design
- STIG-ID: APP3450.1 Access Control
- STIG-ID: APP3480.1 Role-Based Access
- STIG-ID: APP3480.2 Role-Based Access
- STIG-ID: APP3500 Excessive Privileges
- STIG-ID: APP3590.2 Application is vulnerable to buffer overflows