From 5113dc6350fec859f21f6471534b289261a573e4 Mon Sep 17 00:00:00 2001 From: Dianne Skoll Date: Fri, 15 Jan 2021 09:15:20 -0500 Subject: [PATCH 1/2] Always check password to avoid timing side channel attacks on login page This addresses CVE-2021-38562. --- lib/RT/Interface/Web.pm | 8 ++++++++ lib/RT/User.pm | 9 ++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm index 859ceacd408..9e18df4afae 100644 --- a/lib/RT/Interface/Web.pm +++ b/lib/RT/Interface/Web.pm @@ -842,10 +842,18 @@ sub AttemptPasswordAuthentication { my $user_obj = RT::CurrentUser->new(); $user_obj->Load( $ARGS->{user} ); + # Load the RT system user as well to avoid timing side channel + my $system_user = RT::CurrentUser->new(); + $system_user->Load(1); # User with ID 1 should always exist! + my $m = $HTML::Mason::Commands::m; my $remote_addr = RequestENV('REMOTE_ADDR'); unless ( $user_obj->id && $user_obj->IsPassword( $ARGS->{pass} ) ) { + if (!$user_obj->id) { + # Avoid timing side channel... always run IsPassword + $system_user->IsPassword( $ARGS->{pass} ); + } $RT::Logger->error("FAILED LOGIN for @{[$ARGS->{user}]} from $remote_addr"); $m->callback( %$ARGS, CallbackName => 'FailedLogin', CallbackPage => '/autohandler' ); return (0, HTML::Mason::Commands::loc('Your username or password is incorrect')); diff --git a/lib/RT/User.pm b/lib/RT/User.pm index a83b00ac6e2..5c794cb5cbe 100644 --- a/lib/RT/User.pm +++ b/lib/RT/User.pm @@ -1237,15 +1237,18 @@ sub IsPassword { } if ( $self->PrincipalObj->Disabled ) { + # Run the bcrypt generator to avoid timing side-channel attacks + RT::Util::constant_time_eq($self->_GeneratePassword_bcrypt($value), '0' x 64); $RT::Logger->info( "Disabled user " . $self->Name . " tried to log in" ); return (undef); } unless ($self->HasPassword) { - return(undef); - } - + # Run the bcrypt generator to avoid timing side-channel attacks + RT::Util::constant_time_eq($self->_GeneratePassword_bcrypt($value), '0' x 64); + return undef; + } my $stored = $self->__Value('Password'); if ($stored =~ /^!/) { # If it's a new-style (>= RT 4.0) password, it starts with a '!' From 70749bb66cb13dd70bd53340c371038a5f3ca57c Mon Sep 17 00:00:00 2001 From: sunnavy Date: Thu, 12 Aug 2021 05:03:16 +0800 Subject: [PATCH 2/2] Always check password to avoid timing side channel attacks in REST2 basic auth This addresses CVE-2021-38562. --- lib/RT/REST2/Middleware/Auth.pm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/RT/REST2/Middleware/Auth.pm b/lib/RT/REST2/Middleware/Auth.pm index cb047903853..4fdc7469c81 100644 --- a/lib/RT/REST2/Middleware/Auth.pm +++ b/lib/RT/REST2/Middleware/Auth.pm @@ -132,10 +132,19 @@ sub login_from_basicauth { my($user, $pass) = split /:/, (MIME::Base64::decode($1) || ":"), 2; my $cu = RT::CurrentUser->new; $cu->Load($user); + + # Load the RT system user as well to avoid timing side channel + my $system_user = RT::CurrentUser->new(); + $system_user->Load(1); # User with ID 1 should always exist! + if ($cu->id and $cu->IsPassword($pass)) { return $cu; } else { + if (!$cu->id) { + # Avoid timing side channel... always run IsPassword + $system_user->IsPassword($pass); + } RT->Logger->info("Failed login for $user"); return; }