pluck-cms / pluck

Central repo for pluck cms
http://www.pluck-cms.org
56 stars 39 forks source link

Pluck cms v4.7.4 getshell vulerability #45

Closed jgj212 closed 6 years ago

jgj212 commented 7 years ago

description

Pluck cms v4.7.4 getshell vulerability

details

critical code in /data/modules/blog/blog.site.php, $POST is passed to blog_save_reaction, 'blog_reaction_email' and 'blog_reaction_website' will be filtered:

                //If form is posted...
                if (isset($_POST['submit'])) {
                    //Check if everything has been filled in.
                    if (empty($_POST['blog_reaction_name']) || filter_input(INPUT_POST, 'blog_reaction_email', FILTER_VALIDATE_EMAIL) == false || (($_POST['blog_reaction_website'] != 'http://' && !empty($_POST['blog_reaction_website'])) && filter_input(INPUT_POST, 'blog_reaction_website', FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED) == false) || empty($_POST['blog_reaction_message']))
                        echo '<p class="error">'.$lang['contactform']['fields'].'</p>';

                    //Add reaction.
                    else {
                        blog_save_reaction($_GET['post'], $_POST['blog_reaction_name'], $_POST['blog_reaction_email'], $_POST['blog_reaction_website'], $_POST['blog_reaction_message']);

                        //Redirect user.
                            redirect(SITE_URI.'/'.PAGE_URL_PREFIX.CURRENT_PAGE_SEONAME.BLOG_URL_PREFIX.$_GET['post'], 0);
                    }
                }

blog_save_reaction in /data/modules/blog/functions.php, $name and $message will be sanitized, but $website and $email will not be sanitized:

function blog_save_reaction($post, $name, $email, $website, $message, $id = null, $force_time = null) {
    global $lang;

    //Sanitize variables.
    $name = sanitize($name);
    $message = sanitize($message);
    $message = nl2br($message);

    //Have to make sure that the dir exists.
    if (!is_dir(BLOG_POSTS_DIR.'/'.$post)) {
        mkdir(BLOG_POSTS_DIR.'/'.$post);
        chmod(BLOG_POSTS_DIR.'/'.$post, 0777);
    }

    if (!empty($id))
        include BLOG_POSTS_DIR.'/'.$post.'/'.$id.'.php';

    else {
        $files = read_dir_contents(BLOG_POSTS_DIR.'/'.$post, 'files');

        if ($files) {
            $id = count($files);
            $id++;
        }

        else
            $id = 1;

        if (empty($force_time))
            $reaction_time = time();
        else
            $reaction_time = $force_time;
    }

    $data['reaction_name']    = $name;
    $data['reaction_email']   = $email;
    if ($website != 'http://' && !empty($website))
        $data['reaction_website'] = $website;
    $data['reaction_message'] = $message;
    $data['reaction_time']    = $reaction_time;

    save_file(BLOG_POSTS_DIR.'/'.$post.'/'.$id.'.php', $data);
}

savefile in /data/inc/functions.all.php, there is no security checking about $value:

function save_file($file, $content, $chmod = 0777) {
    $data = fopen($file, 'w');

    //If it's an array, we have to create the structure.
    if (is_array($content) && !empty($content)) {
        $final_content = '<?php'."\n";
        foreach ($content as $var => $value) {
            $final_content .= '$'.$var.' = \''.$value.'\';'."\n";
        }
        $final_content .= '?>';

        fputs($data, $final_content);
    }

    else
        fputs($data, $content);

    fclose($data);
    if ($chmod != FALSE)
        chmod($file, $chmod);
}

We found that filter_input is not sufficient, So $_POST[‘blog_reaction_website’] and $_POST[‘blog_reaction_email’] can cause getshell.

POC: 1) install cms, login with admnistartor to create a blog, create a page and insert blog to it, logout with administrator 2) browser the page as guest, and click reactions, submit data as follow: 1 Website data is: http://www.google.com/index.php';phpinfo();//

After click send, phpinfo() will be excuted 2

Credit: ADLab of VenusTech

BSteelooper commented 6 years ago

See my pull request #48