On Fri, Mar 15, 2019 at 02:25:35PM +0100, Peter J. Philipp wrote: > I have have created a patch for cvsweb port that needs review and help in > getting it into the port itself. I'd like to apologize to Marc Espie for > contacting him regarding this port based on his last check-in on this port, > and thanks to Stuart Henderson for directing me here. > > The patch changed since my last submission to misc@ and since I am a complete > newbie in perl this would need a pro to look at it whether it's correct. > > I have produced the patch with 'diff -u cvsweb.orig cvsweb' directly in the > /var/www/cgi-bin directory. Credit goes to Ezio Paglia for finding this XSS > vuln. Also the cvsweb at openbsd.org is affected and can be checked with:
I looked this over and updated the patch to be against the port. It seems to be good and I only found a couple other places that needed to be escaped, the "stickyvars" section and the tr1/tr2 inputs in doLog, although r1, r2, tr1 and tr2 are part of "unsafevars" so their content is pretty limited already. It was a pretty quick look so I don't doubt that there are more, and I didn't actually get a chance to test it out, so hopefully someone else can. > https://cvsweb.openbsd.org/src/sbin/clri/clri.c?f=%22%3E%3Cscript%3Ealert(%27XSS%27)%3C/script%3E > > in chrome the XSS check activates immediately, I don't know what firefox does. With NoScript it throws up a big error saying there was an attempted XSS, without NoScript it throws up an alert box saying "XSS".
Index: Makefile =================================================================== RCS file: /cvs/ports/devel/cvsweb/Makefile,v retrieving revision 1.60 diff -u -p -r1.60 Makefile --- Makefile 4 Sep 2018 12:46:10 -0000 1.60 +++ Makefile 16 Mar 2019 00:17:58 -0000 @@ -3,7 +3,7 @@ COMMENT= CGI script to browse CVS repository trees DISTNAME= cvsweb-2.0.6 -REVISION= 26 +REVISION= 27 CATEGORIES= devel www HOMEPAGE= http://www.freebsd.org/projects/cvsweb.html Index: patches/patch-cvsweb_cgi =================================================================== RCS file: /cvs/ports/devel/cvsweb/patches/patch-cvsweb_cgi,v retrieving revision 1.13 diff -u -p -r1.13 patch-cvsweb_cgi --- patches/patch-cvsweb_cgi 7 Apr 2013 20:07:24 -0000 1.13 +++ patches/patch-cvsweb_cgi 16 Mar 2019 00:17:58 -0000 @@ -1,6 +1,7 @@ $OpenBSD: patch-cvsweb_cgi,v 1.13 2013/04/07 20:07:24 naddy Exp $ ---- cvsweb.cgi.orig Thu Sep 26 22:56:05 2002 -+++ cvsweb.cgi Sun Apr 7 14:15:55 2013 +Index: cvsweb.cgi +--- cvsweb.cgi.orig ++++ cvsweb.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl -wT +#!/usr/bin/perl -w @@ -37,7 +38,18 @@ $OpenBSD: patch-cvsweb_cgi,v 1.13 2013/0 ); @LOGSORTKEYS = qw(cvs date rev); -@@ -2014,20 +2009,6 @@ sub doDiff($$$$$$) { +@@ -1003,8 +998,9 @@ if (-d $fullname) { + if (scalar %tags || $input{only_with_tag}) { + print "<form method=\"get\" action=\"./\">\n"; + foreach my $var (@stickyvars) { ++ my $tmpvar = htmlquote($input{$var}); + print +- "<input type=\"hidden\" name=\"$var\" value=\"$input{$var}\">\n" ++ "<input type=\"hidden\" name=\"$var\" value=\"$tmpvar\">\n" + if (defined($input{$var}) + && (!defined($DEFAULTVALUE{$var}) + || $input{$var} ne $DEFAULTVALUE{$var}) +@@ -2014,20 +2010,6 @@ sub doDiff($$$$$$) { my @difftype = @{$difftype->{'opts'}}; my $human_readable = $difftype->{'colored'}; @@ -58,7 +70,25 @@ $OpenBSD: patch-cvsweb_cgi,v 1.13 2013/0 if ($human_readable) { if ($hr_ignwhite) { push @difftype, '-w'; -@@ -2658,7 +2639,7 @@ sub printLog($;$) { +@@ -2631,7 +2613,7 @@ sub printLog($;$) { + sprintf( + '%s/%s?annotate=%s%s', $scriptname, + urlencode($where), $_, +- $barequery ++ htmlquote($barequery) + ) + ); + } +@@ -2644,7 +2626,7 @@ sub printLog($;$) { + '[select for diffs]', + sprintf( + '%s?r1=%s%s', $scriptwhere, +- $_, $barequery ++ $_, htmlquote($barequery) + ) + ); + } else { +@@ -2658,7 +2640,7 @@ sub printLog($;$) { if (/^1\.1\.1\.\d+$/) { print " <i>(vendor branch)</i>"; } @@ -67,3 +97,57 @@ $OpenBSD: patch-cvsweb_cgi,v 1.13 2013/0 my ($est) = $mytz[(localtime($date{$_}))[8]]; print ", <i>", scalar localtime($date{$_}), " $est</i> ("; } else { +@@ -2847,7 +2829,7 @@ sub doLog($) { + + foreach (@stickyvars) { + printf('<input type="hidden" name="%s" value="%s">', $_, +- $input{$_}) ++ htmlquote($input{$_})) + if (defined($input{$_}) + && ((!defined($DEFAULTVALUE{$_}) + || $input{$_} ne $DEFAULTVALUE{$_}) && $input{$_} ne "")); +@@ -2860,7 +2842,7 @@ sub doLog($) { + print $sel; + print "</select>\n"; + $diffrev = $revdisplayorder[$#revdisplayorder]; +- $diffrev = $input{"r1"} if (defined($input{"r1"})); ++ $diffrev = htmlquote($input{"r1"}) if (defined($input{"r1"})); + print + "<input type=\"text\" size=\"$inputTextSize\" name=\"tr1\" value=\"$diffrev\" onchange=\"this.form.r1.selectedIndex=0\"></td>\n"; + print "<td><br></td>\n</tr>\n"; +@@ -2871,7 +2853,7 @@ sub doLog($) { + print $sel; + print "</select>\n"; + $diffrev = $revdisplayorder[0]; +- $diffrev = $input{"r2"} if (defined($input{"r2"})); ++ $diffrev = htmlquote($input{"r2"}) if (defined($input{"r2"})); + print + "<input type=\"text\" size=\"$inputTextSize\" name=\"tr2\" value=\"$diffrev\" onchange=\"this.form.r2.selectedIndex=0\"></td>\n"; + print "<td><input type=\"submit\" value=\" Get Diffs \" accesskey=\"G\"></td>\n"; +@@ -2916,7 +2898,8 @@ sub doLog($) { + next if ($_ eq "f"); + next if ($_ eq "only_with_tag"); + next if ($_ eq "logsort"); +- print "<input type=\"hidden\" name=\"$_\" value=\"$input{$_}\">\n" ++ printf "<input type=\"hidden\" name=\"%s\" value=\"%s\">\n", ++ $_, htmlquote($input{$_}) + if (defined($input{$_}) + && (!defined($DEFAULTVALUE{$_}) + || $input{$_} ne $DEFAULTVALUE{$_}) && $input{$_} ne ""); +@@ -3286,7 +3269,7 @@ sub clickablePath($$) { + join ('', $scriptname, + urlencode($wherepath), + (!$last || $lastslash ? '/' : ''), +- $query, ++ htmlquote($query), + (!$last || $lastslash ? "#dirlist" : "") + )); + } else { # do not make a link to the current dir +@@ -3527,6 +3510,7 @@ sub htmlquote($) { + # Special Characters; RFC 1866 + s/&/&/g; + s/\"/"/g; ++ s/%22/"/g; + s/</</g; + s/>/>/g; +
