Skip to content

Instantly share code, notes, and snippets.

@themanyone
Created October 4, 2024 07:40
Show Gist options
  • Save themanyone/c9683fdaa77adf9f4dcb1dd2d22a0318 to your computer and use it in GitHub Desktop.
Save themanyone/c9683fdaa77adf9f4dcb1dd2d22a0318 to your computer and use it in GitHub Desktop.
make a script always run as root

How to make a script always run as root

Operation not permitted. Could it be because it is a bash script?

The error message Operation not permitted can occur because you are attempting to set the setuid bit on a Bash script.

Most modern Unix-like operating systems, including Linux, ignore the setuid bit on scripts for security reasons. Setting setuid on scripts can lead to various security vulnerabilities, such as privilege escalation attacks, which is why the operating system typically disallows it.

Why setuid Doesn’t Work on Scripts

  1. Security Risks:

    • Race Conditions: Scripts are interpreted line by line, which can be exploited between the time the script is checked and the time it is executed.
    • Interpreter Vulnerabilities: If the interpreter (e.g., /bin/bash) has vulnerabilities, they can be exploited to execute malicious code with elevated privileges.
    • Environment Manipulation: Attackers can manipulate the environment (e.g., PATH, IFS) to execute unintended commands with elevated privileges.
  2. Kernel Restrictions:

    • Most Unix-like kernels are designed to ignore the setuid bit on scripts to prevent these security issues. This behavior is by design and cannot be easily overridden without modifying kernel parameters, which is not recommended.

Alternatives to Using setuid on Scripts

Since setting the setuid bit on scripts is not feasible, here are some secure alternatives to achieve elevated privileges for specific tasks:

1. Use a Compiled Wrapper Binary

Create a small compiled program (in C, for example) that performs the privileged operations and set the setuid bit on this binary instead of the script.

Steps:

  1. Write a C Program:

    // wrapper.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main() {
        // Ensure the program is running with elevated privileges
        if (setuid(0) != 0) {
            perror("setuid");
            return 1;
        }
    
        // Execute the desired script
        system("/path/to/your/script.sh");
        return 0;
    }
  2. Compile the Program:

    gcc -o wrapper wrapper.c
  3. Set Ownership and setuid Bit:

    sudo chown root:root wrapper
    sudo chmod 4755 wrapper
  4. Run the Wrapper:

    ./wrapper

    This approach allows the wrapper binary to run with root privileges and execute the script. However, ensure that the wrapper is secure and doesn't expose vulnerabilities.

2. Use sudo with Proper Configuration

Configure sudo to allow specific users to execute particular scripts with elevated privileges without requiring the setuid bit.

Steps:

  1. Edit the sudoers File:

    Use visudo to safely edit the sudoers file.

    sudo visudo
  2. Add a Rule for the Specific Script:

    username ALL=(ALL) NOPASSWD: /path/to/your/script.sh
    

    Replace username with the actual user's name.

  3. Execute the Script with sudo:

    sudo /path/to/your/script.sh

    This method allows controlled elevation of privileges for specific commands or scripts.

3. Leverage Capabilities (Linux Specific)

Instead of granting full root privileges, you can assign specific capabilities to an executable. This approach minimizes security risks by granting only the necessary permissions.

Example: Assigning Network Binding Capability

If your script needs to bind to low-numbered ports (below 1024):

  1. Create a Wrapper Binary:

    Similar to the first alternative, create a compiled binary that performs the necessary privileged operations.

  2. Assign Capabilities:

    sudo setcap 'cap_net_bind_service=+ep' /path/to/your/executable

    This command grants the ability to bind to privileged ports without full root privileges.

Note: Capabilities cannot be directly applied to scripts; they must be applied to binaries.

4. Use PolicyKit (polkit) for GUI Applications

For graphical applications or more complex privilege management, polkit provides a mechanism to define fine-grained policies for system-wide privileges.

Resources:

Best Practices and Security Considerations

Regardless of the method you choose, keep the following best practices in mind:

  1. Principle of Least Privilege:

    • Grant the minimal necessary privileges required for the task.
    • Avoid granting full root access when only specific permissions are needed.
  2. Input Validation and Sanitization:

    • Ensure that any inputs to scripts or binaries are properly validated to prevent injection attacks.
  3. Secure Coding Practices:

    • If writing wrapper binaries, ensure they are free from vulnerabilities such as buffer overflows.
  4. Audit and Logging:

    • Keep logs of actions performed with elevated privileges for auditing purposes.
    • Regularly review logs to detect any unauthorized or suspicious activities.
  5. Use Trusted Tools and Libraries:

    • Avoid writing custom privilege escalation tools unless absolutely necessary. Use well-maintained and trusted tools whenever possible.
  6. Regular Updates and Patching:

    • Keep your system and all related software up to date with security patches.

Example: Using sudo for a Specific Script

Here's a step-by-step example of configuring sudo to allow a user to run a specific script with root privileges without a password prompt.

  1. Create the Script:

    sudo touch /usr/local/bin/my_privileged_script.sh
    sudo chmod 755 /usr/local/bin/my_privileged_script.sh

    Edit the script as needed, for example:

    #!/bin/bash
    # my_privileged_script.sh
    echo "This script runs with elevated privileges."
    # Add privileged commands here
  2. Edit the sudoers File:

    sudo visudo

    Add the following line at the end (replace username with the actual user):

    username ALL=(ALL) NOPASSWD: /usr/local/bin/my_privileged_script.sh
    
  3. Run the Script with sudo:

    sudo /usr/local/bin/my_privileged_script.sh

    The script will execute with root privileges without prompting for a password.

Conclusion

Setting the setuid bit on Bash scripts is not permitted due to inherent security risks. Instead, consider using alternative methods such as compiled wrapper binaries, configuring sudo with appropriate permissions, leveraging Linux capabilities, or using polkit for finer-grained control. Always prioritize security by adhering to best practices and minimizing the scope of elevated privileges.

If you need further assistance with a specific method or encounter additional issues, feel free to ask!

@themanyone
Copy link
Author

Note that the compiled wrapper must start with the if(setuid(0) !=) {perror("setuid") stanza. It won't work if it launches right into system().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment