diff options
author | Ivan Kohler <ivan@freeside.biz> | 2014-09-15 20:44:48 -0700 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2014-09-15 20:44:48 -0700 |
commit | ed1f84b4e8f626245995ecda5afcf83092c153b2 (patch) | |
tree | 3f58bbef5fbf2502e65d29b37b5dbe537519e89d /rt/t/security | |
parent | fe9ea9183e8a16616d6d04a7b5c7498d28e78248 (diff) |
RT 4.0.22
Diffstat (limited to 'rt/t/security')
-rw-r--r-- | rt/t/security/CVE-2011-2083-cf-urls.t | 48 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-2083-clickable-xss.t | 52 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-2083-scrub.t | 18 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-2084-attach-tickets.t | 64 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-2084-cf-values.t | 132 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-2084-modifyscrips-templates.t | 126 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-2084-transactions.t | 59 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-4458-verp.t | 48 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-4460-rows-per-page.t | 32 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-5092-datetimeformat.t | 48 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-5092-graph-links.t | 27 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-5092-installmode.t | 24 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-5092-localizeddatetime.t | 30 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-5092-prefs.t | 77 | ||||
-rw-r--r-- | rt/t/security/CVE-2011-5093-execute-code.t | 53 | ||||
-rw-r--r-- | rt/t/security/fake-sendmail | 24 |
16 files changed, 862 insertions, 0 deletions
diff --git a/rt/t/security/CVE-2011-2083-cf-urls.t b/rt/t/security/CVE-2011-2083-cf-urls.t new file mode 100644 index 000000000..b1e1f3b0f --- /dev/null +++ b/rt/t/security/CVE-2011-2083-cf-urls.t @@ -0,0 +1,48 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +my ($base, $m) = RT::Test->started_ok; + +my $link = RT::Test->load_or_create_custom_field( + Name => 'link', + Type => 'Freeform', + MaxValues => 1, + Queue => 0, + LinkValueTo => '__CustomField__', +); + +my $include = RT::Test->load_or_create_custom_field( + Name => 'include', + Type => 'Freeform', + MaxValues => 1, + Queue => 0, + IncludeContentForValue => '__CustomField__', +); + +my $data_uri = 'data:text/html;base64,PHNjcmlwdD5hbGVydChkb2N1bWVudC5jb29raWUpPC9zY3JpcHQ+'; +my $xss = q{')-eval(decodeURI('alert("xss")'))-('}; + +my $ticket = RT::Ticket->new(RT->SystemUser); +$ticket->Create( + Queue => 'General', + Subject => 'ticket A', + 'CustomField-'.$link->id => $data_uri, + 'CustomField-'.$include->id => $xss, +); +ok $ticket->Id, 'created ticket'; + +ok $m->login('root', 'password'), "logged in"; +$m->get_ok($base . "/Ticket/Display.html?id=" . $ticket->id); + +# look for lack of link to data:text/html;base64,... +ok !$m->find_link(text => $data_uri), "no data: link"; +ok !$m->find_link(url => $data_uri), "no data: link"; + +# look for unescaped JS +$m->content_lacks($xss, 'escaped js'); + +$m->warning_like(qr/Potentially dangerous URL type/, "found warning about dangerous link"); +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-2083-clickable-xss.t b/rt/t/security/CVE-2011-2083-clickable-xss.t new file mode 100644 index 000000000..008c80378 --- /dev/null +++ b/rt/t/security/CVE-2011-2083-clickable-xss.t @@ -0,0 +1,52 @@ +use strict; +use warnings; + +use RT::Test tests => undef; +use Test::Warn; + +my ($base, $m) = RT::Test->started_ok; + +my $ticket = RT::Test->create_ticket( + Queue => 'General', + Subject => 'test ticket A', +); +my $id = $ticket->id; +ok $id, "created ticket"; + +my @links = ( + 'javascript:alert("xss")', + 'data:text/html,<script>alert("xss")</script>', +); + +for my $link ( map { ($_, ucfirst $_) } @links ) { + my ($ok, $msg); + warnings_like { + ($ok, $msg) = $ticket->AddLink( + Type => 'RefersTo', + Target => $link, + ); + } [qr/Could not determine a URI scheme/, qr/Couldn't resolve/]; + ok !$ok, $msg; + + ok $m->login, "logged in"; + $m->get_ok($base); + $m->follow_link_ok({ text => 'test ticket A' }, 'ticket page'); + $m->follow_link_ok({ text => 'Links' }, 'links page'); + $m->submit_form_ok({ + with_fields => { + "$id-RefersTo" => $link, + }, + button => 'SubmitTicket', + }, 'submitted links page'); + $m->content_contains("Couldn't resolve "); + $m->next_warning_like(qr/Could not determine a URI scheme/, 'expected warning'); + $m->next_warning_like(qr/Couldn't resolve/, 'expected warning'); + + my $element = $m->find_link( url => $link ); + ok !$element, "no <a> link"; +} + +$m->no_leftover_warnings_ok; + +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-2083-scrub.t b/rt/t/security/CVE-2011-2083-scrub.t new file mode 100644 index 000000000..f05378398 --- /dev/null +++ b/rt/t/security/CVE-2011-2083-scrub.t @@ -0,0 +1,18 @@ +use strict; +use warnings; + +use RT::Test nodb => 1, tests => undef; +use RT::Interface::Web; # This gets us HTML::Mason::Commands +use Test::LongString; + +{ + my $html = '<div id="metadata"><span class="actions"><a>OH HAI</a></span></div><p>Moose</p>'; + my $expected = '<div><span><a>OH HAI</a></span></div><p>Moose</p>'; + is_string(scrub_html($html), $expected, "class and id are stripped"); +} + +sub scrub_html { + return HTML::Mason::Commands::ScrubHTML(shift); +} + +done_testing; diff --git a/rt/t/security/CVE-2011-2084-attach-tickets.t b/rt/t/security/CVE-2011-2084-attach-tickets.t new file mode 100644 index 000000000..d7352cb85 --- /dev/null +++ b/rt/t/security/CVE-2011-2084-attach-tickets.t @@ -0,0 +1,64 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +my $user = RT::Test->load_or_create_user( + Name => 'user', + EmailAddress => 'user@example.com', + Privileged => 1, + Password => 'password', +); + +ok( + RT::Test->set_rights( + { Principal => 'Everyone', Right => [qw/CreateTicket/] }, + { Principal => 'Requestor', Right => [qw/ShowTicket/] }, + ), + 'set rights' +); + +my $secret = "sekrit message"; + +RT::Test->create_tickets( + {}, + { + Subject => 'ticket A', + Requestor => $user->EmailAddress, + Content => "user's ticket", + }, + { + Subject => 'ticket B', + Requestor => 'root@localhost', + Content => $secret, + }, +); + +my $ticket_b = RT::Test->last_ticket; + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login( 'user', 'password' ), 'logged in as user'; + +$m->get_ok("$baseurl/Ticket/Display.html?id=" . $ticket_b->id); +$m->content_contains('No permission'); +$m->warning_like(qr/no permission/i, 'no permission warning'); + +RT::Test->clean_caught_mails; + +# Ticket Create is just one example of where this is vulnerable +$m->get_ok('/Ticket/Create.html?Queue=1'); +$m->submit_form_ok({ + form_name => 'TicketCreate', + fields => { + Subject => 'ticket C', + AttachTickets => $ticket_b->id, + }, +}, 'create a ticket'); + +my @mail = RT::Test->fetch_caught_mails; +ok @mail, "got some outgoing emails"; +unlike $mail[0], qr/\Q$secret\E/, "doesn't contain ticket user can't see"; + +undef $m; +done_testing; + diff --git a/rt/t/security/CVE-2011-2084-cf-values.t b/rt/t/security/CVE-2011-2084-cf-values.t new file mode 100644 index 000000000..1178b15af --- /dev/null +++ b/rt/t/security/CVE-2011-2084-cf-values.t @@ -0,0 +1,132 @@ +use strict; +use warnings; + +use RT::Test tests => undef; +use JSON qw(decode_json); + +my ($base, $m) = RT::Test->started_ok; + +my $cf1 = RT::Test->load_or_create_custom_field( + Name => 'cf1', + Type => 'Select', + MaxValues => 1, + Queue => 0, +); +ok $cf1->id, "created cf1"; + +my $cf2 = RT::Test->load_or_create_custom_field( + Name => 'cf2', + Type => 'Select', + MaxValues => 1, + Queue => 0, +); +ok $cf2->id, "created cf2"; + +ok( $cf1->AddValue( Name => "cf1 value $_" ) ) for qw(a b c); +ok( $cf2->AddValue( Name => "cf2 value $_" ) ) for qw(x y z); + +sub ac { + my (%args) = ( + CF => $cf1->id, + Term => "%", + Context => undef, + ContextId => undef, + ContextType => undef, + @_ + ); + $args{term} = delete $args{Term}; + + if (my $obj = delete $args{Context}) { + $args{ContextId} = $obj->Id unless defined $args{ContextId}; + $args{ContextType} = ref($obj) unless defined $args{ContextType}; + } + + $args{"Object---CustomField-$args{CF}-Values"} = ""; + delete $args{CF}; + + delete $args{$_} for grep {not defined $args{$_}} keys %args; + + my $URI = URI->new("$base/Helpers/Autocomplete/CustomFieldValues"); + $URI->query_form( %args ); + $m->get_ok($URI, "GET to autocompleter"); + return decode_json($m->content); +} + +$m->login; +is_deeply ac(CF => 12345, ContextId => 1, ContextType => "RT::Queue"), + [], 'nothing for invalid CF'; + +is_deeply ac(), + [], "Nothing without a context id"; +is_deeply ac( ContextId => 12345, ContextType => "RT::Queue"), + [], "Nothing with invalid contextid id"; +is_deeply ac( ContextId => 12, ContextType => "RT::User"), + [], "Nothing with invalid contextid type"; + + + +my $user = RT::Test->load_or_create_user( + Name => 'user', + Password => 'password', + Privileged => 1, +); +my $queue = RT::Test->load_or_create_queue( Name => 'CF Test' ); +ok $queue->id, 'found or created queue'; +my $ticket = RT::Test->create_ticket( + Queue => $queue->id, + Subject => "CF application", +); +ok $queue->id, 'created ticket'; + +$m->logout; +$m->login('user','password'); + +is_deeply ac( Context => $queue ), [], 'queue context, no permissions, no result'; +is_deeply ac( Context => $ticket ), [], 'ticket context, no permissions, no result'; + +ok( RT::Test->set_rights( + { Principal => $user, Right => [qw(SeeCustomField)], Object => $queue }, +), 'add queue level CF viewing rights'); + +my $cfvalues = [ ( map { { value => "cf1 value $_" , label => "cf1 value $_" } } qw(a b c) ) ]; +is_deeply ac( Context => $queue ), $cfvalues, 'queue context, with permissions get result'; +is_deeply ac( Context => $ticket ), $cfvalues, 'ticket context, with permissions get result'; + +{ + diag "Switching to non-global CFs"; + my $globalq = RT::Queue->new( RT->SystemUser ); + my ($status, $msg) = $cf1->RemoveFromObject( $globalq ); + ok($status, "Removed CF1 globally: $msg"); + ($status, $msg) = $cf1->AddToObject( $queue ); + ok($status, "Added CF1 to queue @{[$queue->id]}: $msg"); + ($status, $msg) = $cf2->RemoveFromObject( $globalq ); + ok($status, "Removed CF2 globally: $msg"); +} + +is_deeply ac( CF => $cf2->id, Context => $queue ), [], 'queue context, but not applied, get no result'; +is_deeply ac( CF => $cf2->id, Context => $ticket ), [], 'ticket context, but not applied, get no result'; + +is_deeply ac( Context => $queue ), $cfvalues, 'queue context, applied correctly, get result'; +is_deeply ac( Context => $ticket ), $cfvalues, 'ticket context, applied correctly, get result'; + + + +diag "Ticket-level rights"; + +ok( RT::Test->set_rights( + { Principal => "Owner", Right => [qw(SeeCustomField)], Object => $queue }, + { Principal => $user, Right => [qw(OwnTicket SeeTicket)], Object => RT->System }, +), 'add owner level CF viewing rights'); + +is_deeply ac( Context => $queue ), [], 'queue context, but not owner'; +is_deeply ac( Context => $ticket ), [], 'ticket context, but not owner'; + +my ($status, $msg) = $ticket->SetOwner( $user->id ); +ok( $status, "Set owner to user: $msg" ); + +is_deeply ac( Context => $queue ), [], 'queue context is not enough'; +is_deeply ac( Context => $ticket ), $cfvalues, 'ticket context, get values'; + + +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-2084-modifyscrips-templates.t b/rt/t/security/CVE-2011-2084-modifyscrips-templates.t new file mode 100644 index 000000000..f68706e52 --- /dev/null +++ b/rt/t/security/CVE-2011-2084-modifyscrips-templates.t @@ -0,0 +1,126 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +sub set_fails { + my $col = shift; + my $obj = shift; + my $to = ref $_[0] ? +shift->Id : shift; + my $from = $obj->$col; + my $meth = "Set$col"; + + my ($ok, $msg) = $obj->$meth($to); + ok !$ok, "$meth denied: $msg"; + is $obj->$col, $from, "$col left alone"; +} + +sub set_ok { + my $col = shift; + my $obj = shift; + my $to = ref $_[0] ? +shift->Id : shift; + my $from = $obj->$col; + my $meth = "Set$col"; + + my ($ok, $msg) = $obj->$meth($to); + ok $ok, "$meth allowed: $msg"; + is $obj->$col, $to, "$col updated"; +} + +my $qa = RT::Test->load_or_create_queue( Name => 'Queue A' ); +my $qb = RT::Test->load_or_create_queue( Name => 'Queue B' ); +ok $qa->id, "created Queue A"; +ok $qb->id, "created Queue B"; + +my $user = RT::Test->load_or_create_user( Name => 'testuser' ); +my $cu = RT::CurrentUser->new( $user ); +ok $user->id, "created testuser"; + +diag "ModifyScrips"; +{ + my $scrip = RT::Scrip->new( RT->SystemUser ); + my ($scrip_id, $msg) = $scrip->Create( + Description => 'Testing', + Queue => $qa->Id, + ScripCondition => 'User Defined', + ScripAction => 'User Defined', + Template => 'Blank', + CustomIsApplicableCode => 'if ($self->TicketObj->Subject =~ /fire/) { return (1);} else { return(0)}', + CustomPrepareCode => '1;', + CustomCommitCode => 'warn "scrip fired!";', + ); + ok $scrip_id, $msg; + + RT::Test->set_rights( + { Principal => $user, Right => 'ShowScrips' }, + { Principal => $user, Right => 'ModifyScrips', Object => $qa }, + ); + + $scrip = RT::Scrip->new( $cu ); + $scrip->Load( $scrip_id ); + ok $scrip->id, "loaded scrip as test user"; + is $scrip->Queue, $qa->Id, 'queue is A'; + + ok +($scrip->SetName('Testing ModifyScrips')); + + set_fails( Queue => $scrip => $qb ); + set_fails( Queue => $scrip => 0 ); + set_fails( Queue => $scrip => undef ); + set_fails( Queue => $scrip => '' ); + + RT::Test->add_rights( Principal => $user, Right => 'ModifyScrips', Object => $qb ); + + set_ok( Queue => $scrip => $qb ); + set_fails( Queue => $scrip => 0 ); + set_fails( Queue => $scrip => undef ); + set_fails( Queue => $scrip => '' ); + + RT::Test->add_rights( Principal => $user, Right => 'ModifyScrips' ); + + set_ok( Queue => $scrip => 0 ); + + set_fails( Template => $scrip => 2 ); + + RT::Test->add_rights( Principal => $user, Right => 'ShowTemplate' ); + + set_ok( Template => $scrip => 2 ); + is $scrip->TemplateObj->Name, 'Autoreply', 'template name is right'; +} + +diag "ModifyTemplate"; +{ + RT::Test->set_rights( + { Principal => $user, Right => 'ShowTemplate' }, + { Principal => $user, Right => 'ModifyTemplate', Object => $qa }, + ); + + my $template = RT::Template->new( RT->SystemUser ); + my ($id, $msg) = $template->Create( + Queue => $qa->Id, + Name => 'Testing', + Type => 'Perl', + Content => "\n\nThis is a test template.\n", + ); + ok $id, $msg; + + $template = RT::Template->new( $cu ); + $template->Load( $id ); + ok $template->id, "loaded template as test user"; + is $template->Queue, $qa->Id, 'queue is A'; + + ok +($template->SetName('Testing ModifyTemplate')); + + set_fails( Queue => $template => $qb ); + set_fails( Queue => $template => 0 ); + + RT::Test->add_rights( Principal => $user, Right => 'ModifyTemplate', Object => $qb ); + + set_ok( Queue => $template => $qb ); + set_fails( Queue => $template => 0 ); + + RT::Test->add_rights( Principal => $user, Right => 'ModifyTemplate' ); + + set_ok( Queue => $template => 0 ); +} + +done_testing; diff --git a/rt/t/security/CVE-2011-2084-transactions.t b/rt/t/security/CVE-2011-2084-transactions.t new file mode 100644 index 000000000..817288ded --- /dev/null +++ b/rt/t/security/CVE-2011-2084-transactions.t @@ -0,0 +1,59 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +# A privileged user, but with no privs +my $bad = RT::Test->load_or_create_user( + Name => 'testing', + EmailAddress => 'test@example.com', + Password => 'password', +); +ok( $bad, "Got a user object back" ); +ok( $bad->id, "Successfully created a user" ); + + +# A ticket CF +my $obj = RT::Test->load_or_create_custom_field( + Name => "Private CF", + Type => "Freeform", + Queue => 0, +); + +my ($t) = RT::Test->create_tickets( {}, + { Subject => 'Testing' } +); +ok($t->id, "Created a ticket"); + +# Add a txn on it +my ($cfid) = $t->AddCustomFieldValue( + Field => $obj->Id, + Value => "hidden-value" +); +ok($cfid, "Got CF id $cfid"); +my $update_id = $t->Transactions->Last->Id; + +# Somebody else shouldn't be able to see the old and new values +my ($base, $m) = RT::Test->started_ok; +$m->post_ok("$base/REST/1.0/transaction/$update_id", [ + user => 'testing', + pass => 'password', + format => 'l', +]); +$m->content_lacks("hidden-value"); + +# Make a transaction on a user +my $root = RT::Test->load_or_create_user( Name => "root" ); +$root->SetHomePhone("hidden-value"); +$update_id = $root->Transactions->Last->Id; + +# Which should also be hidden from random privileged users +$m->post_ok("$base/REST/1.0/transaction/$update_id", [ + user => 'testing', + pass => 'password', + format => 'l', +]); +$m->content_lacks("hidden-value"); + +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-4458-verp.t b/rt/t/security/CVE-2011-4458-verp.t new file mode 100644 index 000000000..f84b79403 --- /dev/null +++ b/rt/t/security/CVE-2011-4458-verp.t @@ -0,0 +1,48 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +RT->Config->Set( MailCommand => 'sendmailpipe' ); +RT->Config->Set( VERPPrefix => "verp-" ); +RT->Config->Set( VERPDomain => "example.com" ); + +# Ensure that the fake sendmail knows where to write to +$ENV{RT_MAILLOGFILE} = RT::Test->temp_directory . "/sendmailpipe.log"; +my $fake = File::Spec->rel2abs( File::Spec->catfile( + 't', 'security', 'fake-sendmail' ) ); +RT->Config->Set( SendmailPath => $fake); + +ok( + RT::Test->set_rights( + { Principal => 'Everyone', Right => [qw/CreateTicket/] }, + ), + 'set rights' +); + +my $bad = RT::Test->load_or_create_user( + EmailAddress => 'danger-$USER@example.com', +); +ok( $bad, "Got a user object back" ); +ok( $bad->id, "Successfully created a user" ); + +my $current_user = RT::CurrentUser->new(RT->SystemUser); +my ($id, $msg) = $current_user->Load($bad->Id); +ok( $id, "Loaded the user successfully" ); + +my $ticket = RT::Ticket->new( $current_user ); +($id, $msg) = $ticket->Create( + Requestor => $bad->Id, + Subject => "Danger, Will Robinson!", + Queue => "General" +); +ok( $id, "Created a ticket: $msg" ); + +open(LOG, "<", $ENV{RT_MAILLOGFILE}) or die "Can't open log file: $!"; +while (my $line = <LOG>) { + next unless $line =~ /^-f/; + like($line, qr/\$USER/, "Contains uninterpolated \$USER"); +} +close(LOG); + +done_testing; diff --git a/rt/t/security/CVE-2011-4460-rows-per-page.t b/rt/t/security/CVE-2011-4460-rows-per-page.t new file mode 100644 index 000000000..92d6853e5 --- /dev/null +++ b/rt/t/security/CVE-2011-4460-rows-per-page.t @@ -0,0 +1,32 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +plan skip_all => 'valid SQL only on mysql' + unless RT->Config->Get('DatabaseType') eq 'mysql'; + +my ($base, $m) = RT::Test->started_ok; +ok $m->login, "logged in"; + +my $t = RT::Ticket->new( RT->SystemUser ); +$t->Create( + Queue => 1, + Subject => 'seed', +); +ok $t->id, 'created seed ticket'; + +my $root = RT::User->new( RT->SystemUser ); +$root->Load('root'); +my $password = $root->__Value('Password'); +ok $password, 'pulled hashed password from db'; + +my $sql = q[1 union select 1+id as id, 1+id as EffectiveId, 1 as Queue, 'ticket' as Type, 0 as IssueStatement, 0 as Resolution, 12 as Owner, Password as Subject, 0 as InitialPriority, 0 as FinalPriority, 0 as Priority, 0 as TimeEstimated, 0 as TimeWorked, Name as Status, 0 as TimeLeft, null as Told, null as Starts, null as Started, null as Due, null as Resolved, 0 as LastUpdatedBy, null as LastUpdated, 6 as Creator, null as Created, 0 as Disabled from Users]; +RT::Interface::Web::EscapeURI(\$sql); + +$m->get_ok("$base/Search/Results.html?Format=id,Subject,Status;Query=id%3E0;OrderBy=|;Rows=$sql"); +$m->content_lacks($password, "our password hash doesn't show up!"); +$m->warning_like(qr/isn't numeric/); + +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-5092-datetimeformat.t b/rt/t/security/CVE-2011-5092-datetimeformat.t new file mode 100644 index 000000000..470f4f4f6 --- /dev/null +++ b/rt/t/security/CVE-2011-5092-datetimeformat.t @@ -0,0 +1,48 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +my ($base, $m) = RT::Test->started_ok; + +my $user = RT::Test->load_or_create_user( + Name => 'user', + Password => 'password', + Privileged => 1, +); + +ok $user->id, 'created user'; + +ok( + RT::Test->set_rights( + { Principal => 'privileged', Right => [qw(ModifySelf ShowTicket)] }, + ), + "granted ModifySelf to privileged" +); + +my $ticket = RT::Test->create_ticket( + Queue => 'General', + Subject => 'testing', +); + +ok $ticket->id, 'created ticket'; + +$m->login('user'); +$m->get_ok("$base/Prefs/Other.html"); +my $format = 'Formatters'; +$m->submit_form_ok({ + form_name => 'ModifyPreferences', + fields => { + DateTimeFormat => $format, + }, + button => 'Update', +}, 'update prefs'); +is $user->Preferences(RT->System, {})->{DateTimeFormat}, $format, 'set preference'; + +$m->no_warnings_ok; +$m->get_ok("$base/Ticket/Display.html?id=" . $ticket->id); +$m->next_warning_like(qr/Invalid date formatter.+?\Q$format\E/, 'invalid formatter warning'); +$m->content_lacks($_, "lacks formatter in page") for @RT::Date::FORMATTERS; + +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-5092-graph-links.t b/rt/t/security/CVE-2011-5092-graph-links.t new file mode 100644 index 000000000..5e98dd3b5 --- /dev/null +++ b/rt/t/security/CVE-2011-5092-graph-links.t @@ -0,0 +1,27 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +my ($base, $m) = RT::Test->started_ok; +$m->login; + +for my $arg (qw(LeadingLink ShowLinks)) { + my $ticket = RT::Test->create_ticket( + Queue => 'General', + Subject => 'testing', + ); + ok $ticket->id, 'created ticket'; + + ok !$ticket->ToldObj->Unix, 'no Told'; + $m->get_ok("$base/Ticket/Graphs/index.html?$arg=SetTold;id=" . $ticket->id); + + $ticket->Load($ticket->id); # cache busting + + ok !$ticket->ToldObj->Unix, 'still no Told'; + $m->content_lacks('GotoFirstItem', 'no GotoFirstItem error'); + $m->content_like(qr|<img[^>]+?src=['"]/Ticket/Graphs/@{[$ticket->id]}|, 'found image element'); +} + +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-5092-installmode.t b/rt/t/security/CVE-2011-5092-installmode.t new file mode 100644 index 000000000..ce88a4fec --- /dev/null +++ b/rt/t/security/CVE-2011-5092-installmode.t @@ -0,0 +1,24 @@ +use strict; +use warnings; + +BEGIN { + $ENV{RT_TEST_WEB_HANDLER} = 'inline'; +} + +use RT::Test tests => undef; +use Test::Warn; + +my ($base, $m) = RT::Test->started_ok; + +$m->login; +$m->content_like(qr/RT at a glance/i, 'homepage'); + +warning_like { + ok !RT->InstallMode(1), 'install mode failed to turn on'; +} qr/tried to turn on InstallMode/; + +$m->reload; +$m->content_like(qr/RT at a glance/i, 'still homepage'); + +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-5092-localizeddatetime.t b/rt/t/security/CVE-2011-5092-localizeddatetime.t new file mode 100644 index 000000000..733afc08a --- /dev/null +++ b/rt/t/security/CVE-2011-5092-localizeddatetime.t @@ -0,0 +1,30 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +my $root = RT::CurrentUser->new('root'); +my ($ok, $msg) = $root->UserObj->SetLang('en-us'); +ok $ok, $msg; + +my $year = (localtime time)[5] + 1900; +my $date = RT::Date->new( $root ); +$date->SetToNow; + +like $date->AsString( Format => 'LocalizedDateTime' ), + qr/\Q$year\E/, 'contains full year'; + +unlike $date->AsString( Format => 'LocalizedDateTime', DateFormat => 'date_format_short' ), + qr/\Q$year\E/, 'lacks full year'; + +eval { + $date->AsString( Format => 'LocalizedDateTime', DateFormat => 'bogus::format' ); +}; +ok !$@, "didn't die with bogus DateFormat"; + +eval { + $date->AsString( Format => 'LocalizedDateTime', TimeFormat => 'bogus::format' ); +}; +ok !$@, "didn't die with bogus TimeFormat"; + +done_testing; diff --git a/rt/t/security/CVE-2011-5092-prefs.t b/rt/t/security/CVE-2011-5092-prefs.t new file mode 100644 index 000000000..b8e15aae0 --- /dev/null +++ b/rt/t/security/CVE-2011-5092-prefs.t @@ -0,0 +1,77 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +my ($base, $m) = RT::Test->started_ok; + +my $user = RT::Test->load_or_create_user( + Name => 'ausername', + EmailAddress => 'user@example.com', + Password => 'password', + Privileged => 1, +); + +ok $user->id, 'created user'; + +ok( + RT::Test->set_rights( + { Principal => 'privileged', Right => [qw(ModifySelf ShowTicket)] }, + ), + "granted ModifySelf to privileged" +); + +$m->login('ausername'); + +{ + $m->get_ok("$base/Prefs/Other.html"); + my $style = '../css/base'; + $m->submit_form_ok({ + with_fields => { + WebDefaultStylesheet => $style, + }, + button => 'Update', + }, 'update prefs'); + is(RT->Config->Get('WebDefaultStylesheet', $user), $style, 'set preference'); + + SKIP: { + skip "RT::User->Stylesheet wasn't backported", 1 unless $user->can("Stylesheet"); + is $user->Stylesheet, RT->Config->Get('WebDefaultStylesheet'), '$user->Stylesheet is the default'; + } + + $m->get_ok($base); + $m->content_unlike(qr/<link.+?\Q$style\E/, "lack .. path in page <link>"); + $m->content_contains( RT->Config->Get('WebDefaultStylesheet') ); +} + +{ + $m->get_ok("$base/Prefs/Other.html"); + my $format = '/../../m/_elements/full_site_link'; + $m->submit_form_ok({ + form_name => 'ModifyPreferences', + fields => { + UsernameFormat => $format, + }, + button => 'Update', + }, 'update prefs'); + $m->content_contains('saved'); + + my $ticket = RT::Test->create_ticket( + Queue => 'General', + Subject => 'test ticket', + Requestor => 'user@example.com', + ); + ok $ticket->id, 'created ticket'; + $m->get_ok($base . "/Ticket/Display.html?id=" . $ticket->id); + $m->content_lacks('NotMobile', "lacks NotMobile"); + $m->next_warning_like(qr/UsernameFormat/, 'caught UsernameFormat warning'); +} + +{ + $m->get_ok("$base/Helpers/Toggle/ShowRequestor?Status=/../../../Elements/Logo;Requestor=root"); + $m->content_lacks('logo', "didn't display /Elements/Logo"); + $m->content_contains('Results.html', "found link to search results"); +} + +undef $m; +done_testing; diff --git a/rt/t/security/CVE-2011-5093-execute-code.t b/rt/t/security/CVE-2011-5093-execute-code.t new file mode 100644 index 000000000..5124ab88b --- /dev/null +++ b/rt/t/security/CVE-2011-5093-execute-code.t @@ -0,0 +1,53 @@ +use strict; +use warnings; + +use RT::Test tests => undef; + +my $template = RT::Template->new( RT->SystemUser ); +my ($ok, $msg) = $template->Create( + Queue => 0, + Name => 'test', + Type => 'Simple', + Content => <<'.', +===Create-Ticket: testing +Queue: General +Subject: duplicate: { $Tickets{TOP}->Subject } +. +); +ok $ok, $msg; + +my $ticket = RT::Test->create_ticket( + Queue => 'General', + Subject => 'a ticket', +); +ok $ticket->id, "created ticket"; + +for my $type (qw(Simple Perl)) { + if ($template->Type ne $type) { + my ($ok, $msg) = $template->SetType($type); + ok $ok, $msg; + } + + require RT::Action::CreateTickets; + my $action = RT::Action::CreateTickets->new( + CurrentUser => RT->SystemUser, + TemplateObj => $template, + TicketObj => $ticket, + ); + $action->{TransactionObj} = $ticket->Transactions->First; + ok $action->Prepare, 'prepares'; + ok $action->Commit, 'commits'; + + my $new_ticket = RT::Test->last_ticket; + ok $new_ticket->id > $ticket->id, 'new ticket'; + + if ($type eq 'Perl') { + is $new_ticket->Subject, 'duplicate: a ticket', 'interpolated'; + isnt $new_ticket->Subject, 'duplicate: { $Tickets{TOP}->Subject }', 'interpolated'; + } else { + isnt $new_ticket->Subject, 'duplicate: a ticket', 'not interpolated'; + is $new_ticket->Subject, 'duplicate: { $Tickets{TOP}->Subject }', 'not interpolated'; + } +} + +done_testing; diff --git a/rt/t/security/fake-sendmail b/rt/t/security/fake-sendmail new file mode 100644 index 000000000..43259b603 --- /dev/null +++ b/rt/t/security/fake-sendmail @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +die "No \$RT_MAILLOGFILE set in environment" + unless $ENV{RT_MAILLOGFILE}; +open LOG, ">", $ENV{RT_MAILLOGFILE} + or die "Can't write to $ENV{RT_MAILLOGFILE}: $!"; + +my $needs_newline; +for (@ARGV) { + if (/^-/) { + print LOG "\n" if $needs_newline++; + print LOG $_; + } else { + print LOG " $_"; + } +} +print LOG "\n"; + +1 while $_ = <STDIN>; + +exit 0; |