Bug#928944: CVE-2019-12046: lemonldap-ng tokens allows anonymous session when stored in session DB

Xavier yadd at debian.org
Mon May 13 20:05:51 BST 2019


Package: liblemonldap-ng-portal-perl
Severity: grave
Tags: security upstream patch
Justification: user security hole
Forwarded: https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues/1742
Found: 1.9.7-3

Hi all,

during an internal audit, one of lemonldap-ngi's developers discovered an
attack vector. It opens 3 security issues:
 - [high] for 2.0.0 ≤ version < 2.0.4: when CSRF tokens are
   enabled (default) and tokens are stored in session DB (not default,
   used with poor load-balancers), the token can be used to open an
   anonymous short-life session (2mn). It allows one to access to all
   aplications without additional rules
 - [high] for every versions < 2.0.4 or 1.9.19 when SAML/OIDC tokens are
   stored in sessions DB (not default), tokens can be used to have an
   anonymous session
 - [low] for every versions < 2.0.4 or 1.9.19: when self-registration
   is allowed, mail token can be used to have an anonymous session.

Attachements:
 - lemonldap-ng_2.0.2+ds-6.debdiff: fix for stretch
 - lemonldap-ng_2.0.2+ds-7.patch: patch for Buster. It includes 3 new
   upstream tests to prove that vulnerabilities are fixed
 - llng-1742-test.sh: a small tool that can be used to test an existing
   2.0.x installation

This issue also affects Ubuntu-19.04 which includes lemonldap-ng_2.0.2+ds-6.

Cheers,
Xavier

-------------- next part --------------
A non-text attachment was scrubbed...
Name: lemonldap-ng_2.0.2+ds-7.patch
Type: text/x-patch
Size: 16302 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-perl-maintainers/attachments/20190513/d05d20d7/attachment-0002.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: llng-1742-test.sh
Type: application/x-shellscript
Size: 648 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-perl-maintainers/attachments/20190513/d05d20d7/attachment-0003.bin>
-------------- next part --------------
diff --git a/debian/changelog b/debian/changelog
index 08d4a00bc..63ba5aa3f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+lemonldap-ng (1.9.7-3+deb9u1) unstable; urgency=medium
+
+  * Add patch to fix token security (Closes: CVE-2019-12046)
+
+ -- Xavier Guimard <yadd at debian.org>  Mon, 13 May 2019 18:51:54 +0200
+
 lemonldap-ng (1.9.7-3) unstable; urgency=medium
 
   * Remove unnecessary version dependency for lsb-base
diff --git a/debian/patches/CVE-2019-12046.patch b/debian/patches/CVE-2019-12046.patch
new file mode 100644
index 000000000..53662e3e4
--- /dev/null
+++ b/debian/patches/CVE-2019-12046.patch
@@ -0,0 +1,178 @@
+Description: Fix for CVE-2019-12046
+Author: Xavier Guimard <x.guimard at free.fr>
+Origin: upstream, https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues/1743
+Bug: https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues/1743
+Forwarded: not-needed
+Last-Update: 2019-05-13
+
+--- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session.pm
++++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session.pm
+@@ -109,6 +109,12 @@
+ 
+     # Load session data into object
+     if ($data) {
++        if ( $self->kind ) {
++            unless ( $data->{_session_kind} eq $self->kind ) {
++                $self->error("Session kind mistmatch");
++                return undef;
++            }
++        }
+         $self->_save_data($data);
+         $self->kind( $data->{_session_kind} );
+         $self->id( $data->{_session_id} );
+--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/MailReset.pm
++++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/MailReset.pm
+@@ -115,7 +115,8 @@
+             'debug' );
+ 
+         # Get the corresponding session
+-        my $mailSession = $self->getApacheSession( $self->{mail_token} );
++        my $mailSession =
++          $self->getApacheSession( $self->{mail_token}, 1, undef, "mail" );
+ 
+         if ($mailSession) {
+             $self->{mail} = $mailSession->data->{user};
+@@ -215,7 +216,7 @@
+       if ( $self->{mail_token} or $self->getMailSession( $self->{mail} ) );
+ 
+     # Create a new session
+-    my $mailSession = $self->getApacheSession();
++    my $mailSession = $self->getApacheSession( undef, 1, undef, "mail" );
+ 
+     # Set _utime for session autoremove
+     # Use default session timeout and mail session timeout to compute it
+@@ -259,16 +260,15 @@
+     # Skip this step if user clicked on the confirmation link
+     return PE_OK if $self->{mail_token};
+ 
+-    # Check if confirmation mail has already been sent
+     my $mail_session = $self->getMailSession( $self->{mail} );
+-    $self->{mail_already_sent} = ( $mail_session and !$self->{id} ) ? 1 : 0;
+ 
+     # Read mail session to get creation and expiration dates
+     $self->{id} = $mail_session unless $self->{id};
+ 
+     $self->lmLog( "Mail session found: $mail_session", 'debug' );
+ 
+-    my $mailSession = $self->getApacheSession( $mail_session, 1 );
++    my $mailSession =
++      $self->getApacheSession( $mail_session, 1, undef, "mail" );
+     $self->{mailSessionTimeoutTimestamp} =
+       $mailSession->data->{mailSessionTimeoutTimestamp};
+     $self->{mailSessionStartTimestamp} =
+@@ -342,6 +342,9 @@
+     return PE_MAILERROR
+       unless $self->send_mail( $self->{mailAddress}, $subject, $body, $html );
+ 
++    # Save status
++    $mailSession->update( { "mail_already_sent" => 1 } );
++
+     PE_MAILCONFIRMOK;
+ }
+ 
+@@ -384,7 +387,8 @@
+     if ( $result == PE_PASSWORD_OK or $result == PE_OK ) {
+ 
+         # Get the corresponding session
+-        my $mailSession = $self->getApacheSession( $self->{mail_token} );
++        my $mailSession =
++          $self->getApacheSession( $self->{mail_token}, 1, undef, "mail" );
+ 
+         if ($mailSession) {
+ 
+--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Register.pm
++++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Register.pm
+@@ -107,8 +107,8 @@
+             'debug' );
+ 
+         # Get the corresponding session
+-        my $registerSession =
+-          $self->getApacheSession( $self->{register_token} );
++        my $registerSession = $self->getApacheSession( $self->{register_token},
++            1, undef, "register" );
+ 
+         if ( $registerSession && $registerSession->data ) {
+             $self->{registerInfo}->{mail} = $registerSession->data->{mail};
+@@ -223,7 +223,8 @@
+         or $self->getRegisterSession( $self->{registerInfo}->{mail} ) );
+ 
+     # Create a new session
+-    my $registerSession = $self->getApacheSession();
++    my $registerSession =
++      $self->getApacheSession( undef, 1, undef, "register" );
+ 
+     # Set _utime for session autoremove
+     # Use default session timeout and register session timeout to compute it
+@@ -267,17 +268,16 @@
+     # Skip this step if user clicked on the confirmation link
+     return PE_OK if $self->{register_token};
+ 
+-    # Check if confirmation mail has already been sent
+     my $register_session =
+       $self->getRegisterSession( $self->{registerInfo}->{mail} );
+-    $self->{mail_already_sent} = ( $register_session and !$self->{id} ) ? 1 : 0;
+ 
+     # Read session to get creation and expiration dates
+     $self->{id} = $register_session unless $self->{id};
+ 
+     $self->lmLog( "Register session found: $register_session", 'debug' );
+ 
+-    my $registerSession = $self->getApacheSession( $register_session, 1 );
++    my $registerSession =
++      $self->getApacheSession( $register_session, 1, undef, "register" );
+     $self->{registerInfo}->{registerSessionTimeoutTimestamp} =
+       $registerSession->data->{registerSessionTimeoutTimestamp};
+     $self->{registerInfo}->{registerSessionStartTimestamp} =
+@@ -300,7 +300,9 @@
+     $self->{startMailTime} = strftime( "%H:%M",    localtime $startTimestamp );
+ 
+     # Ask if user want another confirmation email
+-    if ( $self->{mail_already_sent} and !$self->param('resendconfirmation') ) {
++    if ( $registerSession->data->{mail_already_sent}
++        and !$self->param('resendconfirmation') )
++    {
+         return PE_MAILCONFIRMATION_ALREADY_SENT;
+     }
+ 
+@@ -338,6 +340,9 @@
+       unless $self->send_mail( $self->{registerInfo}->{mail}, $subject, $body,
+         $html );
+ 
++    # Save status
++    $registerSession->update( { "mail_already_sent" => 1 } );
++
+     PE_MAILCONFIRMOK;
+ }
+ 
+@@ -384,8 +389,8 @@
+     if ( $result == PE_OK ) {
+ 
+         # Get the corresponding session
+-        my $registerSession =
+-          $self->getApacheSession( $self->{register_token} );
++        my $registerSession = $self->getApacheSession( $self->{register_token},
++            1, undef, "register" );
+ 
+         if ($registerSession) {
+ 
+--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_SMTP.pm
++++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_SMTP.pm
+@@ -143,7 +143,7 @@
+ 
+     # Browse found sessions to check if it's a mail session
+     foreach my $id ( keys %$sessions ) {
+-        my $mailSession = $self->getApacheSession( $id, 1 );
++        my $mailSession = $self->getApacheSession( $id, 1, undef, "mail" );
+         next unless ($mailSession);
+         return $id if ( $mailSession->data->{_type} =~ /^mail$/ );
+     }
+@@ -168,7 +168,8 @@
+ 
+     # Browse found sessions to check if it's a register session
+     foreach my $id ( keys %$sessions ) {
+-        my $registerSession = $self->getApacheSession( $id, 1 );
++        my $registerSession =
++          $self->getApacheSession( $id, 1, undef, "register" );
+         next unless ($registerSession);
+         return $id if ( $registerSession->data->{_type} =~ /^register$/ );
+     }
diff --git a/debian/patches/series b/debian/patches/series
index 661cd37e1..b13b6df06 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -2,3 +2,4 @@ javascript-path.patch
 avoid-modify-sources.patch
 replace-mouse-by-moose.patch
 Avoid-developer-tests.patch
+CVE-2019-12046.patch


More information about the pkg-perl-maintainers mailing list