Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed vulnerability within wp-sessions.php #433

Merged
merged 1 commit into from
Dec 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion give.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ private function setup_constants() {

// Plugin version
if ( ! defined( 'GIVE_VERSION' ) ) {
define( 'GIVE_VERSION', '1.3.2' );
define( 'GIVE_VERSION', '1.3.3' );
}

// Plugin Folder Path
Expand Down
41 changes: 27 additions & 14 deletions includes/libraries/class-wp-session.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
* Standardizes WordPress session data using database-backed options for storage.
* for storing user session information.
*
* @package WordPress
* @package WordPress
* @subpackage Session
* @since 3.7.0
* @since 3.7.0
*/

/**
Expand Down Expand Up @@ -66,17 +66,20 @@ public static function get_instance() {
* create a new session with that ID.
*
* @param $session_id
*
* @uses apply_filters Calls `wp_session_expiration` to determine how long until sessions expire.
*/
protected function __construct() {
if ( isset( $_COOKIE[WP_SESSION_COOKIE] ) ) {
$cookie = stripslashes( $_COOKIE[WP_SESSION_COOKIE] );
if ( isset( $_COOKIE[ WP_SESSION_COOKIE ] ) ) {
$cookie = stripslashes( $_COOKIE[ WP_SESSION_COOKIE ] );
$cookie_crumbs = explode( '||', $cookie );

$this->session_id = $cookie_crumbs[0];
$this->expires = $cookie_crumbs[1];
if ( $this->is_valid_md5( $cookie_crumbs[0] ) ) {
$this->session_id = $cookie_crumbs[0];
} else {
$this->regenerate_id( true );
}
$this->expires = $cookie_crumbs[1];
$this->exp_variant = $cookie_crumbs[2];

// Update the session expiration if we're past the variant time
if ( time() > $this->exp_variant ) {
$this->set_expiration();
Expand All @@ -87,9 +90,7 @@ protected function __construct() {
$this->session_id = $this->generate_id();
$this->set_expiration();
}

$this->read_data();

$this->set_cookie();

}
Expand All @@ -114,14 +115,14 @@ protected function __construct() {
*/
protected function set_expiration() {
$this->exp_variant = time() + (int) apply_filters( 'wp_session_expiration_variant', 24 * 60 );
$this->expires = time() + (int) apply_filters( 'wp_session_expiration', 30 * 60 );
$this->expires = time() + (int) apply_filters( 'wp_session_expiration', 30 * 60 );
}

/**
* Set the session cookie
*/
protected function set_cookie() {
@setcookie( WP_SESSION_COOKIE, $this->session_id . '||' . $this->expires . '||' . $this->exp_variant , $this->expires, COOKIEPATH, COOKIE_DOMAIN );
@setcookie( WP_SESSION_COOKIE, $this->session_id . '||' . $this->expires . '||' . $this->exp_variant, $this->expires, COOKIEPATH, COOKIE_DOMAIN );
}

/**
Expand All @@ -130,7 +131,7 @@ protected function set_cookie() {
* @return string
*/
protected function generate_id() {
require_once( ABSPATH . 'wp-includes/class-phpass.php');
require_once( ABSPATH . 'wp-includes/class-phpass.php' );
$hasher = new PasswordHash( 8, false );

return md5( $hasher->get_random_bytes( 32 ) );
Expand All @@ -149,6 +150,17 @@ protected function read_data() {
return $this->container;
}

/**
* Checks if is valid md5 string
*
* @param string $md5
*
* @return int
*/
protected function is_valid_md5( $md5 = '' ) {
return preg_match( '/^[a-f0-9]{32}$/', $md5 );
}

/**
* Write the data from the current session to the data storage system.
*/
Expand Down Expand Up @@ -188,6 +200,7 @@ public function json_in( $data ) {

if ( is_array( $array ) ) {
$this->container = $array;

return true;
}

Expand Down Expand Up @@ -215,7 +228,7 @@ public function regenerate_id( $delete_old = false ) {
* @return bool
*/
public function session_started() {
return !!self::$instance;
return ! ! self::$instance;
}

/**
Expand Down
18 changes: 10 additions & 8 deletions includes/libraries/wp-session.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
* Standardizes WordPress session data and uses either database transients or in-memory caching
* for storing user session information.
*
* @package WordPress
* @package WordPress
* @subpackage Session
* @since 3.7.0
* @since 3.7.0
*/

/**
Expand Down Expand Up @@ -78,6 +78,7 @@ function wp_session_start() {

return $wp_session->session_started();
}

add_action( 'plugins_loaded', 'wp_session_start' );

/**
Expand Down Expand Up @@ -113,6 +114,7 @@ function wp_session_write_close() {
$wp_session->write_data();
do_action( 'wp_session_commit' );
}

add_action( 'shutdown', 'wp_session_write_close' );

/**
Expand All @@ -132,21 +134,19 @@ function wp_session_cleanup() {
if ( ! defined( 'WP_INSTALLING' ) ) {
$expiration_keys = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE option_name LIKE '_wp_session_expires_%'" );

$now = current_time( 'timestamp' );
$now = current_time( 'timestamp' );
$expired_sessions = array();

foreach( $expiration_keys as $expiration ) {
foreach ( $expiration_keys as $expiration ) {
// If the session has expired
if ( $now > intval( $expiration->option_value ) ) {
// Get the session ID by parsing the option_name
$session_id = substr( $expiration->option_name, 20 );

if( (int) -1 === (int) $session_id ) {
if ( (int) -1 === (int) $session_id || ! preg_match( '/^[a-f0-9]{32}$/', $session_id ) ) {
continue;
}

$expired_sessions[] = $expiration->option_name;
$expired_sessions[] = "_wp_session_$session_id";
$expired_sessions[] = esc_sql( "_wp_session_$session_id" );
}
}

Expand All @@ -160,6 +160,7 @@ function wp_session_cleanup() {
// Allow other plugins to hook in to the garbage collection process.
do_action( 'wp_session_cleanup' );
}

add_action( 'wp_session_garbage_collection', 'wp_session_cleanup' );

/**
Expand All @@ -170,4 +171,5 @@ function wp_session_register_garbage_collection() {
wp_schedule_event( current_time( 'timestamp' ), 'twicedaily', 'wp_session_garbage_collection' );
}
}

add_action( 'wp', 'wp_session_register_garbage_collection' );
3 changes: 3 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ We also really like WooCommerce. It's hands-down the most robust eCommerce platf

== Changelog ==

= 1.3.3 =
* Fixed security vulnerability due to WP session IDs

= 1.3.2 =
* New: German/Deutsch translation for Give provided by Konrad - Thanks! :) - https://github.com/WordImpress/Give/issues/383
* New: Polish/Polski translation provided by Emilia - Thanks! :) - https://github.com/WordImpress/Give/issues/418
Expand Down