> In my PERL code,I am using user's input as command line argument for the
> program being executed by System().
> Can user run command of his choice by giving malicious input?
> Is PERL's -T (Taint mode) the solution for this?
Using Taint mode is a good thing. However you can still easily
untaint inappropriately:
$user_filename = $q->param('filename');
$user_filename =~ /^ (.*) $/x;
$filename = $1;
system "/bin/ls $filename";
Sure, the filename submitted by the user was untainted and put into
$filename. But since the untainting didn't do anything to actually
check the input (it was just extracted via $1, no checks or munging
whatsoever) a user could easily supply "/etc/passwd; rm -rf /"
as a filename and system will happily process it.
Lesson 1: do real untainting. Make sure the filename looks
exactly like you want it:
$user_filename =~ /^ ([a-zA-Z]+) $/x;
This would allow files that are 100% alphabetic, for example.
No shell metacharacters, no parent (..) directories, or any
directory (/) stuff at all.
Naturally, what a 'valid' value is depends on your needs.
Lesson 2: say what is valid, don't decide what isn't valid.
The best untainting is when you explicitly say what is all right.
If you were trying to extract a suitable filename (anywhere
on the filesystem, including the use of .. and /'s) you'd want
something like this:
/^ ( [\w./]+ ) $/x;
which details exactly what you'd consider valid. If instead
you try to get rid of 'bad' data, such as shell expansion
characters:
/^ ( [^;\$&]+ ) $/x;
Then you're liable to miss some. For example "*" is missing
from the above list.
Lesson 3: always use the array form of system in perl.
System will pass your command to /bin/sh if it thinks there
are shell metacharacters to expand. If you're using user
input, don't do this. (Heck, never do this - it's poor
form anyway.) Instead, use the array version, which will
do a fork/exec of your command explicitly, and never run
the shell. Thus you'd want to have
system( "/bin/ls", $filename);
If somehow your untainting failed, and the user was allowed
to supply "/etc/passwd; rm -rf /" for the filename, you would
end up running
ls "/etc/passwd; rm -rf /"
And, assuming you don't have a file named "/etc/passwd; rm -rf /"
ls will simply complain that no such file exists.
Short answer: unless you program with lots of paranoia, any
programming language can be abused, perl included.
--
Brian Hatch "I've got as much chance of
Systems and doing that as seeing a
Security Engineer Vorlon doing strip-tease."
http://www.ifokr.org/bri/
Every message PGP signed
This archive was generated by hypermail 2b30 : Wed Jan 22 2003 - 14:27:32 PST