HexBrain

Concrete CMS · Report #1063039

Phar Deserialization Vulnerability via Logging Settings

Validstatus
mediumseverity
5upvotes
24 Sept 2021disclosed

How it was found

Vulnerability Description:

The vulnerable code is located within the concrete/controllers/single_page/dashboard/system/environment/logging.php script. Specifically, into the Logging::update_logging() method:

    public function update_logging()
    {
        $config = $this->app->make('config');
        $request = $this->request;

        if (!$this->token->validate('update_logging')) {
            return $this->showError($this->token->getErrorMessage());
        }

        // Load in variables from the request
        $mode = (string) $request->request->get('logging_mode') === 'advanced' ? 'advanced' : 'simple';
        $handler = $mode === 'simple' ? (string) $request->request->get('handler', 'database') : null;
        $logFile = $handler === 'file' ? (string) $request->request->get('logFile') : null;
        $enableDashboardReport = $request->request->get('enable_dashboard_report') ? true : false;
        $loggingLevel = strtoupper((string) $request->request->get('logging_level'));
        $intLogErrorsPost = $request->request->get('ENABLE_LOG_ERRORS') === 1 ? 1 : 0;
        $intLogEmailsPost = $request->request->get('ENABLE_LOG_EMAILS') === 1 ? 1 : 0;
        $intLogApiPost = $request->request->get('ENABLE_LOG_API') === 1 ? 1 : 0;


        // Handle 'file' based logging
        if ($handler === 'file') {
            $directory = dirname($logFile);

            // Validate the file name
            if (pathinfo($logFile, PATHINFO_EXTENSION) !== 'log') {
                return $this->showError(t('The filename provided must be a valid filename and end with .log'));
            }

            // Validate the file path, create the log file if needed
            if (!file_exists($logFile)) {
                // If the file doesn't exist, make sure we can create one
                if (!is_writable($directory) || !is_dir($directory)) {
                    return $this->showError(t('Log file does not exist on the server. The directory of the file provided must exist and be writable on the web server.'));
                }

User input passed through the “logFile” request parameter is not properly sanitized before being used in a call to the file_exists function. This can be exploited by malicious users to inject arbitrary PHP objects into the application scope (PHP Object Injection via phar:// stream wrapper), allowing them to carry out a variety of attacks, such as executing arbitrary PHP code.

Reproduction Steps:

  1. Login to the Concrete5 instance as an admin user
  2. Go to "System & Settings" -> "Files" -> "Allowed File Types" and add log to File Extensions to Accept
  3. Use the attached Proof of Concept (PoC) script to create a sample Phar file to upload (just run php phar-generator.php from the CLI)
  4. Go to "Files" and upload the phar.log file
  5. Take note of the path where the file has been uploaded (e.g. application/files/4916/0848/5009/phar.log)
  6. Go to "System & Settings" -> "Environment" -> "Logging Settings" and select File as Handler
  7. Put the following string into the File text box: phar://./application/files/4916/0848/5009/phar.log
  8. Click the Save button, go to http://[host]/[concrete5]/application/files/tmp/test.php and you will see a "phpinfo" page

Notes:

The vulnerability has been successfully tested on Concrete5 versions 8.5.4 and 8.5.5 RC1.

Impact

This vulnerability might be abused by malicious users to inject and execute arbitrary PHP code on the web server. However, successful exploitation requires an admin account, and this partially mitigates the issue.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original