Reputation: 1197
Let's say that I have a Perl script which contains a substitution command which takes replacement string as a positional parameter and uses /e
modifier:
perl -pe 's/abc/$ARGV[0]/ge;'
Are there any security concerns with this approach? I mean is it possible to give such positional parameter value which causes perl to execute an unwanted function? I mean something similar: perl -pe 's/abc//;unlink ("/tmp/file");'
.
Upvotes: 5
Views: 299
Reputation: 386541
Unlike /ee
, there's no inherent risk to /e
as it doesn't invoke the Perl parser. It simply causes code in the source file to be evaluated, just like how map BLOCK LIST
and for (LIST) BLOCK
evaluate their BLOCK
.
Note that
s{$foo}{$bar}g
is simply short for
s{$foo}{ qq{$bar} }eg
So if you're ok with
perl -pe's/abc/$ARGV[0]/g'
then you're ok with
perl -pe's/abc/"$ARGV[0]"/eg'
and the virtually identical
perl -pe's/abc/$ARGV[0]/eg'
Upvotes: 3
Reputation: 126752
perl -pe 's/abc/$ARGV[0]/ge'
Are there any security concerns with this approach? I mean is it possible to give such positional parameter value which causes perl to execute an unwanted function?
In
perldoc perlop
in the section
Regexp Quote-Like Operators
it explains
eval
the result.But this isn't entirely true. In both cases the "right side"—the replacement—is evaluated as if it were a do
block†. In the first case the result provides the replacement string, while in the second the result is passed to eval
and the result of that provides the replacement string. There is no distinction whereby the replacement is evaluated as an "expression" in the first place and as a "string" in the second.
Both /e
and /ee
allow for any valid Perl code sequence, including loops, conditionals, and multiple statements, and aren't limited to a single expression
There's never anything wrong with $ARGV[0]
in isolation. Tainted strings become dangerous only if you execute them, either as Perl, using eval
, or as shell code using system
, qx//
, or backticks. So it's fine in the replacement part of a substitution with a single /e
modifier
But if you use something else in the replacement, for instance
perl -pe 's/abc/qx{$ARGV[0]}/eg'
then that parameter will be executed as a shell command, so it clearly isn't safe. But then nor is
perl -pe 's/abc/unlink glob "*.*"/eg'
so you have to be sensible about it
What is dangerous is the double-e modifier /ee
, which treats the replacement as a Perl do
block and then does an eval
on the result. So something like
s/abc/$ARGV[0]/eeg
is very unsafe, because you could run your code like this
perl -pe 's/abc/$ARGV[0]/eeg' 'unlink glob *.*'
With just a single /e
this would just replace abc
with the string
unlink glob *.*
in $ARGV[0]
. But using /ee
, the string is passed to eval
and all your files are deleted!
Remember this:
/e — replacement is an expression (a do
block)
/ee — replacement is an expression (a do
block) and the result is passed to eval
†
This is why I choose to use braces to delimit substitutions that use one of the /e
modes. With
s{abc}{ $ARGV[0] }ge
the replacement looks much more like the block of code that it is than if I had used the usual slashes
Upvotes: 6