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

2019-05-22 Thread Guilhem Moulin
On Wed, 22 May 2019 at 07:34:06 +0200, Xavier wrote:
> It seems that Clément has fixed something related to that feature.
> Could you try 
> https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/commit/deff50f072c64898d1204daa28c01fdcc7275ea4
>  ?

That solves the issue indeed, thanks for the pointer!  I ended up
amending the patch as attached though:

 * Not setting the ‘Access-Control-Allow-Origin: *’ header is upstream
   issue #1519, fixed in e6c034a38aa0e7dadcf0ce87809193b327fbc0e5.

 * The second to last hunk from deff50f072c64898d1204daa28c01fdcc7275ea4
   (-2134,8 +2137,10) doesn't apply, and as it's only cosmetic
   (whitespace change) I just skipped it.

Cheers,
-- 
Guilhem.
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Simple.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Simple.pm
@@ -1049,7 +1049,7 @@ sub updatePersistentSession {
 
 }
 
-## @method void updateSession(hashRef infos, string id)
+## @method void updateSession(hashRef infos, string id, string kind)
 # Update session stored.
 # If no id is given, try to get it from cookie.
 # If the session is available, update datas with $info.
@@ -1057,9 +1057,10 @@ sub updatePersistentSession {
 # server local cache, if there are several LL::NG servers.
 # @param infos hash reference of information to update
 # @param id Session ID
+# @param kind Session kind
 # @return nothing
 sub updateSession {
-my ( $self, $infos, $id ) = @_;
+my ( $self, $infos, $id, $kind ) = @_;
 
 # Return if no infos to update
 return () unless ( ref $infos eq 'HASH' and %$infos );
@@ -1084,7 +1085,9 @@ sub updateSession {
 }
 
 # Update session in global storage
-if ( my $apacheSession = $self->getApacheSession( $id, 1 ) ) {
+if ( my $apacheSession =
+$self->getApacheSession( $id, 1, undef, $kind ) )
+{
 
 # Store updateTime
 $infos->{updateTime} = strftime( "%Y%m%d%H%M%S", localtime() );
@@ -1567,9 +1570,8 @@ sub process {
 {
 if ( ( my $code = $self->{error} ) > 0 ) {
 print $self->header(
--status=> '401 Unauthorizated',
-'-WWW-Authenticate'=> "SSO $self->{portal}",
-'-Access-Control-Allow-Origin' => '*',
+-status => '401 Unauthorizated',
+'-WWW-Authenticate' => "SSO $self->{portal}",
 );
 $self->quit;
 }
@@ -2744,7 +2746,7 @@ sub autoRedirect {
 $cdaInfos->{cookie_name} = $self->{cookieName} . "http";
 }
 
-$self->updateSession( $cdaInfos, $cdaSession->id );
+$self->updateSession( $cdaInfos, $cdaSession->id, "CDA" );
 
 $self->{urldc} .=
 ( $self->{urldc} =~ /\?/ ? '&' : '?' )


signature.asc
Description: PGP signature


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

2019-05-21 Thread Xavier



Le 21 mai 2019 21:40:35 GMT+02:00, Guilhem Moulin  a écrit :
>Hi Xavier,
>
> # Load session data into object
> if ($data) {
>+if ( $self->kind ) {
>+unless ( $data->{_session_kind} eq $self->kind ) {
>+$self->error("Session kind mistmatch");
>+return undef;
>+}
>+}
>
>Doesn't that break CDA in 1.9.7-3+deb9u1?  At least I'm no longer able
>to access a protected application under domains other than the portal.
>
>Error output shows occurrences of “Session kind mistmatch” instead, and
>further debugging suggests that $data->{_session_kind} is "CDA" while
>$self->kind is "SSO" in the execution flow that yields access denial.

Hello,

It seems that Clément has fixed something related to that feature. Could you 
try 
https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/commit/deff50f072c64898d1204daa28c01fdcc7275ea4
 ?

If it's OK, I'll propose a stretch update

-- 
Send with my EELO / K-9 Mail



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

2019-05-21 Thread Guilhem Moulin
Hi Xavier,

 # Load session data into object
 if ($data) {
+if ( $self->kind ) {
+unless ( $data->{_session_kind} eq $self->kind ) {
+$self->error("Session kind mistmatch");
+return undef;
+}
+}

Doesn't that break CDA in 1.9.7-3+deb9u1?  At least I'm no longer able
to access a protected application under domains other than the portal.

Error output shows occurrences of “Session kind mistmatch” instead, and
further debugging suggests that $data->{_session_kind} is "CDA" while
$self->kind is "SSO" in the execution flow that yields access denial.

-- 
Guilhem.


signature.asc
Description: PGP signature


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

2019-05-13 Thread Xavier
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

Description: Fix for CVE 
 When CSRF is enabled (default) and tokens are stored in session database
 (not default, used for poor load balancers), a short-life session can be
 created without being authentified.
 This patch fixes also a low level vulnerability on self-register (same vector,
 see https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues/1743)
 .
 This patch adds also 2 new upstream tests to prove that issues are fixed.
 .
 https://security-tracker.debian.org/tracker/CVE-2019-12046
Author: Xavier Guimard 
Origin: upstream, https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues/1742
Bug: https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues/1742
Bug-Debian: https://bugs.debian.org/
Bug-Ubuntu: https://launchpad.net/bugs/
Forwarded: not-needed
Last-Update: 2019-05-12

--- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Apache/Session/REST.pm
+++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Apache/Session/REST.pm
@@ -21,7 +21,7 @@
 modified => 0,
 };
 foreach (
-qw(baseUrl user password realm localStorage localStorageOptions lwpOpts lwpSslOpts)
+qw(baseUrl user password realm localStorage localStorageOptions lwpOpts lwpSslOpts kind)
   )
 {
 $self->{$_} = $args->{$_};
@@ -116,8 +116,13 @@
 
 sub getJson {
 my $self = shift;
-my $url  = shift;
-my $resp = $self->ua->get( $self->base . $url, @_ );
+my $id   = shift;
+my $resp = $self->ua->get(
+$self->base
+  . $id
+  . ( $self->{kind} ne 'SSO' ? "?kind=$self->{kind}" : '' ),
+@_
+);
 if ( $resp->is_success ) {
 my $res;
 eval { $res = from_json( $resp->content, { allow_nonref => 1 } ) };
--- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session.pm
+++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session.pm
@@ -139,6 +139,14 @@
 
 # Load session data into object
 if ($data) {
+if ( $self->kind and $data->{_session_kind} ) {
+unless ( $data->{_session_kind} eq $self->kind ) {
+$self->error(
+"Session kind mismatch : $data->{_session_kind} is not "
+  . $self->kind );
+return undef;
+}
+}
 $self->_save_data($data);
 $self->kind( $data->{_session_kind} );
 $self->id( $data->{_session_id} );
@@ -158,7 +166,7 @@
 if ( $self->storageModule =~ /^Lemonldap::NG::Common::Apache::Session/ )
 {
 tie %h, $self->storageModule, $self->id,
-  { %{ $self->options }, %$options };
+  { %{ $self->options }, %$options, kind => $self->kind };
 }
 else {
 tie %h, 'Lemonldap::NG::Common::Apache::Session', $self->id,
--- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm
+++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm
@@ -248,7 +248,7 @@
   Lemonldap::NG::Handler::PSGI::Main->tsv->{sessionCacheOptions},
 id=> $id,
 force => $force,
-kind  => $mod->{kind},
+( $id ? () : ( kind => $mod->{kind} ) ),
 ( $info ? ( info => $info ) : () ),
 }
 );
@@ -271,6 +271,9 @@
 $self->error('Unknown (or unconfigured) session type');
 return ();
 }
+if ( my $kind = $req->params('kind') ) {
+$m->{kind} = $kind;
+}
 return $m;
 }
 
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OneTimeToken.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OneTimeToken.pm
@@ -5,7 +5,7 @@
 use JSON qw(from_json to_json);
 use Crypt::URandom;
 
-our $VERSION = '2.0.2';
+our $VERSION = '2.0.4';