Conséquences pour la sécurité de l'utilisation de données non stérilisées dans l'évaluation Shell Arithmetic

17

Dans un commentaire à une question récente , Stéphane Chazelas mentionne qu'il y a des implications sécuritaires à l'arithmétique des parenthèses doubles telles que:

x=$((1-$x))

sur la plupart des coquilles.

Mes compétences Google semblent rouillées et je ne trouve rien. Quelles sont les implications pour la sécurité de l'arithmétique des doubles parenthèses?

garethTheRed
la source

Réponses:

22

Le problème se pose dans les cas où le contenu de $xn'a pas été filtré et contient des données qui pourraient potentiellement être sous le contrôle d'un attaquant dans les cas où le code shell pourrait finir par être utilisé dans un contexte d'escalade de privilèges (par exemple un script appelé par un setuid application, un script sudoers ou utilisé pour traiter des données off-the-network (CGI, hook DHCP ...) directement ou indirectement).

Si:

x='(PATH=2)'

Alors:

x=$((1-$x)))

a pour effet secondaire de se mettre PATHsur 2(un chemin relatif qui pourrait très bien être sous le contrôle de l'attaquant). Vous pouvez remplacer PATHpar LD_LIBRARY_PATHou IFS... La même chose se produit avec x=$((1-x))en bash, zsh ou ksh (pas dash ni yash qui n'acceptent que les constantes numériques dans les variables).

Notez que:

x=$((1-$x))

ne fonctionnera pas correctement pour les valeurs négatives de $xdans certains shells qui implémentent l' --opérateur ( optionnel selon POSIX) (décrément) (comme avec x=-1, cela signifie demander au shell d'évaluer l' 1--1expression arithmétique). "$((1-x))"n'a pas le problème car il xest développé dans le cadre (pas avant) de l'évaluation arithmétique.

Dans bash, zshet ksh(pas dashou yash), si xest:

x='a[0$(uname>&2)]'

Ensuite, l'expansion de $((1-$x))ou $((1-x))provoque unamel'exécution de cette commande (pour zsh, adoit être une variable de tableau, mais on peut l'utiliser psvarpar exemple pour cela).

En résumé, on ne doit pas utiliser ou non initialisées données externes non aseptisé dans les expressions arithmétiques dans les coquilles (notez que l' évaluation arithmétique peut être fait par $((...))(alias $[...]dans bashou zsh) , mais aussi en fonction de la coquille dans le let, [/ test, declare/typeset/export..., return, break, continue, exit, printf, les commandes printintégrées, les indices de tableau ((..))et les [[...]]constructions pour n'en nommer que quelques-uns).

Pour vérifier qu'une variable contient un nombre entier décimal littéral, vous pouvez utiliser POSIXly:

case $var in
  ("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac

Attention, [0-9]dans certains pays, les correspondances à plus de 0123456789. [[:digit:]]devraient être OK mais je ne parierais pas dessus.

Rappelez-vous également que les nombres avec des zéros en tête sont traités comme octaux dans certains contextes ( 010parfois 10, parfois 8) et attention à ce que la vérification ci-dessus laisse passer des nombres potentiellement plus grands que l'entier maximum pris en charge par votre système (ou quelle que soit l'application que vous utiliserez) utilisez cet entier dans; bash par exemple traite 18446744073709551616 comme 0 car c'est 2 64 ). Donc, vous voudrez peut-être ajouter des vérifications supplémentaires dans cette déclaration de cas ci-dessus, comme:

(0?* | -0?*)
  echo >&2 'Only decimal numbers without leading 0 accepted'; exit 1;;
(-??????????* | [!-]?????????*)
  echo >&2 'Only numbers from -999999999 to 999999999 supported'; exit 1;;

Exemples:

$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux

Plus de lecture sur:

Stéphane Chazelas
la source
x='P=3'; : $(($x + 5))sera mis Pà 8, mais x='P=3'; : $((x + 5))sera mis Pà 3(en zsh, kshou bash). "La même chose se produit avec $((x + 1))..." n'est pas correct maintenant; il sera mis PATHà 2, comme autrefois.
mosvy
@mosvy, très bien merci (et pour votre édition précédente). Corrigé maintenant.
Stéphane Chazelas