One of my custom monitors was printing the output of a syslog entry as its summary output. The syslog entry was from a mail program, so it had stuff like "to=<[EMAIL PROTECTED]>". But in mon.cgi's output in my Web browser, it just said "to=".
This is because mon.cgi is just dropping the output into a web page, where the browser parses it for HTML. Years ago we added a call to HTML::Entities:encode_entities to mon.cgi so that messages typed in with the ACK command would not get confused with HTML - the attached patch extends that functionality to monitor output. There are security implications here - if an outside party could get control of the output of a Mon script (easy in my case, since the data comes from syslog and includes error messages from a remote host), that outside party could cobble together some HTML that eventually gets executed in the Mon user's browser (i.e. cross-site scripting). The attached patch renames the "untaint_ack_msgs" parameter to "untaint_all_msgs" and, when set, not only untaints ACK messages, but also untaints last_summary and last_detail output before displaying it. I recommend that we remove this parameter completely and always untaint messages before displaying them in the CGI interface - it's the right thing to do. The cost is one more Perl module dependency, but there are already a host of Perl modules needed to run mon and one more is not going to hurt much. I haven't worked on this code for several years so I may have missed something - an extra pair of eyes on this patch would be appreciated. -- Ed
--- mon.cgi.pl 2005-04-21 16:56:29.000000000 -0400 +++ mon2.cgi.pl 2007-07-12 10:32:59.000000000 -0400 @@ -143,7 +143,7 @@ $monhost_and_port_args $monhost_and_port_args_meta $has_read_config $moncgi_config_file $cf_file_mtime $mon11 - $untaint_ack_msgs @show_watch @no_watch $show_watch_strict + $untaint_all_msgs @show_watch @no_watch $show_watch_strict $required_mon_client_version); # Formatting-related global vars use vars qw($BGCOLOR $TEXTCOLOR $LINKCOLOR $VLINKCOLOR @@ -224,7 +224,7 @@ $cookie_name = "mon-cookie"; #name of cookie given to browser for auth $cookie_path = "/"; # path for auth cookie # Set this to "" for auto-path set - $untaint_ack_msgs = "yes"; # Use HTML::Entities to scrub user-supplied ack messages (recommended!) + $untaint_all_msgs = "yes"; # Use HTML::Entities to scrub user-supplied ack messages (recommended!) # Define optional regexes in the @show_watch variable, # and only hostgroups which match one of these regexes # will be shown. @@ -367,10 +367,10 @@ # # Used to escape HTML in ack's # -if ($untaint_ack_msgs =~ /^y(es)?$/i) { +if ($untaint_all_msgs =~ /^y(es)?$/i) { eval "use HTML::Entities" ; } else { - undef $untaint_ack_msgs; + undef $untaint_all_msgs; } @@ -1104,7 +1104,7 @@ # user requested it, otherwise, just pass it on through # as is. if ( $op{$group}{$service}{'ack'} != 0 ) { - if ($untaint_ack_msgs) { + if ($untaint_all_msgs) { # # We untaint # @@ -1186,7 +1186,8 @@ $webpage->print("<td align=left bgcolor=\"$td_bg_color\">"); $webpage->print("$service_disabled_string<a href=\"$url?${monhost_and_port_args}command=svc_details&args=$group,$service\">"); $webpage->print("<font size=+1><b>${service}</b></font></a>${desc_string} : \n"); - $webpage->print("<font size=+1>$s->{last_summary}</font>\n"); + $webpage->print("<font size=+1>" . + $untaint_all_msgs ? HTML::Entities::encode_entities($s->{last_summary}) : $s->{last_summary} . "</font>\n"); $webpage->print("<br>($failure_string)"); $webpage->print(" ${service_acked_string}") if $service_acked_string ne ""; $webpage->print("</td>\n"); @@ -1642,9 +1643,18 @@ $webpage->print("</td></tr>"); # Now print the detail and summary information for the failed service - $op{$group}->{$service}->{'last_summary'} = "<not specified>" if $op{$group}->{$service}->{'last_summary'} eq "" ; - $op{$group}->{$service}->{'last_detail'} = "<not specified>" if $op{$group}->{$service}->{'last_detail'} eq "" ; - $op{$group}->{$service}->{'last_detail'} =~ s/\n/<BR>/g; + if ($op{$group}->{$service}->{'last_summary'} eq "") { + $op{$group}->{$service}->{'last_summary'} = "<not specified>"; + } elsif ($untaint_all_msgs) { + $op{$group}->{$service}->{'last_summary'} = HTML::Entities::encode_entities($op{$group}{$service}{'last_summary'}) + } + if ($op{$group}->{$service}->{'last_detail'} eq "" ) { + $op{$group}->{$service}->{'last_detail'} = "<not specified>" + } elsif ($untaint_all_msgs) { + $op{$group}->{$service}->{'last_detail'} = HTML::Entities::encode_entities($op{$group}{$service}{'last_detail'}) + } else { # not much of an untaint + $op{$group}->{$service}->{'last_detail'} =~ s/\n/<BR>/g; + }; $webpage->print("<tr><td width=25%><font size=+1 color=\"$font_color\">Failure summary</font>:</td><td>$op{$group}->{$service}->{'last_summary'}</td></tr>\n"); $webpage->print("<tr><td width=25%><font size=+1 color=\"$font_color\">Failure detail</font>:</td><td>$op{$group}->{$service}->{'last_detail'}</td></tr>\n"); $webpage->print("</table>"); @@ -3651,8 +3661,8 @@ return 0; } $dtlog_max_failures_per_page = $val; - } elsif ($key eq "untaint_ack_msgs") { - $untaint_ack_msgs = $val; + } elsif ($key eq "untaint_all_msgs") { + $untaint_all_msgs = $val; } elsif ($key eq "watch") { push(@show_watch, $val); } elsif ($key eq "show_watch_strict") {
_______________________________________________ mon mailing list mon@linux.kernel.org http://linux.kernel.org/mailman/listinfo/mon