Headline
CVE-2023-4792: duplicate-post-page-menu-cpt.php in duplicate-post-page-menu-custom-post-type/trunk – WordPress Plugin Repository
The Duplicate Post Page Menu & Custom Post Type plugin for WordPress is vulnerable to unauthorized page and post duplication due to a missing capability check on the duplicate_ppmc_post_as_draft function in versions up to, and including, 2.3.1. This makes it possible for authenticated attackers with subscriber access or higher to duplicate posts and pages.
1<?php23/*45* Plugin Name: Duplicate Post Page Menu & Custom Post Type67* Description: The best plugin to duplicate post, page, menu and custom post type multiple times in a single click.89* Author: Inqsys Technology1011* Version: 2.3.11213* Text Domain: duplicate-ppmc1415* Author URI: http://www.inqsys.com/1617*1819*/2021/* Check for wordpress installation */2223define( 'PPMC_URL’, plugin_dir_url( __FILE__ ) );24define( 'PPMC_V’, ‘2.3.1’ );2526if ( ! function_exists( ‘add_action’ ) ) {2728 die( ‘Wordpress installation not found!’ );2930} else {3132 require_once( plugin_dir_path(__FILE__) . ‘/class-duplicate-ppmc-settings.php’ );3334} /* End of wordpress installation check */353637/* Check if such class already exist */3839if ( ! class_exists( ‘Duplicate_PPMC_Init’ ) ) {4041 class Duplicate_PPMC_Init {4243 /* Constructor for action hooks */4445 function __construct() {4647 add_filter( ‘plugin_action_links_’.plugin_basename( __FILE__ ), array( $this, ‘duplicate_ppmc_settings_link’ ) );4849 add_action(‘wp_ajax_ppmc_remove_rating’, array( $this, ‘ppmc_remove_rating’ ) );50 add_action(‘wp_ajax_ppmc_remove_discount_notice’, array( $this, ‘ppmc_remove_discount_notice’ ) );51 52 register_activation_hook(__FILE__, array( $this, ‘duplicate_ppmc_activate’));5354 /* Enqueue javascript to admin panel */5556 add_action( ‘admin_enqueue_scripts’, array( $this, ‘duplicate_ppmc_admin_scripts’ ) );5758 /* Handle all cloning process */5960 add_action(‘init’, function(){ 61 if( get_option(‘dppmc_installationNewDate’) === false ){62 update_option(“dppmc_installationNewDate",date(‘Y-m-d h:i:s’) );63 }64 } );6566 add_action('wp_ajax_duplicate_ppmc’, array( $this, ‘duplicate_ppmc_post_as_draft’ ));6768 add_action('wp_ajax_duplicate_ppmc_menu_maker’, array( $this, ‘duplicate_ppmc_menu_maker’ ));69 70 /* Add duplicate controler for post/page */7172 add_filter( 'post_row_actions’, array( $this, ‘duplicate_ppmc_post_link’ ), 10, 2 );7374 add_filter( 'page_row_actions’, array( $this, ‘duplicate_ppmc_post_link’ ), 10, 2 );75 76 add_action( 'post_submitbox_misc_actions’, array( $this, ‘duplicate_ppmc_inpost_button’ ), 60, 2 );77 78 add_action( 'admin_notices’, array( $this, ‘duplicate_ppmc_admin_notice’),100 );7980 add_action( 'admin_notices’, array( $this, ‘duplicate_ppmc_discount_notice’),100 );8182 /* Extra button on plugin page */83 add_filter( 'plugin_action_links_duplicate-post-page-menu-custom-post-type/duplicate-post-page-menu-cpt.php’, array( $this, ‘ppmc_plugin_row_meta’) );8485 /* Add L18n text domain */ 86 add_action( 'plugins_loaded’, array( $this, ‘dppmc_load_plugin_textdomain’ ) );8788 } /* End of __construct() */8990 function aajax(){91 echo 'Ajax function’;92 echo $_REQUEST[‘post’] . ' id post coppied for ' . $_REQUEST[‘copies’] . ' times’;93 die();94 }95 96 function ppmc_plugin_row_meta( $links ) { 9798 $row_meta = array(99 ‘buy_pro’ => ‘<a href="’ . esc_url( ‘https://www.inqsys.com/duplicate-post-page-menu-custom-post-type-pro-wordpress-plugin/’ ) . '” style="font-weight:700;color:red;" target="_blank" aria-label="’ . esc_attr__( ‘Plugin Pro’, ‘dppmc_load_plugin_textdomain’ ) . ‘" style="color:green;">’ . esc_html__( ‘BUY PRO’, ‘dppmc_load_plugin_textdomain’ ) . ‘</a>’100 );101 return array_merge( $row_meta , $links);102103 }104 105 function ppmc_remove_rating(){106 update_option(‘ppmc_support_us_now_x’,’true’); 107 }108109 function ppmc_remove_discount_notice(){110 set_transient( ‘ppmc_remove_discount_notice_xmas_’.PPMC_V , true, DAY_IN_SECONDS * 30 );111 }112113 function duplicate_ppmc_admin_notice(){114115 if( !get_option( “ppmc_next_period_ratings” ) ){116 update_option("ppmc_next_period_ratings", date(‘Y-m-d h:i:s’, strtotime(‘+6 months’) ) );117 }118 119 $support = get_option(‘ppmc_support_us_now_x’);120 $recurring_ask = get_option( ‘ppmc_next_period_ratings’ );121 $install_date = get_option(‘dppmc_installationNewDate’);122 $display_date = date( ‘Y-m-d h:i:s’ );123 $install_date= new DateTime( $install_date );124 $current_date = new DateTime( $display_date );125 $ask_again = new DateTime( $recurring_ask );126 $ask_again = $current_date->diff( $ask_again );127 $ask_days = $ask_again->days;128 $ask_invert = $ask_again->invert;129 $difference = $install_date->diff($current_date);130 $diff_days= $difference->days;131132 if( $ask_days >= 0 && $ask_invert == 1){133 update_option( ‘ppmc_support_us_now_x’, “false” );134 update_option( ‘ppmc_next_period_ratings’, date("Y-m-d h:i:s", strtotime(“+6 months”)) );135 }136137 if( $support != “true” && $diff_days >= 2 ) {138139 $html = "<div class=’notice notice-info important’ id=’message’ style=’padding: 10px;position:relative;line-height:30px;’>";140 $html .= "Thank you for choosing <strong>Duplicate Post Page Menu & Custom Post Type.</strong>";141 $html .= " If you are enjoying using our plugin, kindly leave us a review on <a class=’button button-primary’ href=’https://wordpress.org/plugins/duplicate-post-page-menu-custom-post-type/#reviews’ target=’_blank’>wordpress.org</a><br/>";142 $html .= "<strong><a href=’https://www.inqsys.com/donate’ target=’_new’>Buy Me A Coffee</a></strong> to support the development of this plug-in. ";143 $html .= "<strong><a href=’https://www.inqsys.com/duplicate-post-page-menu-custom-post-type-pro-wordpress-plugin/’ target=’_new’>Buy Pro Version</a></strong> with extra features & lifetime support. ";144 $html .= " <a style=’text-align:right;display:block;’ class=’’ id=’ppmc_done’ >Already Done!</a>";145 $html .= "</div>";146 147 $html .= "<script>148 if( jQuery() != ‘undefined’){149 jQuery(document).ready(150 function($){151 $(‘#ppmc_done’).on(‘click’,function(){152 $.ajax({153 type : ‘post’,154 dataType : ‘json’,155 url : ‘".admin_url(‘admin-ajax.php’)."’,156 data : {action: ‘ppmc_remove_rating’},157 success: function(response) {158 document.location.reload();159 }160 })161 });162 }163 );164 }165 </script>";166 167 echo $html;168 }169 }170171 function duplicate_ppmc_discount_notice(){172173 $should_display = get_transient( ‘ppmc_remove_discount_notice_xmas_’.PPMC_V );174 $display_date = date( ‘d M Y’ );175 $dateFrom = strtotime(“15 December 2021”);176 $dateTo = strtotime(“1 January 2022”);177178 $compare = $dateTo > strtotime($display_date);179 if( false != $should_display || strtotime($display_date) > $dateTo || strtotime($display_date) < $dateFrom ){180 return;181 }182 183 $html = "<div class=’notice notice-info important’ style=’padding: 10px;position:relative;line-height:30px;’>";184 $html .= "<button id=’ppmc-dismiss-sale’ type=’button’ style=’top:0;right:0;position:absolute;background:#72777c;border: 0;color: white;font-size:16px;border-radius:50px;cursor:pointer’>X</button>";185 $html .= "<a href=’https://www.inqsys.com/duplicate-post-page-menu-custom-post-type-pro-wordpress-plugin/’ target=’_new’>";186 $html .= "<img src=’".PPMC_URL."assets/xmas-discount.jpg’ style=’padding-right:10px;width:100%;height:200px’></a>";187 $html .= "<div>188 Hurry!! We are offering <strong>50% off</strong> on our premium plugins. The offer is valid until midnight of ".date(‘d F Y’, $dateTo).".189 To use this offer, use coupon code- “<strong>SAVE50</strong>”. 190 <a class=’button button-primary’ href=’https://www.inqsys.com/duplicate-post-page-menu-custom-post-type-pro-wordpress-plugin/’ target=’_new’>Get your deals now!</a>191 <div id=’ppmc-not-interested’ class=’button button-secondry’>Not Interested</div>192 </div>";193 194 $html .= "</div>";195 196 $html .= "<script>197 if( jQuery() != ‘undefined’){198 jQuery(document).ready(199 function($){200 $(‘#ppmc-dismiss-sale,#ppmc-not-interested’).on(‘click’,function(){201 $.ajax({202 type : ‘post’,203 dataType : ‘json’,204 url : ‘".admin_url(‘admin-ajax.php’)."’,205 data : {action: ‘ppmc_remove_discount_notice’},206 success: function(response) {207 document.location.reload();208 }209 })210 });211 }212 );213 }214 </script>";215216 echo $html;217 }218219 /* Set default option values at the time of plugin activation */220221 function duplicate_ppmc_activate(){222223 if( !get_option(“dppmc_installationNewDate”) ){224 update_option(“dppmc_installationNewDate",date(‘Y-m-d h:i:s’) );225 }226 227 if( !get_option( ‘dppmc_post’ ) ){228229 $post_types = Duplicate_PPMC_Settings::dppmc_all_post();230231 update_option( 'dppmc_post’, ‘0’);232233 update_option( 'dppmc_page’, ‘0’ );234235 update_option( 'dppmc_menu’, ‘0’ );236237238239 foreach($post_types as $post_type){240241 update_option( 'dppmc_’. $post_type->name, ‘0’ );242243 }244245246247 }248249250251 } /* End of duplicate_ppmc_activate() */252253 254255 function dppmc_load_plugin_textdomain(){256257 load_plugin_textdomain( ‘duplicate-ppmc’, false, basename( dirname( __FILE__ ) ) . ‘/languages/’ );258259 }/* End of dppmc_load_plugin_textdomain() */260261262263 /* Create ‘Settings’ option in plugin page */264265 function duplicate_ppmc_settings_link( $links ) {266267 $settings_link = ‘<a href="options-general.php?page=dppmc-settings">’ . __( ‘Settings’ ) . ‘</a>’;268269 array_push( $links, $settings_link );270271 return $links;272273 }/* End of duplicate_ppmc_settings_link */274275276277 /* Make sure values are not null */278279 function duplicate_ppmc_menu_maker() {280 $response = array();281 /* Check for vaild input */282283 if ( ! isset( $_REQUEST[‘name’] ) ) {284285 echo ‘<strong> Something went wrong </strong>’;286 die();287288 }289290291292 /* Make sure values are vaild to process */293294 $name = sanitize_text_field( $_REQUEST[‘name’].’-duplicate’ );295296 if ( true === is_nav_menu($name) ) {297298 $response[“error”] = ‘Menu <strong>’. $name .’</strong> already exist<br/>Please delete or rename the previous menu.’ ;299 echo json_encode( $response );300 die();301 }302303304305 $source = wp_get_nav_menu_object( $_REQUEST[‘name’] );306307 $source_items = wp_get_nav_menu_items( $_REQUEST[‘name’] );308309 $new_id = wp_create_nav_menu( $name );310311 /* Ready to process the menu for duplication */312313 $rel = array();314315 $i = 1;316317 foreach ( $source_items as $menu_item ) {318 319 $args = array(320321 ‘menu-item-db-id’ => $menu_item->db_id,322323 ‘menu-item-object-id’ => $menu_item->object_id,324325 ‘menu-item-object’ => $menu_item->object,326327 ‘menu-item-position’ => $i,328329 ‘menu-item-type’ => $menu_item->type,330331 ‘menu-item-title’ => $menu_item->title,332333 ‘menu-item-url’ => $menu_item->url,334335 ‘menu-item-description’ => $menu_item->description,336337 ‘menu-item-attr-title’ => $menu_item->attr_title,338339 ‘menu-item-target’ => $menu_item->target,340341 ‘menu-item-classes’ => implode( ' ‘, $menu_item->classes ),342343 ‘menu-item-xfn’ => $menu_item->xfn,344345 ‘menu-item-status’ => $menu_item->post_status346347 ); // End of for-each()348349350351 $parent_id = wp_update_nav_menu_item( $new_id, 0, $args );352353 $rel[$menu_item->db_id] = $parent_id;354355 /* Just reassuring, child shouldn’t be left home-alone */356357 if ( $menu_item->menu_item_parent ) {358359 $args[‘menu-item-parent-id’] = $rel[$menu_item->menu_item_parent];360361 $parent_id = wp_update_nav_menu_item( $new_id, $parent_id, $args );362363 }364365366367 $i++;368 } /* End of foreach() */369370371372 /* Refresh(redirect to) the current page */373 374 $response[“menu_id”] = $new_id ;375 echo json_encode( $response );376 die();377 } /* End of duplicate_ppmc_menu_maker() */378379380381 /* Duplicate the selected post and put the new post in draft */382383 function duplicate_ppmc_post_as_draft() {384385 global $wpdb;386387 /* Check for post request */388389 if ( ! ( isset( $_REQUEST[‘post’]) || isset( $_REQUEST[‘post’]) || ( isset( $_REQUEST[‘action’] ) && ‘duplicate_ppmc_post_as_draft’ == $_REQUEST[‘action’] ) ) ) {390391 echo ‘<strong>No post to duplicate has been supplied!</strong>’;392 die();393394 } /* End of if */395396397398 /* Create a single entry if multiple is not required or a non positive number is passed */399400 $copy_required = absint( $_REQUEST[‘copies’] ) ? $_REQUEST[‘copies’]: 1 ;401402403404 /* Loop through number of duplication request */405406 for ( $J = 1; $J <= $copy_required; $J++ ){407408409410 /* Get the original post id */411412 $post_id = ( isset( $_REQUEST[‘post’] ) ? absint( $_REQUEST[‘post’] ) : absint( $_REQUEST[‘post’] ) );413414 /* Get all the original post data */415416 $post = get_post( $post_id );417418419420 /* Get current user and make it new post user (duplicate post) */421422 $current_user = wp_get_current_user();423424 $new_post_author = $current_user->ID;425426427428 /* If post data exists, duplicate the data into new duplicate post */429430 if ( isset( $post ) && null != $post ) {431432433434 /* New post data array */435436 $args = array(437438 ‘comment_status’ => $post->comment_status,439440 ‘ping_status’ => $post->ping_status,441442 ‘post_author’ => $new_post_author,443444 ‘post_content’ => $post->post_content,445446 ‘post_excerpt’ => $post->post_excerpt,447448 ‘post_name’ => $post->post_title . '-duplicate-' . $J,449450 ‘post_parent’ => $post->post_parent,451452 ‘post_password’ => $post->post_password,453454 ‘post_status’ => ‘draft’,455456 ‘post_title’ => $post->post_title . '-duplicate-' . $J,457458 ‘post_type’ => $post->post_type,459460 ‘to_ping’ => $post->to_ping,461462 ‘menu_order’ => $post->menu_order463464 );465466467468 /* Duplicate the post by wp_insert_post() function */469470 $new_post_id = wp_insert_post( $args );471472473474 /* Get all current post terms and set them to the new post draft */475476 $taxonomies = get_object_taxonomies($post->post_type);477478 foreach ( $taxonomies as $taxonomy ) {479480 $post_terms = wp_get_object_terms( $post_id, $taxonomy, array(‘fields’ => ‘slugs’ ) );481482 wp_set_object_terms( $new_post_id, $post_terms, $taxonomy, false );483484 }485486487488 /* Duplicate all post meta-data */489490 $post_meta_data = $wpdb->get_results( ‘SELECT meta_key, meta_value FROM ‘.$wpdb->postmeta.’ WHERE post_id=’.$post_id.’;’ );491492 if ( 0 != count($post_meta_data) ) {493494 $sql_query = ‘INSERT INTO ‘.$wpdb->postmeta.’ (post_id, meta_key, meta_value ) ‘;495496 foreach ( $post_meta_data as $meta_data ) {497498 $meta_key = $meta_data->meta_key;499500 if ( ‘_wp_old_slug’ == $meta_key )501502 continue;503504 $meta_value = addslashes($meta_data->meta_value );505506 $sql_query_sel[]= $wpdb->prepare( “SELECT %d,%s,%s", array( $new_post_id, $meta_key, $meta_value ));507 }508509 $sql_query.= implode(' UNION ALL ', $sql_query_sel );510511 $wpdb->query($sql_query);512513 }514515516517 } else {518519 /* This error must not occur in most cases. But incase it occur. This is how we handle it */520521 echo '<strong>Post creation failed, could not find original post: ' . $post_id .’</strong>’;522 die();523 }524525526527 } /* End of for-loop */528529 /* Reload the current page to load all new created draf post/page */530531 wp_redirect( $_SERVER[‘HTTP_REFERER’] );532533 exit();534535 } /* End of duplicate_ppmc_post_as_draft() */536537 538 /* Add duplicate button in post/page editor screen */539 function duplicate_ppmc_inpost_button($post){540 541 $isDuplicationEnable = get_option( 'dppmc_’.$post->post_type );542 543 if ( current_user_can('edit_post’, $post->ID ) && ‘0’ === $isDuplicationEnable ) {544 $html = ‘<div style="padding-left:10px;padding-bottom:10px;">’;545 $html .= "<a id=’Btdppmc’ ppmc_post_id=".$post->ID.” class=’duplicate_ppmc_item_no".$post->ID."’>Duplicate This </a> " .546 " <input style=’width:60px !important;’ type=’number’ value=’1’ min=’1’ max=’5’ id=’duplicate_ppmc_item_no".$post->ID."’ name=’duplicate_ppmc_item_no’>";547 $html .= '</div>’;548 549 echo $html;550 }551 }552553554 /* Add the duplicate link to action list for post_row_actions. */555556 function duplicate_ppmc_post_link( $actions, $post ) {557 558 $isDuplicationEnable = get_option( 'dppmc_’.$post->post_type );559560 /* Check if user is capable of editing and cloning is enable on post */561562 if ( current_user_can('edit_post’, $post->ID ) && ‘0’ === $isDuplicationEnable ) {563564 /* A button for duplicating the post565566 * and an html number input box for creating multiple duplicate post567568 * two elements are combined into single ‘$action[]' array variable for removing seprator569570 * Asingle line is devided into two for making it more readable571572 */573574 $actions[‘dppmc_btn_count’] = "<a id=’Btdppmc’ ppmc_post_id=".$post->ID.” class=’duplicate_ppmc_item_no".$post->ID."’ >".__(‘Duplicate’, ‘duplicate-ppmc’)."</a> " .575576 "<input style=’width:60px !important;’ type=’number’ value=’1’ min=’1’ max=’5’ id=’duplicate_ppmc_item_no".$post->ID."’ name=’duplicate_ppmc_item_no’>";577578 }579580 return $actions; /* Return the post link action ASA the controler(s) are added */581582583584 } /* End of duplicate_ppmc_post_link */585586587588 /* Enqueue the jQuery script in admin dashboard */589590 function duplicate_ppmc_admin_scripts() {591592593 wp_enqueue_script( 'duplicate_ppmc_admin_js’, plugins_url('assets/js/operations.js’, __FILE__ ) ,594 array( ‘jquery’ ), true, true );595596 wp_enqueue_script( 'duplicate_ppmc_admin_js_vex’, plugins_url('assets/js/vex.min.js’, __FILE__ ) , 597 array( ‘jquery’ ), true, true );598 599 wp_enqueue_script( 'duplicate_ppmc_admin_js_combined_vex’, plugins_url('assets/js/vex.combined.min.js’, __FILE__ ) , 600 array( ‘jquery’ ), true, true );601 602 wp_enqueue_style( 'duplicate_ppmc_admin_style_css’, plugins_url('assets/css/style.css’, __FILE__ ) );603 wp_enqueue_style( 'duplicate_ppmc_admin_css_vex’, plugins_url('assets/css/vex.css’, __FILE__ ) );604 wp_enqueue_style( 'duplicate_ppmc_admin_css_vex_theme_os’, plugins_url('assets/css/vex-theme-os.css’, __FILE__ ) );605 606 /* Send required data to javascript for use */607608 wp_localize_script( 'duplicate_ppmc_admin_js’, 'duplicate_ppmc_ENG’,609610 array(611612 'enable_in_menu’=>get_option(‘dppmc_menu’),613614 'dppmc_bt_name’=>__('Duplicate’, ‘duplicate-ppmc’),615 'ajax_url’=>admin_url(‘admin-ajax.php’)616 )617618 );619620 } /* end of duplicate_ppmc_admin_scripts() */621622623 } /* End of duplicate_ppmc_init{} */624625 return new Duplicate_PPMC_Init();626627} /* End of if-class_exists() */