-T Taintcheck OK auf Windows NOT OK auf UNIX
Beat
- perl
0 Alexander (HH)0 Beat0 Alexander (HH)0 Beat1 MudGuard0 Alexander (HH)0 Alexander (HH)0 Beat
0 Beat
Kann mir jemand sagen, warum ein Script, das auf Windows alle Taint-Checks besteht, auf UNIX miserabel abbricht?
Möglicher Hintergrund: Unix unterscheidet sich dadurch, dass der Owner bei einigen Files verschieden ist vom Owner des ausführenden Scripts.
Ich wüsste aber nicht, dass diese eine Rolle spielt.
mfg Beat
Moin Moin!
Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.
perlsec hast Du gelesen und verstanden?
Alexander
Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.
Das ist ja meine alte Kritik an -T. Du bekommst einfach keinen Fehler. Allenfalls Folgefehler von nicht initialisierten Variablen.
Statt dass ein Script sofort abbricht, läuft es Seelenruhig weiter und lässt dich in den Datengau laufen.
perlsec hast Du gelesen und verstanden?
ja jein
mfg Beat
Moin Moin!
Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.
Das ist ja meine alte Kritik an -T. Du bekommst einfach keinen Fehler.
Dann machst Du was falsch. -T bricht Dein Script mit einer Fehlermeldung ab, wenn Du mit getainteten Werten eine der dokumentierten kritischen Funktionen aufrufst.
Allenfalls Folgefehler von nicht initialisierten Variablen.
Nein. Du machst etwas fürchterlich falsch. Hast Du einen eval-Block rund um den Teil des Codes, der die kritischen Funktionen aufruft? Dann sieh Dir mal $@ genauer an! Diese Funktionen erzeugen mit -T bei getainteten Exceptions, und die kannst Du mit eval abfangen. Exakt wie die(), nicht wie exit().
Statt dass ein Script sofort abbricht, läuft es Seelenruhig weiter und lässt dich in den Datengau laufen.
Nein. Getaintete Parameter für die kritischen Funktionen führen sofort zum Abbruch. Du sitzt vermutlich in einem eval-Block.
Was erwartest Du denn, was Perl sonst machen sollte? $ENV{'PATH'} ist tainted. Soll das Script deswegen sofort abbrechen, obwohl $ENV{'PATH'} gar nicht genutzt wird? (Analog z.B. mit $0 und $^X.) Du mußt wenigstens die Chance haben, die Daten zu validieren oder durch saubere Werte zu ersetzen.
perlsec hast Du gelesen und verstanden?
ja jein
Dann um so mehr: Zeig Code!
Alexander
Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.
OK.
Ich habe jetzt einen Fehlerreport
Betrifft dies:
open( my $LOG2, '>', $Files{logfile} ) or die("$!");
Es handelt sich um den einzigen Schreibzugriff.
Ich kann nun zurückverfolgen, warum $Files{logfile} als tainted gilt.
vorher
...
logfile => $Path{__datadir} . 'log.ehf',
...
vorher
$Path{__datadir} = $Path{homedir} . '/' . '__data/';
$Path{homedir} = $Path{root} . $Path{htmldir} .'/'. $Path{ehfdatadir};
vorher
$Path{scriptpath} =~ s#\\#/#g;
( $Path{root}, $Path{cgi}, $Path{scriptname} ) =
( $Path{scriptpath} =~ m!^ (.*?/) ($Path{cgidir}/\w+/) ([a-z]+\.pl)$!x );
vorher
open( my $config, '<','config.ehf' ) or die ("Kann nicht config.ehf lesen $!");
while(<$config>){
...
/^scriptpath\s*=\s*"([^"]+)"/ and $Path{scriptpath} = $1 and next;
...
}
close $config;
und zu vorderst
my %Path = ( #defaults
...
scriptpath => $0,
);
Wie zu sehen wird zwar $0 verwendet, aber $0 wird auf jeden Fall über eine RE gewaschen.
Da ist kein Grund, dass diese Pfade tainted sein dürfen.
Und wieder meine Frage: Warum auf UNIX und nicht auf Windows?
mfg Beat
Hi,
Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.
OK.
Ich habe jetzt einen Fehlerreport
Schön für Dich. Aber wenn Dir geholfen werden soll, wäre es nicht verkehrt, den auch herzuzeigen.
cu,
Andreas
Moin Moin!
Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.
OK.
Ich habe jetzt einen Fehlerreport
Betrifft dies:
open( my $LOG2, '>', $Files{logfile} ) or die("$!");
>
> Es handelt sich um den einzigen Schreibzugriff.
Nö, an der Stelle machst Du ein open(), keinen Schreibzugriff.
Warum muß ich mir den Code rekonstruieren?
Und warum gibst Du nicht alle relevanten Variablen an?
Woher kommt $Path{'homedir'}? Wenn ich mir das aus $ENV{'HOME'} hole, ist $Files{'logfile'} tainted. Und zwar nur unter Unix, weil Windows $ENV{'HOME'} nicht setzt.
> Wie zu sehen wird zwar $0 verwendet, aber $0 wird auf jeden Fall über eine RE gewaschen.
Nö, Du kannst SO nicht waschen. $0 bleibt tainted, bis Du es ÜBERSCHREIBST, und wenn Du noch so oft matcht. Nur die RE-Puffer ($1, $2, ...) sind vom Tainting explizit ausgenommen.
> Da ist kein Grund, dass diese Pfade tainted sein dürfen.
>
> Und wieder meine Frage: Warum auf UNIX und nicht auf Windows?
S.o.
Das ist meine Rekonstruktion Deines Codes, zusammen mit expliziten Taint-Ausgaben. Und die sagt, dass $Files{'logfile'} am Ende tainted ist. Demzufolge verweigert open() die Arbeit und wirft stattdessen eine Exception.
~~~perl
#!/usr/bin/perl -T
use strict;
use warnings;
use Data::Dumper qw();
use Scalar::Util qw(tainted);
sub T
{
my ($name,$val)=@_;
my $line=(caller())[2];
print "$name is ",tainted($val) ? "" : "not ","tainted in lline $line (value=".Data::Dumper::qquote($val).")\n";
}
my %Path=( #defaults
# ...
scriptpath => $0,
homedir => $ENV{'HOME'},
);
T(scriptpath => $Path{'scriptpath'});
open( my $config, '<','config.ehf' ) or die ("Kann nicht config.ehf lesen $!");
while(<$config>){
T('$_' => $_);
/^scriptpath\s*=\s*"([^"]+)"/ and $Path{scriptpath}=$1 and next;
}
close $config;
T(scriptpath => $Path{'scriptpath'});
$Path{scriptpath} =~ s#\\#/#g;
T(scriptpath => $Path{'scriptpath'});
($Path{root},$Path{cgi},$Path{scriptname})=($Path{scriptpath}=~m!^ (.*?/) ($Path{cgidir}/\w+/) ([a-z]+\.pl)$!x);
T(scriptpath => $Path{'scriptpath'});
T(scriptname => $Path{'scriptname'});
T(root => $Path{'root'});
T(cgi => $Path{'cgi'});
$Path{__datadir} = $Path{homedir} . '/' . '__data/';
T(__datadir => $Path{'__datadir'});
$Path{homedir} = $Path{root} . $Path{htmldir} .'/'. $Path{ehfdatadir};
T(homedir => $Path{'homedir'});
my %Files;
$Files{'logfile'}=$Path{__datadir} . 'log.ehf';
T(logfile => $Files{'logfile'});
open( my $LOG2, '>', $Files{logfile} ) or die("$!");
Möchtest Du das Log übrigens wirklich jedes Mal plätten?
Alexander
Moin Moin!
Das ist meine Rekonstruktion Deines Codes, zusammen mit expliziten Taint-Ausgaben. Und die sagt, dass $Files{'logfile'} am Ende tainted ist. Demzufolge verweigert open() die Arbeit und wirft stattdessen eine Exception.
So sieht das aus:
/home/XXX/beat>perl -T beat.pl
scriptpath is tainted in lline 23 (value="beat.pl")
$_ is tainted in lline 27 (value="# config.ehf\n")
$_ is tainted in lline 27 (value="scriptdir=/home/XXX/beat\n")
scriptpath is tainted in lline 32 (value="beat.pl")
scriptpath is tainted in lline 36 (value="beat.pl")
Use of uninitialized value $Path{"cgidir"} in regexp compilation at beat.pl line 38.
scriptpath is tainted in lline 40 (value="beat.pl")
scriptname is not tainted in lline 41 (value="")
root is not tainted in lline 42 (value="")
cgi is not tainted in lline 43 (value="")
__datadir is tainted in lline 47 (value="/home/XXX/__data/")
Use of uninitialized value $Path{"root"} in concatenation (.) or string at beat.pl line 49.
Use of uninitialized value in concatenation (.) or string at beat.pl line 49.
Use of uninitialized value in concatenation (.) or string at beat.pl line 49.
homedir is not tainted in lline 51 (value="/")
logfile is tainted in lline 56 (value="/home/XXX/__data/log.ehf")
Insecure dependency in open while running with -T switch at beat.pl line 58.
Alexander
OK
Ich habe jetzt mal einen wilden patch vorgenommen.
Ich habe $0 ais einer Regex gezogen.
Allerdings muss ich dabei so liberal vorgehen, dass Sicherheit nur besteht, wenn der Anwender den Scriptpfad im configfile vorgibt.
Hier der Beginn des Scripts
#!/usr/bin/perl -T
BEGIN {
use CGI::Carp qw(carpout);
open(LOG, ">>","error.txt") or die "Unable to append to error.txt: $!\n";
carpout(*LOG);
$1.'/EHFPlugins';
}
use warnings;
use strict;
use lib qw(.);
use Digest::SHA1 qw( sha1_hex );
use constant { NL => "\n", CRLF => "\015\012"};
use Storable qw(lock_store lock_retrieve);
use Tie::File;
use Encode qw(encode);
use URI::Escape;
use EHFLang; # Sprachpaket für ehf-Formulare.
my $L = new EHFLang(); # Die Sprache wird nach dem ersten Aufruf von $Store gesetzt
# importiert die Funktion t() translate
# 1.b System Angaben aus config.ehf
my %System = (
runonce=>0,
debug=>0, # Bitmaske: 1 debug; 2 input; 4 cookies; 8 user; 16 files
updatesite=>0,
version=>"0.9.6.pre"
);
my %Path = (
domain => 'localhost',
protokoll=>'http',
htmldir => 'html',
cgidir => 'cgi',
ehfdatadir => 'ehf_html',
scriptpath=>'',
);
$0 =~ /^(.*)$/ and ($Path{scriptpath}) = $1;
my $ruopen=0;
open( my $config, '<','config.ehf' ) or die ("Kann nicht config.ehf lesen $!");
while(<$config>){
/^#/ and next;
/^domain\s*=\s*([a-zA-Z0-9_.-:]+)\s*$/ and $Path{domain} = $1 and next;
/^protokoll\s*=\s*(https?)\s*$/ and $Path{protokoll} = $1 and next;
/^htmldir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{htmldir} = $1 and next;
/^cgidir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{cgidir} = $1 and next;
/^ehfdatadir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{ehfdatadir} = $1 and next;
/^ehfupdatefrom\s*=\s*(\S+)\s*$/ and $System{updatesite} = $1 and next;
/^ehfdebug\s*=\s*([0-9]+)\s*$/ and $System{debug} = $1 and next;
/^scriptpath\s*=\s*"([^"]+)"/ and $Path{scriptpath} = $1 and next;
/^runonce=([1-9])/ and $ruopen = 1;
}
close $config;
# Installations-Zugriff.
if($ruopen){
tie( my @cf , 'Tie::File', 'config.ehf') or die ("Kein Schreibrecht auf config.ehf $!");
foreach(@cf){
if( /^runonce=([1-9])/ ){
$System{runonce} = $1;
$1 gt 3
? ( $_ = 'runonce=0' )
: ( $_ = 'runonce=' . ( $1 + 1 ) );
}
}
untie( @cf );
}
# 1.c Directory Angaben
$Path{scriptpath} =~ s#\\#/#g;
( $Path{root}, $Path{cgi}, $Path{scriptname} ) =
( $Path{scriptpath} =~ m!^ (.*?/) ($Path{cgidir}/\w+/) ([a-z]+\.pl)$!x );
# Der Pfad zum Homedirectory
$Path{homedir} = $Path{root} . $Path{htmldir} .'/'. $Path{ehfdatadir};
# Der Pfad zum CGI Verzeichnis
$Path{cgidir} = $Path{root} . $Path{cgi};
# 1.d URL Angaben
# Das Schema, Domain
$Path{domurl} = $Path{protokoll} . '://' . $Path{domain};
# Die lokale URL zum HTML Verzeichnis, wo die Daten liegen
$Path{home} = $Path{domurl} .'/'. $Path{ehfdatadir};
# Die lokale URL zum CGI Verzeichnis, wo die Script und Module liegen
$Path{cgiurl} = $Path{domurl} . '/'. $Path{cgi};
$Path{scripturl} = $Path{cgiurl} . $Path{scriptname};
# 1.e Ergänzung
$Path{__datadir} = $Path{homedir} . '/' . '__data/';
$Path{__layoutdir} = $Path{homedir} . '/' . '__layouts/';
$Path{__themedir} = $Path{homedir} . '/' . '__themes/';
$Path{__backupdir} = $Path{homedir} . '/' . '__backups/';
$Path{__static} = $Path{homedir} . '/' . '__static/';
$Path{userdata} = $Path{homedir} . '/' . 'userdata/';
Das Script läuft jetzt auch auf dem UNIX mit -T.
Allerdings muss ich noch aller Routinen testen.
Warum muß ich mir den Code rekonstruieren?
Warum solltest du dir in 5000 Zeilen Code irgend eine raussuchen?
Wenn du der Message nicht vertraust, welche Argumente hast du dann?
Und warum gibst Du nicht alle relevanten Variablen an?
Wie meinen?
Woher kommt $Path{'homedir'}? Wenn ich mir das aus $ENV{'HOME'} hole, ist $Files{'logfile'} tainted. Und zwar nur unter Unix, weil Windows $ENV{'HOME'} nicht setzt.
Ach Schneusel. Es kommt aus einem File, alles via Regex weissgewaschen.
open( my $config, '<','config.ehf' ) or die ("Kann nicht config.ehf lesen $!");
while(<$config>){
/^#/ and next;
/^domain\s*=\s*([a-zA-Z0-9_.-:]+)\s*$/ and $Path{domain} = $1 and next;
/^protokoll\s*=\s*(https?)\s*$/ and $Path{protokoll} = $1 and next;
/^htmldir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{htmldir} = $1 and next;
/^cgidir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{cgidir} = $1 and next;
/^ehfdatadir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{ehfdatadir} = $1 and next;
/^ehfupdatefrom\s*=\s*(\S+)\s*$/ and $System{updatesite} = $1 and next;
/^ehfdebug\s*=\s*([0-9]+)\s*$/ and $System{debug} = $1 and next;
/^scriptpath\s*=\s*"([^"]+)"/ and $Path{scriptpath} = $1 and next;
/^runonce=([1-9])/ and $ruopen = 1;
}
close $config;
Hier werden alle Bestandteile, aus welchen Pfade hergeleitet werden, konsequent gewaschen.
Wie zu sehen wird zwar $0 verwendet, aber $0 wird auf jeden Fall über eine RE gewaschen.
Nö, Du kannst SO nicht waschen. $0 bleibt tainted, bis Du es ÜBERSCHREIBST, und wenn Du noch so oft matcht. Nur die RE-Puffer ($1, $2, ...) sind vom Tainting explizit ausgenommen.
Sag ich ja, Angaben aus $0 werden via Regex herausgezogen, falls die Variable, die $0 speichert, nicht über das config file überschrieben wird
open( my $LOG2, '>', $Files{logfile} ) or die("$!");
[/code]Möchtest Du das Log übrigens wirklich jedes Mal plätten?
Aber sicher!
Ich habe im Moment noch eine andere Baustelle,
da die UNIX Perl Version (5.8.0) anscheinend Mühe mit
print $fh somefunc()
hat.
Ganz seltsames Verhalten und nicht durchgängig der Fall.
mfg Beat