| @@ -9,9 +9,9 @@ | ||
| 9 | 9 | |
| 10 | 10 | /** |
| 11 | 11 | * Implementation of phpBB v3 Converter. |
| 12 | 12 | * |
| 13 | - * @since 2.3.0 bbPress (r4689) | |
| 13 | + * @since 2.2.0 bbPress (r4101) | |
| 14 | 14 | * |
| 15 | 15 | * @link Codex Docs https://codex.bbpress.org/import-forums/phpbb |
| 16 | 16 | */ |
| 17 | 17 | class phpBB extends BBP_Converter_Base { |
| @@ -719,10 +719,10 @@ | ||
| 719 | 719 | * as one value. |
| 720 | 720 | */ |
| 721 | 721 | public function callback_savepass( $field, $row ) { |
| 722 | 722 | return array( |
| 723 | - 'hash' => $field, | |
| 724 | - 'salt' => $row['user_form_salt'] | |
| 723 | + 'hash' => wp_slash( (string) $field ), | |
| 724 | + 'salt' => isset( $row['user_form_salt'] ) ? wp_slash( (string) $row['user_form_salt'] ) : '' | |
| 725 | 725 | ); |
| 726 | 726 | } |
| 727 | 727 | |
| 728 | 728 | /** |
| @@ -738,16 +738,26 @@ | ||
| 738 | 738 | */ |
| 739 | 739 | public function authenticate_pass( $password, $serialized_pass ) { |
| 740 | 740 | |
| 741 | 741 | // Unserialize the password, with safeguards |
| 742 | - $pass_array = unserialize( | |
| 743 | - $serialized_pass, | |
| 744 | - array( | |
| 745 | - 'allowed_classes' => false, | |
| 746 | - 'max_depth' => 1 | |
| 747 | - ) | |
| 748 | - ); | |
| 742 | + $pass_array = $this->unserialize_pass( $serialized_pass ); | |
| 749 | 743 | |
| 744 | + // Bail if the password hash is invalid | |
| 745 | + if ( ! is_array( $pass_array ) || empty( $pass_array['hash'] ) || ! is_string( $pass_array['hash'] ) ) { | |
| 746 | + return false; | |
| 747 | + } | |
| 748 | + | |
| 749 | + // Modern phpBB hashes use PHP's password hashing API | |
| 750 | + if ( ( strpos( $pass_array['hash'], '$2' ) === 0 ) || ( strpos( $pass_array['hash'], '$argon2' ) === 0 ) ) { | |
| 751 | + return password_verify( $password, $pass_array['hash'] ); | |
| 752 | + } | |
| 753 | + | |
| 754 | + // phpBB can wrap a legacy phpass hash in bcrypt | |
| 755 | + if ( preg_match( '#^\$([HP])\\\\(2[ay])\$([./0-9A-Za-z]{9})\$([0-9]{2})\\\\([./0-9A-Za-z]{22})\$([./0-9A-Za-z]{31})$#D', $pass_array['hash'], $matches ) ) { | |
| 756 | + return $this->authenticate_combined_pass( $password, $matches ) | |
| 757 | + || $this->authenticate_combined_pass( md5( $password ), $matches ); | |
| 758 | + } | |
| 759 | + | |
| 750 | 760 | // Encrypted |
| 751 | 761 | if ( strlen( $pass_array['hash'] ) === 34 ) { |
| 752 | 762 | |
| 753 | 763 | // ASCII |
| @@ -767,8 +777,23 @@ | ||
| 767 | 777 | ); |
| 768 | 778 | } |
| 769 | 779 | |
| 770 | 780 | /** |
| 781 | + * Check a phpBB combined phpass and bcrypt password hash. | |
| 782 | + * | |
| 783 | + * @param string $password The password in plain text. | |
| 784 | + * @param array $matches Parsed components of the combined hash. | |
| 785 | + * @return bool True if the password is correct, false if not. | |
| 786 | + */ | |
| 787 | + private function authenticate_combined_pass( $password, $matches ) { | |
| 788 | + $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; | |
| 789 | + $phpass_hash = $this->_hash_crypt_private( $password, '$' . $matches[1] . '$' . $matches[3], $itoa64 ); | |
| 790 | + $bcrypt_hash = '$' . $matches[2] . '$' . $matches[4] . '$' . $matches[5] . $matches[6]; | |
| 791 | + | |
| 792 | + return password_verify( substr( $phpass_hash, 12 ), $bcrypt_hash ); | |
| 793 | + } | |
| 794 | + | |
| 795 | + /** | |
| 771 | 796 | * The crypt function/replacement |
| 772 | 797 | */ |
| 773 | 798 | private function _hash_crypt_private( $password, $setting, &$itoa64 ) { |
| 774 | 799 | $output = '*'; |
| @@ -773,9 +798,9 @@ | ||
| 773 | 798 | private function _hash_crypt_private( $password, $setting, &$itoa64 ) { |
| 774 | 799 | $output = '*'; |
| 775 | 800 | |
| 776 | 801 | // Check for correct hash |
| 777 | - if ( substr( $setting, 0, 3 ) !== '$H$' ) { | |
| 802 | + if ( ! in_array( substr( $setting, 0, 3 ), array( '$H$', '$P$' ), true ) ) { | |
| 778 | 803 | return $output; |
| 779 | 804 | } |
| 780 | 805 | |
| 781 | 806 | $count_log2 = strpos( $itoa64, $setting[3] ); |