Headline
CVE-2015-10102: Security fix for open redirect vulnerability · wp-plugins/freshdesk-support@2aaecd4
A vulnerability, which was classified as critical, has been found in Freshdesk Plugin 1.7 on WordPress. Affected by this issue is some unknown functionality. The manipulation leads to open redirect. The attack may be launched remotely. Upgrading to version 1.8 is able to address this issue. The name of the patch is 2aaecd4e0c7c6c1dc4e6a593163d5f7aa0fa5d5b. It is recommended to upgrade the affected component. VDB-226118 is the identifier assigned to this vulnerability.
@@ -1,14 +1,14 @@ <?php /* @package Freshdesk Official @version 1.7 @version 1.8 */ /* Plugin Name: Freshdesk Official Plugin URI: Description: Freshdesk Official is a seamless way to add your helpdesk account to your website. Supports various useful functions. Author: hjohnpaul,sathishfreshdesk,balakumars,shreyasns Version: 1.7 Version: 1.8 Author URI: http://freshdesk.com/ */
@@ -20,6 +20,7 @@ #include freshdesk api class. define( 'FD_PLUGIN_URL’, plugin_dir_url( __FILE__ ) ); define( 'FD_PAGE_BASENAME’, ‘freshdesk-menu-handle’ ); define( 'DOMAIN_REGEX’, ‘/\bhttps?:\/\/([-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|])/i’ ); require_once( plugin_dir_path( __FILE__ ) . ‘freshdesk-plugin-api.php’ );
add_action( 'init’, ‘fd_login’ ); //Sso handler and comment action handler @@ -45,21 +46,41 @@ function fd_login_redirect( $url, $request, $user ) { if ( ! $fd_redirect_to ) { return $url; } $redirect_url = get_redirect_url( $fd_redirect_to );
// For handling Redirect to Freshdesk on login. if ( $_REQUEST[‘wp-submit’] == “Log In” && is_a( $user, ‘WP_User’ ) ) { if ( $_REQUEST[‘wp-submit’] == “Log In” && is_a( $user, ‘WP_User’ ) && $redirect_url ) { $freshdesk_options = get_option( ‘freshdesk_options’ );
$user_name = $user->data->display_name; $freshdesk_options = get_option( ‘freshdesk_options’ ); $secret = $freshdesk_options[‘freshdesk_sso_key’]; $data = $user_name.$user->data->user_email.time(); $hash_key = hash_hmac("md5", $data, $secret); $ssl_url = $fd_redirect_to."/login/sso?name=".urlencode($user->data->display_name)."&email=".urlencode($user->data->user_email)."×tamp=".time()."&hash=".urlencode($hash_key); $ssl_url = $redirect_url."/login/sso?name=".urlencode($user->data->display_name)."&email=".urlencode($user->data->user_email)."×tamp=".time()."&hash=".urlencode($hash_key); sleep(1); // holding a bit so that it falls within FD 30 mins bar. header("Location: ".$ssl_url); die(); } return $request; }
function get_redirect_url($host_url) { $freshdesk_options = get_option( ‘freshdesk_options’ );
//Stripping protocols from urls to match the host url correctly. $host_url = preg_replace( DOMAIN_REGEX, “$1", trim($host_url) ); $domains = split( “,", $freshdesk_options[‘freshdesk_cname’] ); array_push( $domains, $freshdesk_options[‘freshdesk_domain_url’] );
//Checking the host url against the provided helpdesk/portal url to avoid Open-redirect vulnerability foreach ( $domains as $domain ) { $domain = trim($domain); $url = preg_replace( DOMAIN_REGEX, “$1", $domain); if ( $url == $host_url ) { return $domain; } } } function freshdesk_plugin_menu() { add_menu_page( 'Freshdesk Settings’, 'Freshdesk’, 'manage_options’, 'freshdesk-menu-handle’, ‘freshdesk_settings_page’); add_action( 'admin_init’, ‘freshdesk_settings_init’ ); @@ -83,6 +104,8 @@ function freshdesk_settings_init() { add_settings_section( 'freshdesk_settings_section’, '’, '’, ‘freshdesk-menu-handle’ ); //Domain url. add_settings_field( 'freshdesk_domain_url’, __(‘Helpdesk URL’), ‘freshdesk_domain_callback’ ,’freshdesk-menu-handle’, ‘freshdesk_settings_section’ ); //Host url add_settings_field( ‘freshdesk_cname’, __(‘Portal URLs’), ‘freshdesk_cname_callback’ ,’freshdesk-menu-handle’, ‘freshdesk_settings_section’ );
//Freshdesk Api Key. add_settings_field( ‘freshdesk_api_key’, ‘API Key’, ‘freshdesk_api_callback’ , ‘freshdesk-menu-handle’, ‘freshdesk_settings_section’ ); @@ -102,6 +125,12 @@ function freshdesk_domain_callback() { echo ‘<div class="info-data fd_ui_element">Eg: https://yourcompany.freshdesk.com</div>’; }
function freshdesk_cname_callback() { $options = get_option( ‘freshdesk_options’ ); echo "<input class=’fd_ui_element’ id=’freshdesk_cname’ name=’freshdesk_options[freshdesk_cname]' size=’72’ type=’text’ value=’{$options[‘freshdesk_cname’]}’ />"; echo '<div class="info-data fd_ui_element">Eg: https://support.yourdomain.com,https://support2.yourdomain.com</div>’; }
function freshdesk_enable_sso_callback() { $options = get_option( ‘freshdesk_options’ ); echo '<tr><td colspan="2"><ul class="fd-form-table"><li><div><label><input class="fd_button” type="checkbox” name="freshdesk_options[freshdesk_enable_sso]" id="freshdesk_enable_sso” ‘.$options[‘freshdesk_enable_sso’].’ /><span class="fd_ui_element fd-bold">Enable SSO Login </span></label><div><div class="info-data fd_lmargin">Enabling this will let your users to login using their wordpress credentials</div></li>’; @@ -157,9 +186,31 @@ function validate_freshdesk_settings( $input ) { $freshdesk_options = get_option( ‘freshdesk_options’ ); $error = 0; $url=trim($input[‘freshdesk_domain_url’]); if ( ! preg_match("/\b(?:(?:https?):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i", $url ) ) { $url =’’; if ( $url && ! preg_match( DOMAIN_REGEX, $url ) ) { add_settings_error( 'freshdesk_domain_url’, // setting title 'fd_invalid_domain’, // error ID "$url is an invalid Helpdesk url", // error message ‘error’ // type of message ); $error=1; } $cnames = split( ",", trim($input[‘freshdesk_cname’] ) ); foreach ( $cnames as $cname ) { $cname = trim($cname); if ( ! preg_match( DOMAIN_REGEX, $cname ) && $cname ) { add_settings_error( 'freshdesk_cname’, // setting title 'fd_cname_invalid_domain’, // error ID "$cname is an invalid domain url", // error message ‘error’ // type of message ); $error=1; break; } } $cname = trim($input[‘freshdesk_cname’] );
$sso_secret = $input[‘freshdesk_sso_key’]; $api_key = $input[‘freshdesk_api_key’]; $enable_feedback = validate_checkbox( $input[‘freshdesk_enable_feedback’] ); @@ -169,7 +220,7 @@ function validate_freshdesk_settings( $input ) { add_settings_error( 'freshdesk_domain_url’, // setting title 'fd_domain_url_not_present’, // error ID 'Domain url cannot be blank’, // error message 'Helpdesk url cannot be blank’, // error message ‘error’ // type of message ); $error=1; @@ -198,7 +249,7 @@ function validate_freshdesk_settings( $input ) { if ( $error ) { return $freshdesk_options; } $settings = array( ‘freshdesk_domain_url’ => $url, ‘freshdesk_enable_sso’ => $enable_sso, ‘freshdesk_sso_key’ => $sso_secret, ‘freshdesk_api_key’ => $api_key, ‘freshdesk_enable_feedback’ => $enable_feedback ); $settings = array( ‘freshdesk_domain_url’ => $url, ‘freshdesk_cname’ => $cname, ‘freshdesk_enable_sso’ => $enable_sso, ‘freshdesk_sso_key’ => $sso_secret, ‘freshdesk_api_key’ => $api_key, ‘freshdesk_enable_feedback’ => $enable_feedback );
return $settings; } @@ -238,9 +289,14 @@ function freshdesk_comment_action( $actions, $comment ) { function fd_login() { global $pagenow, $display_name , $user_email; if ( ‘wp-login.php’ == $pagenow ){ $freshdesk_options = get_option( ‘freshdesk_options’ ); $domain = get_redirect_url($_REQUEST[‘host_url’]); error_log("Domain : $domain "); if( ! $domain ) { return; } if ( $_GET[‘action’] == ‘freshdesk-login’ ) { // NOTE: is_user_logged_in dont’t work during [wp-submit] => Log In $freshdesk_options = get_option( ‘freshdesk_options’ ); if( $freshdesk_options[‘freshdesk_enable_sso’] != ‘checked’ ){ return; } @@ -252,30 +308,21 @@ function fd_login() { $user_email = $current_user->user_email; $data = $user_name.$user_email.time(); $hash_key = hash_hmac( "md5", $data, $secret ); $url = freshdesk_sso_login_url( $user_name, $user_email ,$hash_key ); $url = freshdesk_sso_login_url( $domain, $user_name, $user_email ,$hash_key ); header( 'Location: '.$url ) ; die(); } else{ // if wordpress is not logged in. $domain = ( $_REQUEST[‘host_url’] ) ? get_domain_protocol()."://".$_REQUEST[‘host_url’] : $freshdesk_options[‘freshdesk_domain_url’]; // Redirect to the host url if host url option is present with the request.
if (isset($domain)){ header( "Location: " .wp_login_url()."?redirect_to=fd_redirect_to=".$domain ); die(); } } } if ( $_GET[‘action’] == ‘freshdesk-logout’ ) { $redirect_url = wp_login_url(); // Sometimes we get the http referer and some times don’t so to find if it is coming from Freshdesk we do a two condition check and if one is satisfied then Freshdesk is the referer. // Condition-1) Host url is a substring of http referer // Condition-2) Host url exists and the http_referer is empty because request from within wordpress seems to always have a referer. $condition_one = ( strpos($_SERVER[‘HTTP_REFERER’], $_REQUEST[‘host_url’]) !== FALSE ) ? TRUE : FALSE; $condition_two = ( $_REQUEST[‘host_url’] && empty( $_SERVER[‘HTTP_REFERER’] ) ); if ( $condition_one || $condition_two ) { $redirect_url = get_domain_protocol()."://".$_REQUEST[‘host_url’]; } wp_logout(); header( 'Location: '.$redirect_url ); header( 'Location: '.$domain ); die(); } } @@ -302,19 +349,8 @@ function freshdesk_handshake_secret() {
}
function get_domain_protocol() { $freshdesk_options= get_option( ‘freshdesk_options’ ); $domain_url = $freshdesk_options[‘freshdesk_domain_url’]; $temp_array = explode( ":", $domain_url ); $protocol = $temp_array[0]; return $protocol; }
function freshdesk_sso_login_url($user_name,$email,$hash_key){ $host_url = $_GET[‘host_url’]; $protocol = get_domain_protocol()."://"; $domain = (empty($host_url) === true) ? $domain_url : $host_url; // Take the domain_url if host_url is null. return $protocol.$domain."/login/sso?name=".urlencode($user_name)."&email=".urlencode($email)."×tamp=".time()."&hash=".urlencode($hash_key); function freshdesk_sso_login_url($domain, $user_name, $email, $hash_key){ return $domain."/login/sso?name=".urlencode($user_name)."&email=".urlencode($email)."×tamp=".time()."&hash=".urlencode($hash_key); }
//Ajax Action handler. Freshdesk Ticket creation handled here.