summaryrefslogtreecommitdiffstats
path: root/debian/patches/38474.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/38474.patch')
-rw-r--r--debian/patches/38474.patch281
1 files changed, 281 insertions, 0 deletions
diff --git a/debian/patches/38474.patch b/debian/patches/38474.patch
new file mode 100644
index 0000000..e7bfee8
--- /dev/null
+++ b/debian/patches/38474.patch
@@ -0,0 +1,281 @@
+Description: Use hash for user activation key
+ Removes cleartext of the user activation key
+ CVE-2017-14990
+Author: timdxw
+Origin: upstream, https://core.trac.wordpress.org/ticket/38474
+Bug-Debian: https://bugs.debian.org/877629
+Reviewed-by: Craig Small <csmall@debian.org>
+Last-Update: 2023-08-10
+--- a/wp-activate.php
++++ b/wp-activate.php
+@@ -42,13 +42,15 @@
+ wp_safe_redirect( $redirect_url );
+ exit;
+ } else {
+- $result = wpmu_activate_signup( $key );
++ $signup_id = ! empty( $_GET['signup_id'] ) ? $_GET['signup_id'] : $_POST['signup_id'];
++ $result = wpmu_activate_signup( $key, $signup_id );
+ }
+ }
+
+ if ( null === $result && isset( $_COOKIE[ $activate_cookie ] ) ) {
+ $key = $_COOKIE[ $activate_cookie ];
+- $result = wpmu_activate_signup( $key );
++ $signup_id = ! empty( $_GET['signup_id'] ) ? $_GET['signup_id'] : $_POST['signup_id'];
++ $result = wpmu_activate_signup( $key, $signup_id );
+ setcookie( $activate_cookie, ' ', time() - YEAR_IN_SECONDS, $activate_path, COOKIE_DOMAIN, is_ssl(), true );
+ }
+
+@@ -133,6 +135,10 @@
+ <label for="key"><?php _e( 'Activation Key:' ); ?></label>
+ <br /><input type="text" name="key" id="key" value="" size="50" autofocus="autofocus" />
+ </p>
++ <p>
++ <label for="key"><?php _e( 'Signup ID:' ) ?></label>
++ <br /><input type="number" name="signup_id" id="signup_id" value="" size="50" />
++ </p>
+ <p class="submit">
+ <input id="submit" type="submit" name="Submit" class="submit" value="<?php esc_attr_e( 'Activate' ); ?>" />
+ </p>
+--- a/wp-admin/user-new.php
++++ b/wp-admin/user-new.php
+@@ -227,8 +227,8 @@
+ )
+ );
+ if ( isset( $_POST['noconfirmation'] ) && current_user_can( 'manage_network_users' ) ) {
+- $key = $wpdb->get_var( $wpdb->prepare( "SELECT activation_key FROM {$wpdb->signups} WHERE user_login = %s AND user_email = %s", $new_user_login, $new_user_email ) );
+- $new_user = wpmu_activate_signup( $key );
++ $row = $wpdb->get_row( $wpdb->prepare( "SELECT activation_key, signup_id FROM {$wpdb->signups} WHERE user_login = %s AND user_email = %s", $new_user_login, $new_user_email ) );
++ $new_user = wpmu_activate_signup( $row['activation_key'], $row['signup_id'] );
+ if ( is_wp_error( $new_user ) ) {
+ $redirect = add_query_arg( array( 'update' => 'addnoconfirmation' ), 'user-new.php' );
+ } elseif ( ! is_user_member_of_blog( $new_user['user_id'] ) ) {
+--- a/wp-includes/ms-default-filters.php
++++ b/wp-includes/ms-default-filters.php
+@@ -26,7 +26,7 @@
+ add_action( 'wpmu_new_user', 'newuser_notify_siteadmin' );
+ add_action( 'wpmu_activate_user', 'add_new_user_to_blog', 10, 3 );
+ add_action( 'wpmu_activate_user', 'wpmu_welcome_user_notification', 10, 3 );
+-add_action( 'after_signup_user', 'wpmu_signup_user_notification', 10, 4 );
++add_action( 'after_signup_user', 'wpmu_signup_user_notification', 10, 5 );
+ add_action( 'network_site_new_created_user', 'wp_send_new_user_notifications' );
+ add_action( 'network_site_users_created_user', 'wp_send_new_user_notifications' );
+ add_action( 'network_user_new_created_user', 'wp_send_new_user_notifications' );
+@@ -39,7 +39,7 @@
+ // Blogs.
+ add_filter( 'wpmu_validate_blog_signup', 'signup_nonce_check' );
+ add_action( 'wpmu_activate_blog', 'wpmu_welcome_notification', 10, 5 );
+-add_action( 'after_signup_site', 'wpmu_signup_blog_notification', 10, 7 );
++add_action( 'after_signup_site', 'wpmu_signup_blog_notification', 10, 8 );
+ add_filter( 'wp_normalize_site_data', 'wp_normalize_site_data', 10, 1 );
+ add_action( 'wp_validate_site_data', 'wp_validate_site_data', 10, 3 );
+ add_action( 'wp_insert_site', 'wp_maybe_update_network_site_counts_on_update', 10, 1 );
+--- a/wp-includes/ms-functions.php
++++ b/wp-includes/ms-functions.php
+@@ -783,10 +783,17 @@
+ * @param array $meta Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
+ */
+ function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = array() ) {
+- global $wpdb;
++ global $wpdb, $wp_hasher;
+
+ $key = substr( md5( time() . wp_rand() . $domain ), 0, 16 );
+
++ if ( empty( $wp_hasher ) ) {
++ require_once ABSPATH . WPINC . '/class-phpass.php';
++ $wp_hasher = new PasswordHash( 8, true );
++ }
++
++ $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
++
+ /**
+ * Filters the metadata for a site signup.
+ *
+@@ -801,8 +808,9 @@
+ * @param string $user The user's requested login name.
+ * @param string $user_email The user's email address.
+ * @param string $key The user's activation key.
++ * @param string $hashed The user's hashed activation key.
+ */
+- $meta = apply_filters( 'signup_site_meta', $meta, $domain, $path, $title, $user, $user_email, $key );
++ $meta = apply_filters( 'signup_site_meta', $meta, $domain, $path, $title, $user, $user_email, $key, $hashed );
+
+ $wpdb->insert(
+ $wpdb->signups,
+@@ -813,7 +821,7 @@
+ 'user_login' => $user,
+ 'user_email' => $user_email,
+ 'registered' => current_time( 'mysql', true ),
+- 'activation_key' => $key,
++ 'activation_key' => $hashed,
+ 'meta' => serialize( $meta ),
+ )
+ );
+@@ -830,8 +838,10 @@
+ * @param string $user_email The user's email address.
+ * @param string $key The user's activation key.
+ * @param array $meta Signup meta data. By default, contains the requested privacy setting and lang_id.
++ * @param int $signup_id Signup ID.
++ * @param string $hashed The user's hashed activation key.
+ */
+- do_action( 'after_signup_site', $domain, $path, $title, $user, $user_email, $key, $meta );
++ do_action( 'after_signup_site', $domain, $path, $title, $user, $user_email, $key, $meta, $wpdb->insert_id, $hashed );
+ }
+
+ /**
+@@ -849,13 +859,20 @@
+ * @param array $meta Optional. Signup meta data. Default empty array.
+ */
+ function wpmu_signup_user( $user, $user_email, $meta = array() ) {
+- global $wpdb;
++ global $wpdb, $wp_hasher;
+
+ // Format data.
+ $user = preg_replace( '/\s+/', '', sanitize_user( $user, true ) );
+ $user_email = sanitize_email( $user_email );
+ $key = substr( md5( time() . wp_rand() . $user_email ), 0, 16 );
+
++ if ( empty( $wp_hasher ) ) {
++ require_once ABSPATH . WPINC . '/class-phpass.php';
++ $wp_hasher = new PasswordHash( 8, true );
++ }
++
++ $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
++
+ /**
+ * Filters the metadata for a user signup.
+ *
+@@ -867,8 +884,9 @@
+ * @param string $user The user's requested login name.
+ * @param string $user_email The user's email address.
+ * @param string $key The user's activation key.
++ * @param string $hashed The user's hashed activation key.
+ */
+- $meta = apply_filters( 'signup_user_meta', $meta, $user, $user_email, $key );
++ $meta = apply_filters( 'signup_user_meta', $meta, $user, $user_email, $key, $hashed );
+
+ $wpdb->insert(
+ $wpdb->signups,
+@@ -879,7 +897,7 @@
+ 'user_login' => $user,
+ 'user_email' => $user_email,
+ 'registered' => current_time( 'mysql', true ),
+- 'activation_key' => $key,
++ 'activation_key' => $hashed,
+ 'meta' => serialize( $meta ),
+ )
+ );
+@@ -893,8 +911,10 @@
+ * @param string $user_email The user's email address.
+ * @param string $key The user's activation key.
+ * @param array $meta Signup meta data. Default empty array.
++ * @param int $signup_id Signup ID.
++ * @param string $hashed The user's hashed activation key.
+ */
+- do_action( 'after_signup_user', $user, $user_email, $key, $meta );
++ do_action( 'after_signup_user', $user, $user_email, $key, $meta, $wpdb->insert_id, $hashed );
+ }
+
+ /**
+@@ -920,9 +940,10 @@
+ * @param string $user_email The user's email address.
+ * @param string $key The activation key created in wpmu_signup_blog().
+ * @param array $meta Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
++ * @param int $signup_id Signup ID.
+ * @return bool
+ */
+-function wpmu_signup_blog_notification( $domain, $path, $title, $user_login, $user_email, $key, $meta = array() ) {
++function wpmu_signup_blog_notification( $domain, $path, $title, $user_login, $user_email, $key, $meta = array(), $signup_id ) {
+ /**
+ * Filters whether to bypass the new site email notification.
+ *
+@@ -942,9 +963,9 @@
+
+ // Send email with activation link.
+ if ( ! is_subdomain_install() || get_current_network_id() != 1 ) {
+- $activate_url = network_site_url( "wp-activate.php?key=$key" );
++ $activate_url = network_site_url( "wp-activate.php?key=$key&signup_id=$signup_id" );
+ } else {
+- $activate_url = "http://{$domain}{$path}wp-activate.php?key=$key"; // @todo Use *_url() API.
++ $activate_url = "http://{$domain}{$path}wp-activate.php?key=$key&signup_id=$signup_id"; // @todo use *_url() API
+ }
+
+ $activate_url = esc_url( $activate_url );
+@@ -1055,9 +1076,10 @@
+ * @param string $user_email The user's email address.
+ * @param string $key The activation key created in wpmu_signup_user()
+ * @param array $meta Optional. Signup meta data. Default empty array.
++ * @param int $signup_id Signup ID.
+ * @return bool
+ */
+-function wpmu_signup_user_notification( $user_login, $user_email, $key, $meta = array() ) {
++function wpmu_signup_user_notification( $user_login, $user_email, $key, $meta = array(), $signup_id ) {
+ /**
+ * Filters whether to bypass the email notification for new user sign-up.
+ *
+@@ -1107,7 +1129,7 @@
+ $key,
+ $meta
+ ),
+- site_url( "wp-activate.php?key=$key" )
++ site_url( "wp-activate.php?key=$key&signup_id=$signup_id" )
+ );
+
+ $subject = sprintf(
+@@ -1157,17 +1179,53 @@
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $key The activation key provided to the user.
++ * @param int $signup_id The Signup ID.
+ * @return array|WP_Error An array containing information about the activated user and/or blog.
+ */
+-function wpmu_activate_signup( $key ) {
+- global $wpdb;
++function wpmu_activate_signup( $key, $signup_id ) {
++ global $wpdb, $wp_hasher;
+
+- $signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE activation_key = %s", $key ) );
++ $signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE activation_key = %s OR signup_id = %d", $key, $signup_id ) );
+
+ if ( empty( $signup ) ) {
+ return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
+ }
+
++ // If the key requested matches the actual key in the database, it's a legacy one.
++ if ( $key === $signup->activation_key ) {
++ return new WP_Error( 'expired_key', __( 'Invalid key' ) );
++ }
++
++ // The format of the new keys is <timestamp>:<hashed_key>.
++ if ( false === strpos( $signup->activation_key, ':' ) ) {
++ return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
++ }
++
++ if ( empty( $wp_hasher ) ) {
++ require_once ABSPATH . WPINC . '/class-phpass.php';
++ $wp_hasher = new PasswordHash( 8, true );
++ }
++
++ list( $pass_request_time, $signup_key ) = explode( ':', $signup->activation_key, 2 );
++
++ if ( ! $wp_hasher->CheckPassword( $key, $signup_key ) ) {
++ return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
++ }
++
++ /**
++ * Filters the expiration time of signup activation keys.
++ *
++ * @since 5.0
++ *
++ * @param int $expiration_duration The expiration time in seconds.
++ */
++ $expiration_duration = apply_filters( 'activate_signup_expiration', DAY_IN_SECONDS );
++ $expiration_time = $pass_request_time + $expiration_duration;
++
++ if ( time() > $expiration_time ) {
++ return new WP_Error( 'expired_key', __( 'Invalid key' ) );
++ }
++
+ if ( $signup->active ) {
+ if ( empty( $signup->domain ) ) {
+ return new WP_Error( 'already_active', __( 'The user is already active.' ), $signup );