From 67543ce1d62161fdef9dca198289d7dd7dceacc0 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sun, 10 Feb 2019 16:30:07 +0000 Subject: useragent: Don't allow non-HTTP protocols to be used This prevents the aggregate plugin from being used to read the contents of local files via file:/// URLs. Signed-off-by: Simon McVittie --- t/aggregate-file.t | 173 +++++++++++++++++++++++++++++++++++++ t/noparanoia/LWPx/ParanoidAgent.pm | 2 + t/secret.rss | 11 +++ 3 files changed, 186 insertions(+) create mode 100755 t/aggregate-file.t create mode 100644 t/noparanoia/LWPx/ParanoidAgent.pm create mode 100644 t/secret.rss (limited to 't') diff --git a/t/aggregate-file.t b/t/aggregate-file.t new file mode 100755 index 000000000..f00743dac --- /dev/null +++ b/t/aggregate-file.t @@ -0,0 +1,173 @@ +#!/usr/bin/perl +use utf8; +use warnings; +use strict; + +use Encode; +use Test::More; + +BEGIN { + plan(skip_all => "CGI not available") + unless eval q{ + use CGI qw(); + 1; + }; + + plan(skip_all => "IPC::Run not available") + unless eval q{ + use IPC::Run qw(run); + 1; + }; + + use_ok('IkiWiki'); + use_ok('YAML::XS'); +} + +# We check for English error messages +$ENV{LC_ALL} = 'C'; + +use Cwd qw(getcwd); +use Errno qw(ENOENT); + +my $installed = $ENV{INSTALLED_TESTS}; + +my @command; +if ($installed) { + @command = qw(ikiwiki --plugin inline); +} +else { + ok(! system("make -s ikiwiki.out")); + @command = ("perl", "-I".getcwd."/blib/lib", './ikiwiki.out', + '--underlaydir='.getcwd.'/underlays/basewiki', + '--set', 'underlaydirbase='.getcwd.'/underlays', + '--templatedir='.getcwd.'/templates'); +} + +sub write_old_file { + my $name = shift; + my $dir = shift; + my $content = shift; + writefile($name, $dir, $content); + ok(utime(333333333, 333333333, "$dir/$name")); +} + +sub write_setup_file { + my %params = @_; + my %setup = ( + wikiname => 'this is the name of my wiki', + srcdir => getcwd.'/t/tmp/in', + destdir => getcwd.'/t/tmp/out', + url => 'http://example.com', + cgiurl => 'http://example.com/cgi-bin/ikiwiki.cgi', + cgi_wrapper => getcwd.'/t/tmp/ikiwiki.cgi', + cgi_wrappermode => '0751', + add_plugins => [qw(aggregate)], + disable_plugins => [qw(emailauth openid passwordauth)], + aggregate_webtrigger => 1, + ); + if ($params{without_paranoia}) { + $setup{libdirs} = [getcwd.'/t/noparanoia']; + } + unless ($installed) { + $setup{ENV} = { 'PERL5LIB' => getcwd.'/blib/lib' }; + } + writefile("test.setup", "t/tmp", + "# IkiWiki::Setup::Yaml - YAML formatted setup file\n" . + Dump(\%setup)); +} + +sub thoroughly_rebuild { + ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT}); + ok(! system(@command, qw(--setup t/tmp/test.setup --rebuild --wrappers))); +} + +sub run_cgi { + my (%args) = @_; + my ($in, $out); + my $method = $args{method} || 'GET'; + my $environ = $args{environ} || {}; + my $params = $args{params} || { do => 'prefs' }; + + my %defaults = ( + SCRIPT_NAME => '/cgi-bin/ikiwiki.cgi', + HTTP_HOST => 'example.com', + ); + + my $cgi = CGI->new($args{params}); + my $query_string = $cgi->query_string(); + diag $query_string; + + if ($method eq 'POST') { + $defaults{REQUEST_METHOD} = 'POST'; + $in = $query_string; + $defaults{CONTENT_LENGTH} = length $in; + } else { + $defaults{REQUEST_METHOD} = 'GET'; + $defaults{QUERY_STRING} = $query_string; + } + + my %envvars = ( + %defaults, + %$environ, + ); + run(["./t/tmp/ikiwiki.cgi"], \$in, \$out, init => sub { + map { + $ENV{$_} = $envvars{$_} + } keys(%envvars); + }); + + return decode_utf8($out); +} + +sub test { + my $content; + + ok(! system(qw(rm -rf t/tmp))); + ok(! system(qw(mkdir t/tmp))); + + write_old_file('aggregator.mdwn', 't/tmp/in', + '[[!aggregate name="ssrf" url="file://'.getcwd.'/t/secret.rss"]]' + .'[[!inline pages="internal(aggregator/*)"]]'); + + write_setup_file(); + thoroughly_rebuild(); + + $content = run_cgi( + method => 'GET', + params => { + do => 'aggregate_webtrigger', + }, + ); + unlike($content, qr{creating new page}); + unlike($content, qr{Secrets}); + ok(! -e 't/tmp/in/.ikiwiki/transient/aggregator/ssrf'); + ok(! -e 't/tmp/in/.ikiwiki/transient/aggregator/ssrf/Secrets_go_here._aggregated'); + + thoroughly_rebuild(); + $content = readfile('t/tmp/out/aggregator/index.html'); + unlike($content, qr{Secrets}); + + diag('Trying test again with LWPx::ParanoidAgent disabled'); + + write_setup_file(without_paranoia => 1); + thoroughly_rebuild(); + + $content = run_cgi( + method => 'GET', + params => { + do => 'aggregate_webtrigger', + }, + ); + unlike($content, qr{creating new page}); + unlike($content, qr{Secrets}); + ok(! -e 't/tmp/in/.ikiwiki/transient/aggregator/ssrf'); + ok(! -e 't/tmp/in/.ikiwiki/transient/aggregator/ssrf/Secrets_go_here._aggregated'); + + thoroughly_rebuild(); + $content = readfile('t/tmp/out/aggregator/index.html'); + unlike($content, qr{Secrets}); +} + +test(); + +done_testing(); diff --git a/t/noparanoia/LWPx/ParanoidAgent.pm b/t/noparanoia/LWPx/ParanoidAgent.pm new file mode 100644 index 000000000..751e80ce6 --- /dev/null +++ b/t/noparanoia/LWPx/ParanoidAgent.pm @@ -0,0 +1,2 @@ +# make import fail +0; diff --git a/t/secret.rss b/t/secret.rss new file mode 100644 index 000000000..11202e9ed --- /dev/null +++ b/t/secret.rss @@ -0,0 +1,11 @@ + + + +Secrets go here +Secrets go here + + Secrets go here + Secrets go here + + + -- cgit v1.2.3