Guide to API Privilege Escalation
Poor implementations of this system may cause root
-privilege vulnerabilities and compromised servers. Read the Security requirements section of this document before you use this system.
To run a function with escalated privileges, call a function through the Call
method or use the send_cpwrapd_request
pluggable wrapper. The system manages privilege escalation, and ensures that the user can only run the permitted code.
-
cPanel, L.L.C. introduced the
Call
method for Perl admin modules in cPanel & WHM version 54 in order to simplify construction of modules. We recommend that you write admin modules with this method when possible. For earlier versions and other programming languages, use the Standard method . -
To query all of the
SETUID
andSETGID
values on a server, run the following command:find / -type f \( -perm -04000 -o -perm -02000 \) \-exec ls -lg {} \;
The Admin module method
In cPanel & WHM version 82 and later, cPanel, L.L.C. recommends that you develop Perl admin modules as subclasses of the Cpanel::Admin::Base
base class.
For more information, read our Admin Module method documentation.
The Call method (54+)
cPanel, L.L.C. introduced this functionality in cPanel & WHM version 54 for admin modules in Perl.
Basic usage
For cPanel & WHM versions 80 and earlier, you can develop admin modules as subclasses of the cPanel-provided Cpanel::AdminBin::Script::Call
base class. This class, and the Cpanel::AdminBin::Call
module that accompanies it, contain privilege escalation logic so that admin modules are simpler to write and call.
To make a TheModule
module in the TheNameSpace
namespace, perform the following steps:
-
Create the
/usr/local/cpanel/bin/admin/TheNameSpace
directory. -
Run the following command to create the
configuration
file:
echo mode=full > /usr/local/cpanel/bin/admin/TheNamespace/TheModule.conf
-
Create your new module in the
/usr/local/cpanel/bin/admin/TheNamespace/TheModule
file. -
Set that file to be executable with the following command:
chmod 0700 /usr/local/cpanel/bin/admin/TheNamespace/TheModule
Example
The following example admin
module uses the Call
method:
#!/usr/local/cpanel/3rdparty/bin/perl
package TheNamespace::TheModule;
use strict;
use parent 'Cpanel::AdminBin::Script::Call';
__PACKAGE__->run() if !caller;
sub _actions { return qw( DO_GOOD ) }
sub DO_GOOD {
my ($self, $arg1, $arg2) = @_;
return "I did good with "$arg1" and "$arg2->[0]".";
}
1;
Class methods
The run(OPTS)
method runs the script after it checks whether the first element in the value of the @ARGV
array is --bincheck
. If --bincheck
exists in the @ARGV
array, the system prints the BinCheck ok
message with a trailing newline and the process performs an exit()
. This is normally how Call
-type admin modules invoke themselves when run from a script.
-
The
OPTS
object is an optional list of arguments that can include thealarm
argument, an integer that represents a timeout value for the script. This option defaults to 350 seconds. -
The following example includes the
run()
method with thealarm
argument:__PACKAGE__->run( alarm => 600 ); #allow 10 minutes rather than the default 350 seconds
The new(OPTS)
method is identical to the run()
method, but it does not check whether the first element in the value of the @ARGV
array is the --bincheck
flag.
- This method helps you test your module.
-
For example, the following example includes the
new()
method:TheTestedModule->new();
DO_GOOD
To call the DO_GOOD
function from unprivileged code, your code should resemble the following example:
my $resp = Cpanel::AdminBin::Call::call('TheNamespace', 'TheModule', 'DO_GOOD', 'first arg', ['second arg']);
The above example passes the first arg
and second arg
parameters to the DO_GOOD
method in the admin
module.
- This example returns one value, but you may also return a list.
- Input parameters and return values may be scalars, array references, or hash references.
-
This structure does not support scalar references, references that use the
bless()
function, and self-referential data structures as inputs or outputs.
The code calls the admin
function with the same context (void, scalar, or list) as the Cpanel::AdminBin::Call::call()
method itself. The system handles mismatched returns (for example, an array in scalar context as a return value) as Perl handles them. The admin
module traps exceptions and then re-throws them without a stack trace in the code that calls them.
For a full example, read our Guide to API Privilege Escalation - Call Your Application documentation.
The $self
parameter in the example contains a reference to the instance of your admin
module and class. Your class will inherit several useful methods such as get_caller_username()
from the Cpanel::AdminBin::Script::Call
module.
For more information, read our Guide to API Privilege Escalation - Object Methods documentation.
The Standard method
Basic usage
To use privilege escalation in your custom code, perform the following steps:
-
Create the following files:
- A configuration file. Download a simple example file: Simple.tar.gz .
- An application file. Download an an advanced example file: Advanced.tar.gz .
- Never use any of these example files on a production system.
-
Store these files in a new namespace in the
/usr/local/cpanel/bin/admin/
directory.- The namespace and the directory name must be identical.
-
Do
not
create your
AdminBin
application in theCpanel
namespace.
-
Use the
Cpanel::AdminBin::send_cpwrapd_request
method to call the application as the authenticated user.
Security requirements
Whenever you use this system, do not manipulate files or directories that a user owns as the root
user or execute any actions on unvalidated input.
You must adhere to the following security practices:
-
Only
use this system to execute code that must run as the
root
user. - Thoroughly validate any input that passes through this system.
- Sanitize the admin script's environment.
To sanitize the admin
script's environment, set environment variables to limit the paths from which the script loads libraries.
-
This action sanitizes the
@INC
array and ensures that users cannot load arbitrary libraries. -
The following example adds the
/usr/local/cpanel/
directory to the environment, and then removes entries that do not match standard Perl library paths:BEGIN { unshift @INC, '/usr/local/cpanel'; @INC = grep( !/(^\.|\.\.|\/\.+)/, @INC ); }