Peu importe comment vous résolvez cela, cela ne fera toujours pas grand-chose. Le cdseul a un effet à l'intérieur de la bash -ccoque.
Kusalananda
Je ne donne qu'un exemple minimal pour la question seulement, ce n'est pas une solution de travail à mon vrai problème, qui est unix.stackexchange.com/a/269080/674 plus que dans la chaîne de commande donnée sudo bash -cj'ai une extension variable vers un chemin qui pourrait contenir des espaces blancs.
Tim
Réponses:
13
Il n'y a pas de division de mot (comme dans la fonctionnalité qui fractionne les variables lors des extensions non cotées) dans ce code car il $myvarn'est pas non cité.
Il existe cependant une vulnérabilité d'injection de commandes telle qu'elle $myvarest développée avant d'être transmise à bash. Son contenu est donc interprété comme du code bash!
Les espaces qui s'y trouvent entraîneront la transmission de plusieurs arguments cd, non pas à cause du fractionnement de mots , mais parce qu'ils seront analysés comme plusieurs jetons dans la syntaxe du shell. Avec une valeur de bye;reboot, cela redémarrera! ¹
Ici, vous voudriez:
sudo bash -c 'cd -P -- "$1"' bash "$myvar"
(où vous passez le contenu de $myvarcomme premier argument de ce script en ligne; notez comment les deux $myvaret $1ont été cités pour leur shell respectif afin d'empêcher le fractionnement de mots IFS (et la globalisation)).
Ou:
sudo MYVAR="$myvar" bash -c 'cd -P -- "$MYVAR"'
(où vous passez le contenu de $myvardans une variable d'environnement).
Bien sûr, vous n'obtiendrez rien d'utile en exécutant uniquementcd dans ce script en ligne (à part vérifier si vous rootpouvez cdy entrer). Vraisemblablement, vous voulez que ce script soit cdlà et ensuite faire autre chose comme:
Si l'intention était d'utiliser sudopour pouvoir accéder à cdun répertoire auquel vous n'avez pas accès autrement, cela ne peut pas vraiment fonctionner.
sudo sh -c 'cd -P -- "$1" && exec bash' sh "$myvar"
lancera une interaction bashavec son répertoire actuel dans $myvar. Mais ce shell fonctionnera comme root.
Vous pourriez faire:
sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
Pour obtenir une interaction non privilégiée bashavec le répertoire actuel $myvar, mais si vous n'aviez pas les autorisations pour cdy accéder en premier lieu, vous ne pourrez rien faire dans ce répertoire même s'il s'agit de votre répertoire de travail actuel.
$ myvar=/var/spool/cron/crontabs
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ ls
ls: cannot open directory '.':Permission denied
Une exception serait si vous disposez d'une autorisation de recherche sur le répertoire lui-même mais pas sur l'un des composants de répertoire de son chemin:
$ myvar=1/2
$ mkdir -p "$myvar"
$ chmod 01
$ cd 1/2
cd: permission denied:1/2
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ pwd
/home/stephane/1/2
bash-4.4$ mkdir 3
bash-4.4$ ls
3
bash-4.4$ cd "$PWD"
bash: cd:/home/stephane/1/2:Permission denied
¹ à proprement parler, pour des valeurs $myvarsimilaires $(seq 10)(littéralement), il y aurait bien sûr un fractionnement des mots lors de l'expansion de cette substitution de commandes par le bash shell commencé commeroot
Il y a une nouvelle (bash 4.4) citant la magie qui vous permet de faire plus directement ce que vous voulez. Selon le contexte plus large, l'utilisation de l'une des autres techniques pourrait être meilleure, mais cela fonctionne dans ce contexte limité.
Si vous ne pouvez pas faire confiance au contenu de $myvar, la seule approche raisonnable consiste à utiliser GNU printfpour en créer une version échappée:
ARGUMENT est imprimé dans un format qui peut être réutilisé comme entrée de shell, en échappant les caractères non imprimables avec la $''syntaxe POSIX proposée .
Voir ma réponse pour une version portable de ceci.
R .. GitHub STOP HELPING ICE
GNU printfn'y sera invoqué que sur les systèmes GNU et s'il $(printf '%q' "$myvar")est exécuté dans un shell où il printfn'est pas intégré. La plupart des obus ont printfintégré de nos jours. Tous ne prennent pas en charge un %qbien et quand ils le font, ils citeraient quelque chose dans un format pris en charge par le shell correspondant, qui n'est pas nécessairement le même que celui compris par bash. En fait, bash« s printfne parvient pas à citer correctement les choses pour lui - même , même pour certaines valeurs de $myvardans certains endroits.
Stéphane Chazelas
Avec bash-4.3au moins, c'est toujours une vulnérabilité d'injection de commande avec myvar=$'\xa3``reboot`\xa3`' dans une locale zh_HK.big5hkscs par exemple.
Stéphane Chazelas
3
Tout d'abord, comme d'autres l'ont remarqué, votre cdcommande est inutile car elle se produit dans le contexte d'un shell qui sort immédiatement. Mais en général, la question a du sens. Ce dont vous avez besoin est un moyen de shell citer une chaîne arbitraire , afin qu'elle puisse être utilisée dans un contexte où elle sera interprétée comme une chaîne entre shell. J'en ai un exemple dans ma page astuces sh :
quote (){ printf %s\\n "$1"| sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/";}
Ce que Stéphane Chazelas suggère est certainement la meilleure façon de procéder. Je vais juste fournir une réponse sur la façon de citer en toute sécurité avec la syntaxe d'expansion des paramètres plutôt que d'utiliser un sedsous - processus, comme dans la réponse de R ...
Cela protégera le CD contre les fichiers commençant par un tiret (-) ou les liens suivants qui peuvent entraîner des problèmes.
Cela fonctionnera si vous pouvez avoir confiance que la chaîne $myvarest un chemin.
Cependant, "l'injection de code" est toujours possible car vous "exécutez une chaîne":
Les guillemets simples ne fonctionneront pas ici, car votre variable ne sera pas développée. Si vous êtes sûr que la variable de votre chemin est filtrée, la solution la plus simple consiste à simplement ajouter des guillemets autour de l'expansion résultante, une fois qu'elle est dans le nouveau shell bash:
Encore une vulnérabilité d'injection de commandes, comme pour les valeurs de $myvarlike $(reboot)ou"; reboot; #
Stéphane Chazelas
1
l'utilisation sudo bash -c "cd -P -- '$myvar'"limiterait le problème aux seules valeurs $myvar qui contiennent des guillemets simples qui seraient plus faciles à nettoyer.
cd
seul a un effet à l'intérieur de labash -c
coque.sudo bash -c
j'ai une extension variable vers un chemin qui pourrait contenir des espaces blancs.Réponses:
Il n'y a pas de division de mot (comme dans la fonctionnalité qui fractionne les variables lors des extensions non cotées) dans ce code car il
$myvar
n'est pas non cité.Il existe cependant une vulnérabilité d'injection de commandes telle qu'elle
$myvar
est développée avant d'être transmise àbash
. Son contenu est donc interprété comme du code bash!Les espaces qui s'y trouvent entraîneront la transmission de plusieurs arguments
cd
, non pas à cause du fractionnement de mots , mais parce qu'ils seront analysés comme plusieurs jetons dans la syntaxe du shell. Avec une valeur debye;reboot
, cela redémarrera! ¹Ici, vous voudriez:
(où vous passez le contenu de
$myvar
comme premier argument de ce script en ligne; notez comment les deux$myvar
et$1
ont été cités pour leur shell respectif afin d'empêcher le fractionnement de mots IFS (et la globalisation)).Ou:
(où vous passez le contenu de
$myvar
dans une variable d'environnement).Bien sûr, vous n'obtiendrez rien d'utile en exécutant uniquement
cd
dans ce script en ligne (à part vérifier si vousroot
pouvezcd
y entrer). Vraisemblablement, vous voulez que ce script soitcd
là et ensuite faire autre chose comme:Si l'intention était d'utiliser
sudo
pour pouvoir accéder àcd
un répertoire auquel vous n'avez pas accès autrement, cela ne peut pas vraiment fonctionner.lancera une interaction
bash
avec son répertoire actuel dans$myvar
. Mais ce shell fonctionnera commeroot
.Vous pourriez faire:
Pour obtenir une interaction non privilégiée
bash
avec le répertoire actuel$myvar
, mais si vous n'aviez pas les autorisations pourcd
y accéder en premier lieu, vous ne pourrez rien faire dans ce répertoire même s'il s'agit de votre répertoire de travail actuel.Une exception serait si vous disposez d'une autorisation de recherche sur le répertoire lui-même mais pas sur l'un des composants de répertoire de son chemin:
¹ à proprement parler, pour des valeurs
$myvar
similaires$(seq 10)
(littéralement), il y aurait bien sûr un fractionnement des mots lors de l'expansion de cette substitution de commandes par lebash
shell commencé commeroot
la source
Il y a une nouvelle (bash 4.4) citant la magie qui vous permet de faire plus directement ce que vous voulez. Selon le contexte plus large, l'utilisation de l'une des autres techniques pourrait être meilleure, mais cela fonctionne dans ce contexte limité.
la source
Si vous ne pouvez pas faire confiance au contenu de
$myvar
, la seule approche raisonnable consiste à utiliser GNUprintf
pour en créer une version échappée:Comme le
printf
dit la page de manuel:la source
printf
n'y sera invoqué que sur les systèmes GNU et s'il$(printf '%q' "$myvar")
est exécuté dans un shell où ilprintf
n'est pas intégré. La plupart des obus ontprintf
intégré de nos jours. Tous ne prennent pas en charge un%q
bien et quand ils le font, ils citeraient quelque chose dans un format pris en charge par le shell correspondant, qui n'est pas nécessairement le même que celui compris parbash
. En fait,bash
« sprintf
ne parvient pas à citer correctement les choses pour lui - même , même pour certaines valeurs de$myvar
dans certains endroits.bash-4.3
au moins, c'est toujours une vulnérabilité d'injection de commande avecmyvar=$'\xa3``reboot`\xa3`'
dans une locale zh_HK.big5hkscs par exemple.Tout d'abord, comme d'autres l'ont remarqué, votre
cd
commande est inutile car elle se produit dans le contexte d'un shell qui sort immédiatement. Mais en général, la question a du sens. Ce dont vous avez besoin est un moyen de shell citer une chaîne arbitraire , afin qu'elle puisse être utilisée dans un contexte où elle sera interprétée comme une chaîne entre shell. J'en ai un exemple dans ma page astuces sh :Avec cette fonction, vous pouvez alors faire:
la source
Ce que Stéphane Chazelas suggère est certainement la meilleure façon de procéder. Je vais juste fournir une réponse sur la façon de citer en toute sécurité avec la syntaxe d'expansion des paramètres plutôt que d'utiliser un
sed
sous - processus, comme dans la réponse de R ...La sortie de ce script est:
la source
Oui, il y a division des mots.
Eh bien, techniquement, la division de la ligne de commande lors de l'analyse de la ligne par bash.
Commençons par citer correctement:
La solution la plus simple (et non sécurisée) pour faire fonctionner la commande comme je pense que vous voudrez qu'elle soit:
Confirmons ce qui se passe (en supposant
myvar="/path to/my directory"
):Comme vous pouvez le voir, la chaîne de chemin a été divisée en espaces. Et:
N'est pas divisé.
Cependant, la commande (telle qu'elle est écrite) n'est pas sécurisée. Meilleure utilisation:
Cela protégera le CD contre les fichiers commençant par un tiret (-) ou les liens suivants qui peuvent entraîner des problèmes.
Cela fonctionnera si vous pouvez avoir confiance que la chaîne
$myvar
est un chemin.Cependant, "l'injection de code" est toujours possible car vous "exécutez une chaîne":
Vous avez besoin d'une citation plus forte de la chaîne, comme:
Comme vous pouvez le voir ci-dessus, la valeur n'a pas été interprétée mais simplement utilisée comme
"$1'
.Maintenant, nous pouvons (en toute sécurité) utiliser sudo:
S'il y a plusieurs arguments, vous pouvez utiliser:
la source
Les guillemets simples ne fonctionneront pas ici, car votre variable ne sera pas développée. Si vous êtes sûr que la variable de votre chemin est filtrée, la solution la plus simple consiste à simplement ajouter des guillemets autour de l'expansion résultante, une fois qu'elle est dans le nouveau shell bash:
la source
$myvar
like$(reboot)
ou"; reboot; #
sudo bash -c "cd -P -- '$myvar'"
limiterait le problème aux seules valeurs$myvar
qui contiennent des guillemets simples qui seraient plus faciles à nettoyer.