diff --git a/includes/admin/core/class-admin-builder.php b/includes/admin/core/class-admin-builder.php index 0cd129ac..b655d341 100644 --- a/includes/admin/core/class-admin-builder.php +++ b/includes/admin/core/class-admin-builder.php @@ -1220,6 +1220,10 @@ if ( ! class_exists( 'um\admin\core\Admin_Builder' ) ) { $arr_options['function_exists'] = function_exists( $um_callback_func ); } + if ( in_array( $um_callback_func, UM()->fields()->dropdown_options_source_blacklist(), true ) ) { + wp_send_json_error( __( 'This is not possible for security reasons. Don\'t use internal PHP functions.', 'ultimate-member' ) ); + } + $arr_options['data'] = array(); if ( function_exists( $um_callback_func ) ) { $arr_options['data'] = call_user_func( $um_callback_func ); diff --git a/includes/core/class-fields.php b/includes/core/class-fields.php index f31a17f8..0ff3768f 100644 --- a/includes/core/class-fields.php +++ b/includes/core/class-fields.php @@ -146,17 +146,19 @@ if ( ! class_exists( 'um\core\Fields' ) ) { if ( array_key_exists( 'custom_dropdown_options_source', $args ) ) { if ( function_exists( wp_unslash( $args['custom_dropdown_options_source'] ) ) ) { - $allowed_callbacks = UM()->options()->get( 'allowed_choice_callbacks' ); - if ( ! empty( $allowed_callbacks ) ) { - $allowed_callbacks = array_map( 'rtrim', explode( "\n", $allowed_callbacks ) ); - $allowed_callbacks[] = $args['custom_dropdown_options_source']; - } else { - $allowed_callbacks = array( $args['custom_dropdown_options_source'] ); - } - $allowed_callbacks = array_unique( $allowed_callbacks ); - $allowed_callbacks = implode( "\r\n", $allowed_callbacks ); + if ( ! in_array( $args['custom_dropdown_options_source'], UM()->fields()->dropdown_options_source_blacklist(), true ) ) { + $allowed_callbacks = UM()->options()->get( 'allowed_choice_callbacks' ); + if ( ! empty( $allowed_callbacks ) ) { + $allowed_callbacks = array_map( 'rtrim', explode( "\n", $allowed_callbacks ) ); + $allowed_callbacks[] = $args['custom_dropdown_options_source']; + } else { + $allowed_callbacks = array( $args['custom_dropdown_options_source'] ); + } + $allowed_callbacks = array_unique( $allowed_callbacks ); + $allowed_callbacks = implode( "\r\n", $allowed_callbacks ); - UM()->options()->update( 'allowed_choice_callbacks', $allowed_callbacks ); + UM()->options()->update( 'allowed_choice_callbacks', $allowed_callbacks ); + } } } @@ -201,19 +203,21 @@ if ( ! class_exists( 'um\core\Fields' ) ) { if ( array_key_exists( 'custom_dropdown_options_source', $args ) ) { if ( function_exists( wp_unslash( $args['custom_dropdown_options_source'] ) ) ) { - $allowed_callbacks = UM()->options()->get( 'allowed_choice_callbacks' ); - if ( ! empty( $allowed_callbacks ) ) { - $allowed_callbacks = array_map( 'rtrim', explode( "\n", $allowed_callbacks ) ); - $allowed_callbacks[] = $args['custom_dropdown_options_source']; - } else { - $allowed_callbacks = array( $args['custom_dropdown_options_source'] ); + if ( ! in_array( $args['custom_dropdown_options_source'], UM()->fields()->dropdown_options_source_blacklist(), true ) ) { + $allowed_callbacks = UM()->options()->get( 'allowed_choice_callbacks' ); + if ( ! empty( $allowed_callbacks ) ) { + $allowed_callbacks = array_map( 'rtrim', explode( "\n", $allowed_callbacks ) ); + $allowed_callbacks[] = $args['custom_dropdown_options_source']; + } else { + $allowed_callbacks = array( $args['custom_dropdown_options_source'] ); + } + $allowed_callbacks = array_unique( $allowed_callbacks ); + $allowed_callbacks = implode( "\r\n", $allowed_callbacks ); + + UM()->options()->update( 'allowed_choice_callbacks', $allowed_callbacks ); + + $args['custom_dropdown_options_source'] = wp_unslash( $args['custom_dropdown_options_source'] ); } - $allowed_callbacks = array_unique( $allowed_callbacks ); - $allowed_callbacks = implode( "\r\n", $allowed_callbacks ); - - UM()->options()->update( 'allowed_choice_callbacks', $allowed_callbacks ); - - $args['custom_dropdown_options_source'] = wp_unslash( $args['custom_dropdown_options_source'] ); } } @@ -1291,6 +1295,17 @@ if ( ! class_exists( 'um\core\Fields' ) ) { return ''; } + public function dropdown_options_source_blacklist() { + $blacklist = array( + 'phpinfo', + 'exec', + 'passthru', + 'shell_exec', + 'system', + ); + $blacklist = apply_filters( 'um_dropdown_options_source_blacklist', $blacklist ); + return $blacklist; + } /** * Gets selected option value from a callback function @@ -1305,6 +1320,10 @@ if ( ! class_exists( 'um\core\Fields' ) ) { if ( in_array( $type, array( 'select', 'multiselect' ) ) && ! empty( $data['custom_dropdown_options_source'] ) ) { + if ( in_array( $data['custom_dropdown_options_source'], $this->dropdown_options_source_blacklist(), true ) ) { + return $value; + } + $has_custom_source = apply_filters( "um_has_dropdown_options_source__{$data['metakey']}", false ); if ( $has_custom_source ) { @@ -1372,6 +1391,10 @@ if ( ! class_exists( 'um\core\Fields' ) ) { if ( in_array( $type, array( 'select', 'multiselect' ) ) && ! empty( $data['custom_dropdown_options_source'] ) ) { + if ( in_array( $data['custom_dropdown_options_source'], $this->dropdown_options_source_blacklist(), true ) ) { + return $arr_options; + } + if ( function_exists( $data['custom_dropdown_options_source'] ) ) { if ( isset( $data['parent_dropdown_relationship'] ) ) { $arr_options = call_user_func( $data['custom_dropdown_options_source'], $data['parent_dropdown_relationship'] ); @@ -3037,7 +3060,9 @@ if ( ! class_exists( 'um\core\Fields' ) ) { if ( ! empty( $data['custom_dropdown_options_source'] ) && $has_parent_option && function_exists( $data['custom_dropdown_options_source'] ) && um_user( $data['parent_dropdown_relationship'] ) ) { - $options = call_user_func( $data['custom_dropdown_options_source'], $data['parent_dropdown_relationship'] ); + if ( ! in_array( $data['custom_dropdown_options_source'], $this->dropdown_options_source_blacklist(), true ) ) { + $options = call_user_func( $data['custom_dropdown_options_source'], $data['parent_dropdown_relationship'] ); + } $disabled_by_parent_option = ''; if ( um_user( $form_key ) ) { @@ -3053,10 +3078,11 @@ if ( ! class_exists( 'um\core\Fields' ) ) { // Child dropdown if ( $has_parent_option ) { - if ( ! empty( $data['custom_dropdown_options_source'] ) && $has_parent_option && function_exists( $data['custom_dropdown_options_source'] ) && isset( UM()->form()->post_form[ $form_key ] ) ) { - $options = call_user_func( $data['custom_dropdown_options_source'], $data['parent_dropdown_relationship'] ); + if ( ! in_array( $data['custom_dropdown_options_source'], $this->dropdown_options_source_blacklist(), true ) ) { + $options = call_user_func( $data['custom_dropdown_options_source'], $data['parent_dropdown_relationship'] ); + } } } diff --git a/includes/core/class-form.php b/includes/core/class-form.php index 3b919ede..6a529bbe 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -148,6 +148,13 @@ if ( ! class_exists( 'um\core\Form' ) ) { wp_send_json( $arr_options ); } + if ( in_array( $ajax_source_func, UM()->fields()->dropdown_options_source_blacklist(), true ) ) { + $arr_options['status'] = 'error'; + $arr_options['message'] = __( 'This is not possible for security reasons.', 'ultimate-member' ); + + wp_send_json( $arr_options ); + } + if ( isset( $_POST['form_id'] ) ) { UM()->fields()->set_id = absint( $_POST['form_id'] ); } diff --git a/includes/core/class-validation.php b/includes/core/class-validation.php index f318877b..6ef84de6 100644 --- a/includes/core/class-validation.php +++ b/includes/core/class-validation.php @@ -95,8 +95,10 @@ if ( ! class_exists( 'um\core\Validation' ) ) { isset( $fields[ $key ]['custom_dropdown_options_source'] ) && ! empty( $fields[ $key ]['custom_dropdown_options_source'] ) && function_exists( $fields[ $key ]['custom_dropdown_options_source'] ) ) { - $arr_options = call_user_func( $fields[ $key ]['custom_dropdown_options_source'] ); - $fields[ $key ]['options'] = array_keys( $arr_options ); + if ( ! in_array( $fields[ $key ]['custom_dropdown_options_source'], UM()->fields()->dropdown_options_source_blacklist(), true ) ) { + $arr_options = call_user_func( $fields[ $key ]['custom_dropdown_options_source'] ); + $fields[ $key ]['options'] = array_keys( $arr_options ); + } } // Unset changed value that doesn't match the option list diff --git a/includes/core/um-actions-profile.php b/includes/core/um-actions-profile.php index 12d06e13..49f01f7d 100644 --- a/includes/core/um-actions-profile.php +++ b/includes/core/um-actions-profile.php @@ -294,10 +294,12 @@ function um_user_edit_profile( $args ) { if ( isset( $array['options'] ) && in_array( $array['type'], array( 'select', 'multiselect' ) ) ) { $options = array(); - if ( ! empty( $array['custom_dropdown_options_source'] ) && function_exists( $array['custom_dropdown_options_source'] ) && ! $has_custom_source ) { - $callback_result = call_user_func( $array['custom_dropdown_options_source'], $array['options'] ); - if ( is_array( $callback_result ) ) { - $options = array_keys( $callback_result ); + if ( ! empty( $array['custom_dropdown_options_source'] ) && function_exists( $array['custom_dropdown_options_source'] ) && ! $has_custom_source ) { + if ( ! in_array( $array['custom_dropdown_options_source'], UM()->fields()->dropdown_options_source_blacklist(), true ) ) { + $callback_result = call_user_func( $array['custom_dropdown_options_source'], $array['options'] ); + if ( is_array( $callback_result ) ) { + $options = array_keys( $callback_result ); + } } } diff --git a/includes/core/um-filters-fields.php b/includes/core/um-filters-fields.php index 7bde5b92..d431a434 100644 --- a/includes/core/um-filters-fields.php +++ b/includes/core/um-filters-fields.php @@ -694,6 +694,9 @@ add_filter( 'um_field_non_utf8_value', 'um_field_non_utf8_value' ); */ function um_select_dropdown_dynamic_callback_options( $options, $data ) { if ( ! empty( $data['custom_dropdown_options_source'] ) && function_exists( $data['custom_dropdown_options_source'] ) ) { + if ( in_array( $data['custom_dropdown_options_source'], UM()->fields()->dropdown_options_source_blacklist(), true ) ) { + return $options; + } $options = call_user_func( $data['custom_dropdown_options_source'] ); }