简体   繁体   中英

How does IPC::System::Simple capturex work?

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:

  1. 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 ?)

  2. 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:

  1. Pass the shell a single string. In backticks, Perl constructs the entire command, and if it looks like the shell needs to handle it (globs, etc), the shell gets a chance to stick its fingers in. The shell then figures out what the command means, interprets its arguments, and does the work. So, the *.tmp is still a glob:
system $single_string;
exec $single_string;
  1. Pass a list to the system and execute the command directly, with no shell in the way. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM