bash - How to prevent malicious code execution via input?

Asked

Viewed 154 times

3

I own a script (script.sh) who receives a environment variable:

echo $MINHAVARIAVEL

But when calling it via terminal, I realized that I can pass commands through this variable, and these commands are executed without checks to style sql Injection. Example:

home$ MINHAVARIAVEL=$(rm -rf /etc) script.sh 

Instead of treating the variable as a string, my script would treat it as a command, inject it into the instruction, and execute it, opening precedents for security holes.

How do I avoid running malicious code on environment variables? Or: How I force my environment variable to be interpreted only as a harmless "string"?

  • This "injection" code already occurs at the time of assignment. Expanding the variable will not execute the rm -rf

  • it is. when you put a command between $() he is executed immediately. in that case there, $MINHAVARIAVEL contains the result of rm, and that is what is passed to the script’s enironment. Executing a string as a command is the role of the eval (with all the risks inherent to its use)

1 answer

5


The data entry proposed in the question causes code execution before passing the variable to the script.

The use of subshell $() executes the command immediately and replaces its result in the string:

nunks@yokoi:~$ TESTE="Diretorio atual: $(pwd)"
nunks@yokoi:~$ echo $TESTE
Diretorio atual: /home/nunks

Thus, the proposed execution is first removing the /etc and then calling the script. It is not the script that executes malicious code, it is the proper assignment of $MINHAVARIVEL user-made.

To make the script cause this malicious execution, you would need to make (ill-)use of eval:

#!/bin/bash
#script.sh
eval $MINHAVARIAVEL;

~$ MIN='rm -Rf /etc' . /script.sh


Mandatory notice on the use of eval

Rebound here that, as a rule, should not be used eval for nothing. The above example is just one case in which its use represents a security breach. It is virtually impossible to guarantee the validity of all inputs (malicious users tend to be quite smart), being much better to interpret the user’s data entry and define what will run within the script. It is inherently unsafe to allow the user to execute operating system commands within his script.


Use of control replacement $(comando) or `comando`

Opening a subshell within parentheses $(comando) or severe accents `comando` is called by the bash of control override: the command in question is evaluated first and its return is passed to the "out" command, being very useful for assigning variables dynamically.

It is important to stress that this kind of expansion works as eval, and shall be treated with the same care. The above malicious execution can also be triggered with replacements:

#!/bin/bash
#script.sh
echo $($MINHAVARIAVEL);

~$ MIN='rm -Rf /etc' . /script.sh


Use of process substitution <(comando) and >(comando)

The bash also provides process substitution, enabling them to function as "files" by creating dynamic Fifos or "numbered" files in the /dev/fd. This is very practical to, for example, work with the output of complex pipelines without the need to first store them in file.

The entire overwrite is used as if it were a file, and the command passed between parentheses is evaluated and executed as in the command overwrites mentioned above, but its output is sent to a temporary file or FIFO to be read immediately by the process that called it. So, also works as eval and should also be used with care. Example of the same above malicious execution, now with process overwriting:

#!/bin/bash
#script.sh
cat <($MINHAVARIAVEL);

~$ MIN='rm -Rf /etc' . /script.sh


Therefore...

There is more than one way to execute code contained in variables in bash, and none of them should be used without having control of what is inside the variable in question. They’re all as dangerous as the eval.

This serves primarily as a warning that user input should never be used as data, and should always be checked. Strictly define the "format" or "type" of input data and, first of all, check if they fit within the expected.

Verification of input data

That said, it is always important to clean the data entries to avoid not only malicious use, but also many bugs inherent to the creativity of the user in choosing the data to pass to the script.

The bash offers several types of testing to facilitate the identification of variables, such as the test to see if it points to an existing file path (-a):

#!/bin/bash
if [[ ! -a $MINHAVARIAVEL ]]; then
  echo MINHAVARIAVEL deve ser um arquivo!;
  exit 1;
fi;

For cases where the format of the string passed is known and strict, I usually use regular expressions. Example with date string:

#!/bin/bash
if [[ ! $ANOMESDIA =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
  #sei que a regex acima e bastante simploria para teste de data,
  #trata-se de mero exemplo
  echo O formato de ANOMESDIA deve ser AAAA-MM-DD!;
  exit 1;
fi;

In order to make life easier for the end user, my scripts tend to contain a mountain of tests before starting the actual execution, seeking to ensure that the input data is entered in a format defined as strictly as possible. At each false test I offer an error explanatory message and a basic help of the command, then finish with error code:

#!/bin/bash
#testaidade.sh

help() {
  echo
  echo Ajuda:
  echo Passe sua idade para script!;
  echo Exemplo: $0 22;
}
IDADE=$1;

if [[ -z $IDADE ]]; then #$IDADE está vazia
  help;
  exit 1;
fi;
if [[ ! $IDADE =~ ^[0-9]+$ ]]; then
  echo Sua idade deve ser um valor numérico.;
  help;
  exit 1;
fi;
echo Idade testada. O valor informado foi $IDADE;

Thus, you can manipulate the information in your script without any extra concern as to the integrity of the entries informed by the user.

  • So it’s "impossible" for the user to pass malicious code via input that ends up running, right? Unless I use eval (or other explicit execution command in input), I am protected and can handle the input without fear of code injected into my script?

  • 2

    The way you asked the question, malicious code is executed, yes, but at the time of variable assignment, in the $() command expansion subshell, and not by the script. That being said, as long as your script does not run input strings without first checking them, you can rest easy. It is protected as long as it does not jump from the plane without checking if it is using parachute, haha.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.