Headline
CVE-2023-2987: config.php in wordapp/trunk/includes – WordPress Plugin Repository
The Wordapp plugin for WordPress is vulnerable to authorization bypass due to an use of insufficiently unique cryptographic signature on the ‘wa_pdx_op_config_set’ function in versions up to, and including, 1.5.0. This makes it possible for unauthenticated attackers to the plugin to change the ‘validation_token’ in the plugin config, providing access to the plugin’s remote control functionalities, such as creating an admin access URL, which can be used for privilege escalation.
1<?php2/**3 * Configuration related functions.4 *5 * @author Sheroz Khaydarov http://sheroz.com6 * @license GNU General Public License, version 27 * @license http://www.gnu.org/licenses/gpl-2.0.html8 * @copyright Wordapp, 20179 * @link https://github.com/sheroz/wp-wordapp-plugin10 * @since 1.0.011 */1213/**14 * Clears configuration data.15 * Removes Wordapp plugin related configuration data from the WordPress option storage. Called internally when plugin activated, deactivated or uninstalled.16 *17 * @internel18 */19function wa_pdx_config_clear()20{21 delete_option( PDX_CONFIG_OPTION_KEY );22 if (PDX_LOG_ENABLE)23 {24 $log = "Plugin Configuration Removed.\n";25 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);26 }27}2829/**30 * Checks configuration data.31 *32 * @return mixed The non-confidential information about plugin status33 */34function wa_pdx_op_config_check()35{36 global $wp_version;37 $cfg = get_option( PDX_CONFIG_OPTION_KEY );38 wa_pdx_send_response(array (39 ‘configured’ => !empty($cfg),40 ‘ajax-url’ => admin_url(‘admin-ajax.php’),41 ‘plugin-version’ => PDX_PLUGIN_VERSION_NUMBER,42 ‘wp-version’ => $wp_version,43 ‘plugins-found’ => wa_pdx_look_for_plugins()44 ), true);45}4647/**48 * Sets configuration.49 * This operation is initiated from Wordapp Platform to configure plugin for further data exchange operations.50 *51 * @api52 *53 * @param array $params The operation parameters passed from Wordapp Platform.54 *55 * @return mixed JSON that indicates success/failure status56 * of the operation in ‘success’ field,57 * and an appropriate ‘data’ or ‘error’ fields.58 */59function wa_pdx_op_config_set ($params)60{61 if (PDX_LOG_ENABLE) {62 $log = "— PDX_OP_CONFIG_SET —\n";63 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);64 }6566 if (empty($params))67 wa_pdx_send_response(‘Invalid Data’);6869 $ticket_id = $params[‘ticket_id’];70 $api_pdx_url = $params[‘api_pdx_url’];71 $timestamp = $params[‘timestamp’];72 $signature = $params[‘signature’];7374 if (empty($ticket_id) || empty($api_pdx_url))75 wa_pdx_send_response(‘Invalid Params’);7677 /* // test signature78 $signed_data = '02cb861f54267b72e01b5f522a904b20ff9bd604d94a039b90d6a8ef1e10006a8ehttp://localhost:3000/api/pdx’;79 $signature_hex_ruby = '8a9e38a3aba180f8424b20e7fe3e3075569032e30ff0fdef29031f0701ebda853b26d8d8bc5f698151780a287072fb78811fb3259f4e2b38e3e5cde82a92f3e58deaf378182821d7b03b0ce7682089eac0b56bb48a02b6a9281154e524056b8b3ccbb6666aca1d5271046dd997e0e627080f757af1db7b80238e7747dcdacd7e2db3409998b3c99474ad02ed5f82ef8118ff5a668604a02a758577fa1d66fdf96afc719a10ca015e3c5327a978c7275f0f88f1c8e84b90cb46dab592abbaa03fdc49dfd703f489124ba43f1283dd939b3ea9dda75c9d68c548ac8e1ad1416c934d6db5563769578c0c8ddc1d9a4fe40cebcb007b5f525a9e0a57faa820234be0’;80 $signature_php =’’;8182 openssl_sign($signed_data, $signature_php, $PDX_PRV_KEY_PEM_2048, “SHA256”);8384 $signature_php_hex = bin2hex($signature_php);85 $log.= "RUBY signature: " . $signature_hex_ruby ."\n";86 $log.= "PHP signature : " . $signature_php_hex ."\n";8788 // function hex2bin($data) {89 // $len = strlen($data);90 // return pack(“H” . $len, $data);91 // }9293 $ok = openssl_verify($signed_data, $signature_php, $PDX_PUB_KEY_PEM_2048, “SHA256”);94 if ($ok == 1) {95 $log.= "PHP signature good\n";96 } elseif ($ok == 0) {97 $log.= "PHP signature bad\n";98 } else {99 $log.= "PHP signature ugly, error checking signature\n";100 }101102 */103104 $wa_pdx_options = wa_pdx_get_options();105106 if ($wa_pdx_options[‘validate_signature’])107 {108 $reassembled_data = sprintf("%02x", PDX_OP_WP_CONFIG_SET);109 $reassembled_data .= $ticket_id;110 $reassembled_data .= $api_pdx_url;111 $reassembled_data .= dechex($timestamp);112113 $reassembled_data = strtolower ( $reassembled_data);114115 $signature = pack(“H” . strlen($signature), $signature);116 $verified = openssl_verify($reassembled_data, $signature, PDX_PUB_KEY_PEM_2048, “SHA256”);117118 if (PDX_LOG_ENABLE)119 {120 $log = "Reassembled data: " . $reassembled_data ."\n";121 if ($verified == 1) {122 $log.= "Signature verification result: OK.\n";123 } elseif ($verified == 0) {124 $log.= "Signature verification result: FAILED.\n";125 } else {126 $log.= "Signature verification result: Unknown Error.\n";127 }128 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);129 }130131 if ( $verified != 1 ) {132 wa_pdx_send_response(‘Signature verification failed.’);133 }134 }135136 if ($wa_pdx_options[‘validate_ip’])137 {138 $sender = $_SERVER[‘REMOTE_ADDR’];139 $ips = explode(' ', $wa_pdx_options[‘server_ip’]);140 $found = false;141 foreach ($ips as $ip) {142 if ($found = ($sender==$ip))143 break;144 }145 if (!$found)146 wa_pdx_send_response(‘IP Verification Failed:’ . $_SERVER[‘REMOTE_ADDR’]);147 }148149 if (PDX_CONFIG_PUSH == 1)150 {151 $pdx_config = $params[‘config’];152 if (empty($pdx_config))153 wa_pdx_send_response(‘Invalid configuration parameter.’);154155 update_option( PDX_CONFIG_OPTION_KEY, $pdx_config );156157 if (PDX_LOG_ENABLE)158 {159 $log = "direct config set: " . json_encode($pdx_config) ."\n";160 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);161 }162 wa_pdx_send_response('Configuration set successfully’, true);163 }164165 $api_pdx_tickets_url = $api_pdx_url . '/tickets’;166167 if (PDX_LOG_ENABLE)168 {169 $log = "Configuration process started…\n";170 $log.= "Knocking the door of the Wordapp Platform with ticket: $ticket_id at $api_pdx_tickets_url\n";171 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);172 }173 /*174 $data_string = json_encode(array( ‘ticket_id’ => $ticket_id ));175 $api_pdx_headers = array(176 'Accept: application/json’,177 'Accept-Encoding: gzip, deflate’,178 'Accept-Language: en-US,en;q=0.8’,179 'Content-Type: application/json; charset=utf-8’,180 'Content-Length: '. strlen($data_string),181 'User-Agent: '.PDX_PLUGIN_VERSION,182 'X-Api-Version: application/vnd.wordapp-v1+json’183 );184 $ch = curl_init();185 curl_setopt($ch, CURLOPT_URL,$api_pdx_tickets_url);186 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, “POST”);187 // curl_setopt($ch, CURLOPT_POST, 1);188 curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);189 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);190 curl_setopt($ch, CURLOPT_HTTPHEADER, $api_pdx_headers);191 // curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,0);192 // curl_setopt($ch, CURLOPT_TIMEOUT, 5); //timeout in seconds193194 $response = curl_exec($ch);195 curl_close($ch);196 */197198 $args = array(199 ‘method’ => 'POST’,200 ‘httpversion’ => '1.0’,201 ‘headers’ => array(202 ‘Accept’ => 'application/json’,203 ‘Accept-Encoding’ => 'gzip, deflate’,204 ‘Accept-Language’ => 'en-US,en;q=0.8’,205 ‘Content-Type’ => 'application/json; charset=utf-8’,206 ‘User-Agent’ => 'Wordapp Plugin Version ' . PDX_PLUGIN_VERSION_NUMBER,207 ‘X-Api-Version’ => 'application/vnd.wordapp-v1+json’208 ),209 ‘timeout’ => 5,210 ‘blocking’ => true,211 ‘body’ => json_encode(array( ‘ticket_id’ => $ticket_id ))212 );213214// $http = new WP_Http();215// $response = $http->request($api_pdx_tickets_url, $args);216217 $response = wp_remote_post($api_pdx_tickets_url, $args);218219 if ( is_wp_error( $response ) ) {220 $error_message = $response->get_error_message();221 if (PDX_LOG_ENABLE)222 {223 $log = "Configuration fetch phase 2 failed. Url: $api_pdx_tickets_url\nError message: $error_message\n";224 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);225 }226 wa_pdx_send_response(‘Configuration fetch phase 2 failed’);227 }228229 $response_code = wp_remote_retrieve_response_code( $response );230 if ($response_code != 200) {231 if (PDX_LOG_ENABLE)232 {233 $log = "Invalid response code: $response_code\n";234 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);235 }236 wa_pdx_send_response(‘Invalid response code’);237 }238239 $response_body = wp_remote_retrieve_body( $response );240 if (empty($response_body)) {241 if (PDX_LOG_ENABLE)242 {243 $log = "Empty configuration data\n";244 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);245 }246 wa_pdx_send_response(‘Empty configuration data’);247 }248249 if (PDX_LOG_ENABLE)250 {251 $log = "Configuration data received: " . $response_body ."\n";252 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);253 }254255 $json_config = json_decode( $response_body );256257 // validate signature !!!258 $pdx_config = array (259 'pdx_api_version’=> $json_config->pdx_api_version,260 ‘validation_token’ => $json_config->validation_token,261 ‘preview_token’ => $json_config->preview_token,262 ‘timestamp’ => $json_config->timestamp263 );264265 if (PDX_LOG_ENABLE)266 {267 $log = "Configuration: validation_token = " . $json_config->validation_token ."\n";268 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);269 }270271 // save configuration into option table272 update_option( PDX_CONFIG_OPTION_KEY, $pdx_config );273274 if (PDX_LOG_ENABLE)275 {276 $log = "Configuration set successfully\n";277 file_put_contents(PDX_LOG_FILE, $log, FILE_APPEND);278 }279 wa_pdx_send_response('Configuration set successfully’, true);280281}