CVE-2023-0046 (PHP, published 2023-01-04T12:15Z)
Description: value: Improper Restriction of Names for Files and Other Resources in GitHub repository lirantal/daloradius prior to master-branch.
Severity: nan (CVSS v3 base score: 7.2)
Weakness: CWE-641 \u2014 Improper Restriction of Names for Files and Other Resources
The product constructs the name of a file or other resource using input from an upstream component, but it does not restrict or incorrectly restricts the resulting name.
Repository: https://github.com/lirantal/daloradius
Files changed:
config-backup.php
config-logging.php
Commit message: Better validating log filepath (#326)



Vulnerable code:
?>

        </div><!-- #contentnorightbar -->
        
        <div id="footer">
<?php
    include('page-footer.php');
        </div><!-- #footer -->
    </div>
</div>

</body>
</html>

    // if the form has been submitted we validate and store the configuration
    if (array_key_exists('submit', $_POST) && isset($_POST['submit'])) {
        
        foreach ($param_label as $param => $label) {
            if (array_key_exists($param, $_POST) && isset($_POST[$param]) &&
                in_array(strtolower($_POST[$param]), array("yes", "no"))) {
                $configValues[$param] = $_POST[$param];

        if (array_key_exists('CONFIG_LOG_FILE', $_POST) && isset($_POST['CONFIG_LOG_FILE']) &&
            is_writable($_POST['CONFIG_LOG_FILE'])) {
            $configValues['CONFIG_LOG_FILE'] = $_POST['CONFIG_LOG_FILE'];
        }

        include("library/config_write.php");
    }    

    include("library/layout.php");

?>

<form name="loggingsettings" method="POST">
    <fieldset>
        <h302><?= t('title','Settings'); ?></h302>
        <br>
        
        <ul>
<?php
        print_select_as_list_elem($name, $label, array("no", "yes"), $configValues[$name]);
?>

            <li class="fieldset">
                <label for="CONFIG_LOG_FILE" class="form"><?= t('all','FilenameLogging') ?></label>
                <input value="<?= $configValues['CONFIG_LOG_FILE'] ?>" name="CONFIG_LOG_FILE" id="CONFIG_LOG_FILE">
            </li>


            <li class="fieldset">
                <br/><hr><br/>
                <input type="submit" name="submit" value="<?= t('buttons','apply') ?>" class="button">
            </li>
        </ul>
    </fieldset>
</form>

        </div><!-- #contentnorightbar -->
        
        <div id="footer">
<?php
    include('page-footer.php');
?>
        </div><!-- #footer -->
    </div>
</div>
</body>
</html>

Fixed code:
    
    
    print_footer_and_html_epilogue();
    include('library/check_operator_perm.php');
    
    // init logging variables
    $logAction = "";
    $logDebugSQL = "";
    
    include("library/validation.php");
    include("library/layout.php");
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        if (array_key_exists('csrf_token', $_POST) && isset($_POST['csrf_token']) && dalo_check_csrf_token($_POST['csrf_token'])) {
            
            $isError = false;
            
            // validate yes/no params
            foreach ($param_label as $param => $label) {
                if (array_key_exists($param, $_POST) && !empty(strtolower(trim($_POST[$param]))) &&
                    in_array(strtolower(trim($_POST[$param])), array("yes", "no"))) {
                    $configValues[$param] = $_POST[$param];
                }
            
            // validate path
            $log_path_prefix = $configValues['CONFIG_PATH_DALO_VARIABLE_DATA'] . "/log";
            $log_file_suffix = ".log";
            
            if (array_key_exists('CONFIG_LOG_FILE', $_POST) && !empty(trim($_POST['CONFIG_LOG_FILE']))) {
                $candidate_log_file = trim($_POST['CONFIG_LOG_FILE']);
                
                if (
                        // this ensure that the log_path_prefix is a directory
                        is_dir($log_path_prefix) &&

                        // this ensures that candidate_log_file starts with the log_path_prefix
                        substr($candidate_log_file, 0, strlen($log_path_prefix)) === $log_path_prefix &&
                        
                        // this ensures that candidate_log_file does not contain ".."
                        strpos($candidate_log_file, "..") === false &&
                        
                        // this ensures that candidate_log_file ends with the log_file_suffix
                        substr($candidate_log_file, -strlen($log_file_suffix)) === $log_file_suffix &&
                        
                        // this ensures that candidate_log_file is at a writable location
                        // or that at least it can be written inside the parent directory
                        (is_writable($candidate_log_file) || is_writable(dirname($candidate_log_file)))
                    ) {
                    
                    $configValues['CONFIG_LOG_FILE'] = $candidate_log_file;
                    
                } else {
                    $isError = true;
                }
            } else {
                $isError = true;
            }
            
            // we write ONLY IF isError is false
            if (!$isError) {
                include("library/config_write.php");
            } else {
                $failureMsg = sprintf("Log path not allowed. Ensure that log file name locates a writable %s file contained in %s",
                                      $log_file_suffix, $log_path_prefix);
                $logAction .= "$failureMsg on page: ";
            }
            
        } else {
            // csrf
            $failureMsg = "CSRF token error";
            $logAction .= "$failureMsg on page: ";
    }
        
    
    $fieldset0_descriptor = array(
                                    "title" => t('title','Settings')
                                 );
    
    
    $input_descriptors0 = array();
    
        $input_descriptors0[] = array(
                                        "type" => "select",
                                        "options" => array( "yes", "no" ),
                                        "caption" => $label,
                                        "name" => $name,
                                        "selected_value" => $configValues[$name]
                                     );
    
    $input_descriptors0[] = array(
                                        "type" => "text",
                                        "caption" => t('all','FilenameLogging'),
                                        "name" => 'CONFIG_LOG_FILE',
                                        "value" => $configValues['CONFIG_LOG_FILE']
                                     );
    
    $input_descriptors0[] = array(
                                    "name" => "csrf_token",
                                    "type" => "hidden",
                                    "value" => dalo_csrf_token(),
                                 );

    $input_descriptors0[] = array(
                                    'type' => 'submit',
                                    'name' => 'submit',
                                    'value' => t('buttons','apply')
                                 );
    
    open_form();
    
    // open 0-th fieldset
    open_fieldset($fieldset0_descriptor);
    
    foreach ($input_descriptors0 as $input_descriptor) {
        print_form_component($input_descriptor);
    }
    
    close_fieldset();
    
    close_form();
    
    
    print_footer_and_html_epilogue();
?>