[request-tracker-maintainers] [jesse at bestpractical.com: [Rt-announce] SECURITY - Session Fixation Vulnerability in RT 3.0.0-3.8.5]

Dominic Hargreaves dom at earth.li
Mon Nov 30 17:01:10 UTC 2009


FYI,

I've been liasing with Jesse and the Debian security team about this
issue and fixed packages should appear soon.

----- Forwarded message from Jesse Vincent <jesse at bestpractical.com> -----

Date: Mon, 30 Nov 2009 11:51:05 -0500
From: Jesse Vincent <jesse at bestpractical.com>
To: rt-announce at lists.bestpractical.com
User-Agent: Mutt/1.5.20 (2009-06-14)
Subject: [Rt-announce] SECURITY - Session Fixation Vulnerability in RT
	3.0.0-3.8.5

In late September, a customer contacted us to report a session fixation
vulnerability in RT 3.8.5 and all earlier versions back to and including
RT 3.0.0.  Over the course of the past month, we've worked to develop
and release a version of RT not vulnerable to this issue as well as a
"hot patch" to earlier versions of RT which eliminates the vulnerability
with minimal code changes.  RT 3.8.6, released on October 19th, is _not_
vulnerable.

We have been assigned CVE number CVE-2009-3585 for this issue.

This issue could allow a malicious attacker who can operate a server in
the same domain (example.com where RT is rt.example.com) to obtain and
redistribute an RT session identifier to an unsuspecting user before
they log into RT.  When that user logs in, the attacker would then be
able to hijack the user's session.

As part of an internal audit of the session handling code, we found and
fixed an additional, related vulnerability which could allow an attacker
with HTTP access to the RT server to construct a similar attack without
the need for a server within the same domain.

If you are using RT's $WebExternalAuth configuration variable, you are
not vulnerable to this issue (but should still apply this patch).
If you are using the RT extension "RT-Authen-ExternalAuth", you must apply
this patch. RT-Authen-ExternalAuth does NOT protect you from this
vulnerability.

I have attached six patches which should cover all vulnerable versions
of RT 3.  RT 3.6.10 will be released later today and will include a
version of this patch.  As mentioned before, RT 3.8.6 is _not_ vulnerable.

The SHA1s of patches are:
38e0a8ce3480807a5dd6cc4da0eb51183382cddd  RT-3.0.0-session_fixation.v3.patch
de22a6e67d7d9d163a392d92530818f3d28e0af2  RT-3.0.1-3.0.6-session_fixation.v3.patch
03fb855a449393ef93db67b800d396bdbfb38a8f  RT-3.0.7-3.6.1-session_fixation.v3.patch
7e5acff213a735894663f63fac90c95089a5e5d1  RT-3.6.2-3.6.3-session_fixation.v3.patch
9c60e647c848e35cea5a6ffe36bdd1f0a355c91f  RT-3.6.4-3.6.9-session_fixation.v2.patch
ada53ca94fdb4db3b185a7e14405d5a9ef76017f  RT-3.8-session_fixation.patch

RT 3.0.0

 $ cd /opt/rt3/share
 $ patch -p1 < /path/to/RT-3.0.0-session_fixation.v3.patch

RT 3.0.1-3.0.6

 $ cd /opt/rt3/share
 $ patch -p1 < /path/to/RT-3.0.1-3.0.6-session_fixation.v3.patch

RT 3.0.7-3.6.1

 $ cd /opt/rt3/share
 $ patch -p1 < /path/to/RT-3.0.7-3.6.1-session_fixation.v3.patch


RT 3.6.2-3.6.3

 $ cd /opt/rt3/share
 $ patch -p1 < RT-3.6.2-3.6.3-session_fixation.v3.patch

RT 3.6.4-3.6.9

 $ cd /opt/rt3/share
 $ patch -p1 < RT-3.6.4-3.6.9-session_fixation.v2.patch

RT 3.8.0-3.8.5

 $ cd /opt/rt3/share
 $ patch -p1 < /path/to/RT-3.8-session_fixation.patch

You should then clear your mason cache. If your RT is installed in
/opt/rt3, you would use this command:

 $ rm -rf /opt/rt3/var/mason_data/obj/*

and restart your webserver, this is often accomplished with

 $ /etc/init.d/httpd restart
   (or)
 $ /etc/init.d/apache restart

I apologize for any inconvenience that this issue may have caused you.
We go to great lengths to make sure that RT is robust and secure, but,
as with any software, occasionally we do find defects.  We do our best
to deal with them quickly and responsibly.

I'd like to thank Mikal Gule and the University of Oslo for bringing
this issue to our attention and working with us to triage it and test
the patches included below.  I'd also like to thank Thomas Goetz, who
also brought a variant of this issue to our attention.

If you require assistance evaluating whether your RT deployment is
vulnerable to this issue or deploying the patch, please don't hesitate to
contact us at sales at bestpractical.com.  While we're not able to provide
commercial support without charge, we'll make every effort to provide
help for this issue as quickly and as inexpensively as possible.

Best,

Jesse Vincent
Best Practical

diff --git a/html/Elements/SetupSessionCookie b/html/Elements/SetupSessionCookie
index 019dc28..3f8ea84 100755
--- a/html/Elements/SetupSessionCookie
+++ b/html/Elements/SetupSessionCookie
@@ -42,7 +42,7 @@ my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
             LockDirectory => $RT::MasonSessionDir,
           };
     };
-    if ($@) {
+    if ( $@ || !($session{'CurrentUser'} && $session{'CurrentUser'}->id) ) {
 
         # If the session is invalid, create a new session.
         if ( $@ =~ /Object does not/i ) {
@@ -56,6 +56,18 @@ my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
               };
             undef $cookies{'RT_SID'};
         }
+        elsif ( !($session{'CurrentUser'} && $session{'CurrentUser'}->id) ) {
+            tied(%session)->delete;
+            tie %session, $session_class, undef,
+              $backends{$RT::DatabaseType} ? {
+                Handle     => $RT::Handle->dbh,
+                LockHandle => $RT::Handle->dbh,
+              } : {
+                Directory     => $RT::MasonSessionDir,
+                LockDirectory => $RT::MasonSessionDir,
+              };
+            undef $cookies{'RT_SID'};
+        }
         else {
             die "RT Couldn't write to session directory '$RT::MasonSessionDir': $@. Check that this dir ectory's permissions are correct.";
         }

diff --git a/html/Elements/SetupSessionCookie b/html/Elements/SetupSessionCookie
index 26eba3b..303827a 100755
--- a/html/Elements/SetupSessionCookie
+++ b/html/Elements/SetupSessionCookie
@@ -33,7 +33,7 @@ my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
 
     eval {
         tie %session, $session_class,
-          $SessionCookie || ( $cookies{'RT_SID'} ? $cookies{'RT_SID'}->value() : undef ),
+          ( $cookies{'RT_SID'} ? $cookies{'RT_SID'}->value() : undef ),
           $backends{$RT::DatabaseType} ? {
             Handle     => $RT::Handle->dbh,
             LockHandle => $RT::Handle->dbh,
@@ -42,7 +42,7 @@ my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
             LockDirectory => $RT::MasonSessionDir,
           };
     };
-    if ($@) {
+    if ( $@ || !($session{'CurrentUser'} && $session{'CurrentUser'}->id) ) {
 
         # If the session is invalid, create a new session.
         if ( $@ =~ /Object does not/i ) {
@@ -56,6 +56,18 @@ my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
               };
             undef $cookies{'RT_SID'};
         }
+        elsif ( !($session{'CurrentUser'} && $session{'CurrentUser'}->id) ) {
+            tied(%session)->delete;
+            tie %session, $session_class, undef,
+              $backends{$RT::DatabaseType} ? {
+                Handle     => $RT::Handle->dbh,
+                LockHandle => $RT::Handle->dbh,
+              } : {
+                Directory     => $RT::MasonSessionDir,
+                LockDirectory => $RT::MasonSessionDir,
+              };
+            undef $cookies{'RT_SID'};
+        }
         else {
             die "RT Couldn't write to session directory '$RT::MasonSessionDir': $@. Check that this dir ectory's permissions are correct.";
         }

diff --git a/html/Elements/SetupSessionCookie b/html/Elements/SetupSessionCookie
index fc04017..d072358 100755
--- a/html/Elements/SetupSessionCookie
+++ b/html/Elements/SetupSessionCookie
@@ -40,7 +40,7 @@ my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
     }
     eval {
         tie %session, $session_class,
-          $SessionCookie || ( $cookies{$cookiename} ? $cookies{$cookiename}->value() : undef ),
+          ( $cookies{$cookiename} ? $cookies{$cookiename}->value() : undef ),
           $backends{$RT::DatabaseType} ? {
             Handle     => $RT::Handle->dbh,
             LockHandle => $RT::Handle->dbh,
@@ -49,7 +49,7 @@ my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
             LockDirectory => $RT::MasonSessionDir,
           };
     };
-    if ($@) {
+    if ( $@ || !($session{'CurrentUser'} && $session{'CurrentUser'}->id) ) {
 
         # If the session is invalid, create a new session.
         if ( $@ =~ /Object does not/i ) {
@@ -63,6 +63,18 @@ my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
               };
             undef $cookies{$cookiename};
         }
+        elsif ( !($session{'CurrentUser'} && $session{'CurrentUser'}->id) ) {
+            tied(%session)->delete;
+            tie %session, $session_class, undef,
+              $backends{$RT::DatabaseType} ? {
+                Handle     => $RT::Handle->dbh,
+                LockHandle => $RT::Handle->dbh,
+              } : {
+                Directory     => $RT::MasonSessionDir,
+                LockDirectory => $RT::MasonSessionDir,
+              };
+            undef $cookies{$cookiename};
+        }
         else {
             die "RT Couldn't write to session directory '$RT::MasonSessionDir': $@. Check that this dir ectory's permissions are correct.";
         }

--- ../rt-3.8.5/share/html/Elements/SetupSessionCookie	2009-09-15 02:23:22.000000000 +0900
+++ share/html/Elements/SetupSessionCookie	2009-09-30 08:17:57.000000000 +0900
@@ -53,11 +53,17 @@
 my %cookies      = CGI::Cookie->fetch;
 my $cookiename   = "RT_SID_". RT->Config->Get('rtname');
 $cookiename     .= ".". $ENV{'SERVER_PORT'} if $ENV{'SERVER_PORT'};
-$SessionCookie ||= ( $cookies{$cookiename} ? $cookies{$cookiename}->value : undef ),
+$SessionCookie = ( $cookies{$cookiename} ? $cookies{$cookiename}->value : undef );
 
 tie %session, 'RT::Interface::Web::Session', $SessionCookie;
 undef $cookies{$cookiename} unless $SessionCookie && $session{'_session_id'} eq $SessionCookie;
 
+unless ($session{'CurrentUser'} && $session{CurrentUser}->id) {
+	tied(%session)->delete;
+	undef $cookies{$cookiename};
+	tie %session, 'RT::Interface::Web::Session', undef;
+}
+
 if ( int RT->Config->Get('AutoLogoff') ) {
     my $now = int(time/60);
     my $last_update = $session{'_session_last_update'} || 0;


diff --git a/html/Elements/SetupSessionCookie b/html/Elements/SetupSessionCookie
index b2b6d96..056524e 100755
--- a/html/Elements/SetupSessionCookie
+++ b/html/Elements/SetupSessionCookie
@@ -67,8 +67,7 @@ unless ( $RT::Handle->dbh && $RT::Handle->dbh->ping ) {
 }
 eval {
     tie %session, $session_class,
-        $SessionCookie
-        || ( $cookies{$cookiename} ? $cookies{$cookiename}->value() : undef ),
+        ( $cookies{$cookiename} ? $cookies{$cookiename}->value() : undef ),
         $backends{$RT::DatabaseType}
         ? {
         Handle     => $RT::Handle->dbh,
@@ -95,6 +94,21 @@ if ($@) {
         undef $cookies{$cookiename};
     };
 }
+elsif ( !($session{'CurrentUser'} && $session{'CurrentUser'}->id) ) {
+    eval {
+        undef $cookies{$cookiename};
+        tied(%session)->delete;
+        tie %session, $session_class, undef, $backends{$RT::DatabaseType}
+            ? {
+            Handle     => $RT::Handle->dbh,
+            LockHandle => $RT::Handle->dbh,
+            }
+            : {
+            Directory     => $RT::MasonSessionDir,
+            LockDirectory => $RT::MasonSessionDir,
+            };
+    }
+}
 
 if ($@) {
     die loc("RT couldn't store your session.") . "\n"

diff --git a/html/Elements/SetupSessionCookie b/html/Elements/SetupSessionCookie
index 087f825..c7b3c72 100755
--- a/html/Elements/SetupSessionCookie
+++ b/html/Elements/SetupSessionCookie
@@ -50,7 +50,7 @@ return if $m->is_subrequest; # avoid reentrancy, as suggested by masonbook
 
 my %cookies    = CGI::Cookie->fetch();
 my $cookiename = "RT_SID_" . $RT::rtname . "." . $ENV{'SERVER_PORT'};
-$SessionCookie ||= $cookies{$cookiename} ? $cookies{$cookiename}->value : undef;
+$SessionCookie = $cookies{$cookiename} ? $cookies{$cookiename}->value : undef;
 
 my %backends   = (
     mysql => 'Apache::Session::MySQL',
@@ -95,6 +95,13 @@ if ($@) {
         undef $cookies{$cookiename};
     };
 }
+elsif ( !($session{'CurrentUser'} && $session{'CurrentUser'}->id) ) {
+    eval {
+        undef $cookies{$cookiename};
+        tied(%session)->delete;
+        tie %session, $session_class, undef, $session_properties;
+    }
+}
 
 if ($@) {
     die loc("RT couldn't store your session.") . "\n"




_______________________________________________
RT-Announce mailing list
RT-Announce at lists.bestpractical.com
http://lists.bestpractical.com/cgi-bin/mailman/listinfo/rt-announce


----- End forwarded message -----

-- 
Dominic Hargreaves | http://www.larted.org.uk/~dom/
PGP key 5178E2A5 from the.earth.li (keyserver,web,email)



More information about the pkg-request-tracker-maintainers mailing list