Bugzilla – Attachment 40444 Details for
Bug 14426
SQL Injection in Staff Client
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 14426 : SQL injection in borrowers_out.pl
Bug-14426--SQL-injection-in-borrowersoutpl.patch (text/plain), 16.67 KB, created by
Chris Cormack
on 2015-06-22 07:47:54 UTC
(
hide
)
Description:
Bug 14426 : SQL injection in borrowers_out.pl
Filename:
MIME Type:
Creator:
Chris Cormack
Created:
2015-06-22 07:47:54 UTC
Size:
16.67 KB
patch
obsolete
>From ab8065473f985f53b6e90298f9849151b85f5778 Mon Sep 17 00:00:00 2001 >From: Chris Cormack <chris@bigballofwax.co.nz> >Date: Mon, 22 Jun 2015 19:46:41 +1200 >Subject: [PATCH] Bug 14426 : SQL injection in borrowers_out.pl > >This script needs a total rewrite to be made safe, >removing it until that happens >--- > .../prog/en/includes/reports-menu.inc | 1 - > .../prog/en/modules/reports/borrowers_out.tt | 137 ---------- > .../prog/en/modules/reports/reports-home.tt | 1 - > reports/borrowers_out.pl | 297 --------------------- > 4 files changed, 436 deletions(-) > delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/reports/borrowers_out.tt > delete mode 100755 reports/borrowers_out.pl > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/reports-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/reports-menu.inc >index 8c4fe9f..fd28373 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/reports-menu.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/reports-menu.inc >@@ -22,7 +22,6 @@ > > <h5>Inactive</h5> > <ul> >- <li><a href="/cgi-bin/koha/reports/borrowers_out.pl">Patrons who haven't checked out</a></li> > <li><a href="/cgi-bin/koha/reports/catalogue_out.pl">Items with no checkouts</a></li> > </ul> > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/borrowers_out.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/borrowers_out.tt >deleted file mode 100644 >index bc6e6b2..0000000 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/borrowers_out.tt >+++ /dev/null >@@ -1,137 +0,0 @@ >-[% INCLUDE 'doc-head-open.inc' %] >-<title>Koha › Reports › Patrons with no checkouts</title> >-[% INCLUDE 'doc-head-close.inc' %] >-[% INCLUDE 'calendar.inc' %] >-<script type="text/javascript"> >-//<![CDATA[ >-$(document).ready(function(){ >- $("#to").datepicker({ maxDate: "-1D" }); >-}); >-//]]> >-</script> >-</head> >-<body id="rep_borrowers_out" class="rep"> >-[% INCLUDE 'header.inc' %] >-[% INCLUDE 'cat-search.inc' %] >- >-<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/reports/reports-home.pl">Reports</a> › Patrons with no checkouts</div> >- >-<div id="doc3" class="yui-t2"> >- >- <div id="bd"> >- <div id="yui-main"> >- <div class="yui-b"> >- >-[% IF ( do_it ) %] >- [% FOREACH mainloo IN mainloop %] >- <h1>Patrons with no checkouts</h1> >- [% IF ( mainloo.loopfilter ) %] >- <p>Filtered on:</p> >- [% FOREACH loopfilte IN mainloo.loopfilter %] >- <p>[% IF ( loopfilte.err ) %] [% END %] [% loopfilte.crit %] =[% loopfilte.filter %][% IF ( loopfilte.err ) %] [% END %]</p> >- [% END %] >- [% END %] >- >- <table> >- <tr> >- <th>Num/Patrons</th> >- [% FOREACH loopco IN mainloo.loopcol %] >- <th>[% loopco.coltitle %]</th> >- [% END %] >- </tr> >- [% FOREACH loopro IN mainloo.looprow %] >- [% UNLESS ( loop.odd ) %] >- <tr class="highlight"> >- [% ELSE %] >- <tr> >- [% END %] >- <td>[% loopro.rowtitle %]</td> >- [% FOREACH loopcel IN loopro.loopcell %] >- <td>[% IF ( loopcel.value ) %][% loopcel.value %][% END %] >- </td> >- [% END %] >- </tr> >- [% END %] >- </table> >- [% END %] >-[% ELSE %] >- <h1>Patrons with no checkouts</h1> >- <form method="post" action="/cgi-bin/koha/reports/borrowers_out.pl"> >- <fieldset class="rows"> >- <ol> >- <li><label for="patroncategory">Patron category: </label> <select name="Filter" id="patroncategory"><option value="" > Any category code</option> >- [% FOREACH borcatloo IN borcatloop %] >- <option value="[% borcatloo.value %]" >[% borcatloo.description %] </option> >- [% END %] >- </select> >-</li> >- <li><label for="to">Not checked out since: </label> <input size="10" id="to" name="Filter" value="" type="text" /> >-</li> >- </ol> >- </fieldset> >- >- <fieldset class="rows"> >- <legend>Limits</legend> >- <ol> >- <li><label for="numberlimit">Limit to: </label><select name="Limit" id="numberlimit"> >- <option value ="" selected="selected">None</option> >- <option value ="5"> 5</option> >- <option value ="10">10</option> >- <option value ="15">15</option> >- <option value ="20">20</option> >- <option value ="25">25</option> >- <option value ="40">40</option> >- <option value ="50">50</option> >- <option value ="100">100</option> >- </select></li> >- <li><label for="criteria">By: </label><select name="Criteria" id="criteria"> >- <option value ="" selected="selected">None</option> >- <option value ="categorycode">Patron category</option> >- <option value ="branchcode">Library</option> >- </select></li> >- </ol> >- </fieldset> >- >-<fieldset class="rows"> >- <legend>Output</legend> >- <ol> >- <li> >- <label for="outputscreen">To screen into the browser: </label><input type="radio" checked="checked" name="output" id="outputscreen" value="screen" /> >- </li> >- <li> >- <label for="outputfile">To a file:</label> <input type="radio" name="output" value="file" id="outputfile" /> >- <label class="inline" for="basename">Named: </label><input type="text" name="basename" id="basename" value="Export" /> >- <label class="inline" for="MIME">Into an application </label> >- <select name="MIME" id="MIME" size="1"> >- [% FOREACH value IN CGIextChoice %] >- <option value="[% value %]">[% value %]</option> >- [% END %] >- </select> >- <select name="sep" id="sep" size="1"> >- [% FOREACH value IN CGIsepChoice.values.sort() %] >- [% IF ( value == CGIsepChoice.default ) %] >- <option value="[% value %]" selected="selected">[% value %]</option> >- [% ELSE %] >- <option value="[% value %]">[% value %]</option> >- [% END %] >- [% END %] >- </select> >- </li> >- </ol> >- </fieldset> >- >- <fieldset class="action"> >- <input type="submit" value="Submit" /> >- <input type="hidden" name="report_name" value="[% report_name %]" /> >- <input type="hidden" name="do_it" value="1" /> >- </fieldset> >- </form> >-[% END %] >- >-</div> >-</div> >-<div class="yui-b"> >-[% INCLUDE 'reports-menu.inc' %] >-</div> >-</div> >-[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/reports-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/reports-home.tt >index fde9ad3..7ba81d2 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/reports-home.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/reports-home.tt >@@ -54,7 +54,6 @@ > > <h2>Inactive</h2> > <ul> >- <li><a href="/cgi-bin/koha/reports/borrowers_out.pl">Patrons who haven't checked out</a></li> > <li><a href="/cgi-bin/koha/reports/catalogue_out.pl">Items with no checkouts</a></li> > </ul> > >diff --git a/reports/borrowers_out.pl b/reports/borrowers_out.pl >deleted file mode 100755 >index 7ca848a..0000000 >--- a/reports/borrowers_out.pl >+++ /dev/null >@@ -1,297 +0,0 @@ >-#!/usr/bin/perl >- >-# Copyright 2000-2002 Katipo Communications >-# >-# This file is part of Koha. >-# >-# Koha is free software; you can redistribute it and/or modify it >-# under the terms of the GNU General Public License as published by >-# the Free Software Foundation; either version 3 of the License, or >-# (at your option) any later version. >-# >-# Koha is distributed in the hope that it will be useful, but >-# WITHOUT ANY WARRANTY; without even the implied warranty of >-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >-# GNU General Public License for more details. >-# >-# You should have received a copy of the GNU General Public License >-# along with Koha; if not, see <http://www.gnu.org/licenses>. >- >-use strict; >-use warnings; >- >-use CGI qw ( -utf8 ); >-use C4::Auth; >-use C4::Context; >-use C4::Koha; >-use C4::Output; >-use C4::Circulation; >-use C4::Reports; >-use C4::Members; >-use C4::Dates qw/format_date_in_iso/; >- >-=head1 NAME >- >-reports/borrowers_out.pl >- >-=head1 DESCRIPTION >- >-Plugin that shows a stats on borrowers >- >-=cut >- >-my $input = new CGI; >-my $do_it=$input->param('do_it'); >-my $fullreportname = "reports/borrowers_out.tt"; >-my $limit = $input->param("Limit"); >-my $column = $input->param("Criteria"); >-my @filters = $input->param("Filter"); >-$filters[1] = format_date_in_iso($filters[1]) if $filters[1]; >-my $output = $input->param("output"); >-my $basename = $input->param("basename"); >-our $sep = $input->param("sep") || ''; >-$sep = "\t" if ($sep eq 'tabulation'); >-my ($template, $borrowernumber, $cookie) >- = get_template_and_user({template_name => $fullreportname, >- query => $input, >- type => "intranet", >- authnotrequired => 0, >- flagsrequired => {reports => '*'}, >- debug => 1, >- }); >-$template->param(do_it => $do_it, >- ); >-if ($do_it) { >-# Displaying results >- my $results = calculate($limit, $column, \@filters); >- if ($output eq "screen"){ >-# Printing results to screen >- $template->param(mainloop => $results); >- output_html_with_http_headers $input, $cookie, $template->output; >- exit; >- } else { >-# Printing to a csv file >- print $input->header(-type => 'application/vnd.sun.xml.calc', >- -encoding => 'utf-8', >- -attachment=>"$basename.csv", >- -filename=>"$basename.csv" ); >- my $cols = @$results[0]->{loopcol}; >- my $lines = @$results[0]->{looprow}; >-# header top-right >- print "num /". @$results[0]->{column} .$sep; >-# Other header >- foreach my $col ( @$cols ) { >- print $col->{coltitle}.$sep; >- } >- print "Total\n"; >-# Table >- foreach my $line ( @$lines ) { >- my $x = $line->{loopcell}; >- print $line->{rowtitle}.$sep; >- foreach my $cell (@$x) { >- my $cellvalue = defined $cell->{value} ? $cell->{value}.$sep : ''.$sep; >- print $cellvalue; >- } >-# print $line->{totalrow}; >- print "\n"; >- } >-# footer >- print "TOTAL"; >- $cols = @$results[0]->{loopfooter}; >- foreach my $col ( @$cols ) { >- print $sep.$col->{totalcol}; >- } >- print $sep.@$results[0]->{total}; >- exit; >- } >-# Displaying choices >-} else { >- my $dbh = C4::Context->dbh; >- my @values; >- my %labels; >- my %select; >- my $req; >- >- my $CGIextChoice = ( 'CSV' ); # FIXME translation >- my $CGIsepChoice = GetDelimiterChoices; >- >- my ($codes,$labels) = GetborCatFromCatType(undef,undef); >- my @borcatloop; >- foreach my $thisborcat (sort keys %$labels) { >- my %row =(value => $thisborcat, >- description => $labels->{$thisborcat}, >- ); >- push @borcatloop, \%row; >- } >- $template->param( >- CGIextChoice => $CGIextChoice, >- CGIsepChoice => $CGIsepChoice, >- borcatloop =>\@borcatloop, >- ); >-output_html_with_http_headers $input, $cookie, $template->output; >-} >- >- >-sub calculate { >- my ($line, $column, $filters) = @_; >- my @mainloop; >- my @loopfooter; >- my @loopcol; >- my @loopline; >- my @looprow; >- my %globalline; >- my $grantotal =0; >-# extract parameters >- my $dbh = C4::Context->dbh; >- >-# Filters >-# Checking filters >-# >- my @loopfilter; >- for (my $i=0;$i<=2;$i++) { >- my %cell; >- if ( @$filters[$i] ) { >- if (($i==1) and (@$filters[$i-1])) { >- $cell{err} = 1 if (@$filters[$i]<@$filters[$i-1]) ; >- } >- $cell{filter} .= @$filters[$i]; >- $cell{crit} .="Bor Cat" if ($i==0); >- $cell{crit} .="Without issues since" if ($i==1); >- push @loopfilter, \%cell; >- } >- } >- my $colfield; >- my $colorder; >- if ($column){ >- $column = "borrowers.".$column if $column=~/categorycode/ || $column=~/branchcode/; >- my @colfilter ; >- $colfilter[0] = @$filters[0] if ($column =~ /category/ ) ; >- # $colfilter[0] = @$filters[11] if ($column =~ /sort2/ ) ; >- #warn "filtre col ".$colfilter[0]." ".$colfilter[1]; >- >- # loop cols. >- $colfield .= $column; >- $colorder .= $column; >- >- my $strsth2; >- $strsth2 .= "select distinct $colfield FROM borrowers WHERE 1"; >- if ($colfilter[0]) { >- $colfilter[0] =~ s/\*/%/g; >- $strsth2 .= " and $column LIKE '$colfilter[0]' " ; >- } >- $strsth2 .=" group by $colfield"; >- $strsth2 .=" order by $colorder"; >- # warn "". $strsth2; >- >- my $sth2 = $dbh->prepare( $strsth2 ); >- $sth2->execute; >- while (my ($celvalue) = $sth2->fetchrow) { >- my %cell; >- # my %ft; >- # warn "coltitle :".$celvalue; >- $cell{coltitle} = $celvalue; >- # $ft{totalcol} = 0; >- push @loopcol, \%cell; >- } >- # warn "fin des titres colonnes"; >- } >- >- my $i=0; >-# my @totalcol; >- >- #Initialization of cell values..... >- my @table; >- >-# warn "init table"; >- if($line) { >- for (my $i=1;$i<=$line;$i++) { >- foreach my $col ( @loopcol ) { >- $table[$i]->{($col->{coltitle})?$col->{coltitle}:"Global"}=0; >- } >- } >- } >- >- >-# preparing calculation >- my $strcalc ; >- >-# Processing calculation >- $strcalc .= "SELECT CONCAT( borrowers.surname , \"\\t\",borrowers.firstname, \"\\t\", borrowers.cardnumber)"; >- $strcalc .= " , $colfield " if ($colfield); >- $strcalc .= " FROM borrowers "; >- $strcalc .= "WHERE 1 "; >- @$filters[0]=~ s/\*/%/g if (@$filters[0]); >- $strcalc .= " AND borrowers.categorycode like '" . @$filters[0] ."'" if ( @$filters[0] ); >- >- $strcalc .= " AND NOT EXISTS (SELECT * FROM issues WHERE issues.borrowernumber=borrowers.borrowernumber "; >- $strcalc .= " AND issues.timestamp> '" . @$filters[1] . "'" if (@$filters[1]); >- $strcalc .= ") "; >- $strcalc .= " AND NOT EXISTS (SELECT * FROM old_issues WHERE old_issues.borrowernumber=borrowers.borrowernumber "; >- $strcalc .= " AND old_issues.timestamp> '" . @$filters[1] . "'" if (@$filters[1]); >- $strcalc .= ") "; >- $strcalc .= " group by borrowers.borrowernumber"; >- $strcalc .= ", $colfield" if ($column); >- $strcalc .= " order by $colfield " if ($colfield); >- my $max; >- if ($line) { >- if (@loopcol) { >- $max = $line*@loopcol; >- } else { $max=$line;} >- $strcalc .= " LIMIT 0,$max"; >- } >- >- my $dbcalc = $dbh->prepare($strcalc); >- $dbcalc->execute; >-# warn "filling table"; >- my $previous_col; >- $i=1; >- while (my @data = $dbcalc->fetchrow) { >- my ($row, $col )=@data; >- $col = "zzEMPTY" if (!defined($col)); >- $i=1 if (($previous_col) and not($col eq $previous_col)); >- $table[$i]->{$col}=$row; >-# warn " $i $col $row"; >- $i++; >- $previous_col=$col; >- } >- >- push @loopcol,{coltitle => "Global"} if not($column); >- >- $max =(($line)?$line:@table -1); >- for ($i=1; $i<=$max;$i++) { >- my @loopcell; >- #@loopcol ensures the order for columns is common with column titles >- # and the number matches the number of columns >- my $colcount=0; >- foreach my $col ( @loopcol ) { >- my $value; >- if (@loopcol){ >- $value =$table[$i]->{(($col->{coltitle} eq "NULL") or ($col->{coltitle} eq "Global"))?"zzEMPTY":$col->{coltitle}}; >- } else { >- $value =$table[$i]->{"zzEMPTY"}; >- } >- push @loopcell, {value => $value} ; >- } >- push @looprow,{ 'rowtitle' => $i , >- 'loopcell' => \@loopcell, >- }; >- } >- >- >- >- # the header of the table >- $globalline{loopfilter}=\@loopfilter; >- # the core of the table >- $globalline{looprow} = \@looprow; >- $globalline{loopcol} = \@loopcol; >-# # the foot (totals by borrower type) >- $globalline{loopfooter} = \@loopfooter; >- $globalline{total}= $grantotal; >- $globalline{line} = $line; >- $globalline{column} = $column; >- push @mainloop,\%globalline; >- return \@mainloop; >-} >- >-1; >-__END__ >-- >2.1.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 14426
:
40444
|
40448
|
40494
|
40502