The documentation of capurex
, states that the function never invokes the shell .
My assumption: Since no shell is invoked, characters like *
or ;
will not get interpreted and therefore can't do harm. This is why calls to external programs are not (or less) susceptible to accidentally malformed input or intended injection attacks as shown in the example below (sorry for the German output messages):
use v5.26;
use IPC::System::Simple 'capturex';
# (very) vulnerable to shell injection
say `ls @ARGV`;
# just a visual line
say '----------';
# no shell injection "possible" (?)
say capturex('ls', @ARGV);
The output:
user@host:-$ perl shell-injection.pl -1 \*.pl \; hostname
shell-injection.pl
host
----------
ls: Zugriff auf '*.pl' nicht möglich: Datei oder Verzeichnis nicht gefunden
ls: Zugriff auf ';' nicht möglich: Datei oder Verzeichnis nicht gefunden
ls: Zugriff auf 'hostname' nicht möglich: Datei oder Verzeichnis nicht gefunden
"ls" unexpectedly returned exit value 2 at shell-injection.pl line 11.
user@host:-$
My Questions:
What terminologies can be used to describe, how the code is executed with capturex
? What are examples / techniques / terms used in other languages or environments? (eg system call
?)
Is it actually advisable to use this technique without input checking (I assume not) and if not, for what reason (attack vector)?
The best way to get informed about how capturex
operates is by looking at its source .
The sub implements its own piped open in "list-form", to work around the (ancient.) v5.6.x limitations. It does so by fork
-ing a process using piped open and then "manually" exec
-ing the command in the child, where it can use the list-form. Then the output is read in the parent. Follow the word "pipe" in the open page, and then the link to perlipc .
So there can be no shell involved since exec in the LIST form uses execvp(3)
system call to directly run the command. (What may happen when it runs with a single argument as well, if it contains no shell meta-charactes.) Thus the characters that (would) have a special meaning in the shell may be used freely as literal characters in the command.
As for the second question -- if a command is formed with user-input it must always be checked really carefully, Note that one shouldn't literally use input in a command. but rather support keywords and parameters based on which the program composes the command. Avoiding the shell of course helps but any user input must be checked.
The injection bug is more of a programming error, whereby variable interpolation isn't used right and results in an unintended command; there is no need for malicious acts there, just for the "right" input that exposes the bug.
All capturex
does is save you from having to form a valid shell command. Some validation may still be needed.
What terminologies can be used to describe, how the code is executed with
capturex
?
The source for the latest version of IPC::System::Simple is found here .
On non-Windows systems, capturex
uses the fork
and execve
system calls via the open(my $pipe, '-|')
and exec BLOCK LIST
Perl functions respectively. This form of Perl's exec
function executes the program directly rather than invoking a shell.
exec "ls foo"; # Executes /bin/sh
exec { "/bin/sh" } "/bin/sh", "-c", "ls foo"; # Equivalent to previous.
exec { "ls" } "ls", "foo"; # Executes ls
Is it actually advisable to use this technique without input checking (I assume not) and if not, for what reason (attack vector)?
What if you provide a relative path to the program to execute and the user set the PATH
env var being used?
What if you provide a relative path to a file as an argument and the user set the current work directory?
What if you pass a string that starts with a -
? That could be interpreted as an option rather than argument. (This is why you'd use 'ls', '--', $file
instead of 'ls', $file
.)
What if you pass ../../../../../../etc/passwd
? That could have undesired effect if the program uses the argument in a file path.
What if you pass a regex to a program, and the regular expression would take longer than the lifespan of the universe to fail to match?
It's possible that some validation still needs to occur. All capturex
does is save you from having to form a valid shell command.
It might be the receiving program's job to do the validation, it might be yours, or it might be a combination.
Yes, check the values you send to external commands even if you don't think you are because you have some other security feature in place.
You have two different paths to executing external commands in your example:
*.tmp
is still a glob:system $single_string;
exec $single_string;
capturex
is doing this for you. There's no shell to interpret things such as *.tmp
, so the arguments are their literal values. You'd see the same behavior with the list forms of system
or exec
:system $program, @args;
exec $program, @args
You still have to be careful, because @args
might be empty, so that looks like the single argument form again. There's a special form that handles that for you. It looks like you specify the program twice, but it all works out:
system { $program }, $program, @args;
exec { $program }, $program, @args
I discuss this in detail in Mastering Perl 's "Secure Programming Techniques" chapter, but you can read about some of it in perlsec too.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.