Независимо от того, как вы решите это, это все равно не поможет. cdИмеет только эффект внутри bash -cоболочки.
Кусалананда
Я даю лишь минимальный пример только для вопроса, это не рабочее решение моей реальной проблемы, а именно unix.stackexchange.com/a/269080/674 плюс то, что в приведенной sudo bash -cмне командной строке есть расширение переменной до путь, который может содержать пробелы.
Тим
Ответы:
13
В этом коде нет разделения слов (как в функции, которая разделяет переменные при раскрытии без кавычек)$myvar и без кавычек.
Однако существует уязвимость, связанная с внедрением команд, $myvarкоторая расширяется перед передачей вbash . Таким образом, его содержание интерпретируется как код bash!
Пробелы в них приведут к передаче нескольких аргументов cdне из-за разделения слов , а потому, что они будут проанализированы как несколько токенов в синтаксисе оболочки. Со значениемbye;reboot , это перезагрузит! ¹
Здесь вы бы хотели:
sudo bash -c 'cd -P -- "$1"' bash "$myvar"
(где вы передаете содержимое в $myvarкачестве первого аргумента этого встроенного скрипта; обратите внимание, как $myvarи$1 были процитированы для их соответствующей оболочки, чтобы предотвратить расщепление IFS-слов (и глобализация)).
Или:
sudo MYVAR="$myvar" bash -c 'cd -P -- "$MYVAR"'
(где вы передаете содержимое $myvar переменной среды).
Конечно, вы не добьетесь ничего полезного, запустив толькоcd этот встроенный скрипт (кроме проверки, rootможно ли cdтуда войти). Предположительно, вы хотите, чтобы этот скрипт cdтут же делал что-то еще, например:
Если намерение состояло в том, чтобы использовать , sudoчтобы иметь возможность cdв каталог , который вы в противном случае не имеют доступа к, то , что не может реально работать.
sudo sh -c 'cd -P -- "$1" && exec bash' sh "$myvar"
запустит интерактив bashс текущим каталогом в $myvar. Но эта оболочка будет работать как root.
Вы могли бы сделать:
sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
Чтобы получить непривилегированный интерактив bashс текущим каталогом $myvar, но если у вас не было разрешений cdна этот каталог, вы не сможете ничего сделать в этом каталоге, даже если это ваш текущий рабочий каталог.
$ 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
Исключением может быть, если у вас есть разрешение на поиск для самого каталога, но не для одного из компонентов каталога его пути:
¹ Строго говоря, для значений $myvarlike $(seq 10)(в буквальном смысле слова), конечно, произойдет разделение слов при расширении этой подстановки команд bash оболочкой, начинающейся какroot
Есть новая (bash 4.4) магия цитирования, которая позволяет вам более прямо делать то, что вы хотите. В зависимости от более широкого контекста, использование одного из других методов может быть лучше, но оно работает в этом ограниченном контексте.
ARGUMENT печатается в формате, который можно использовать в качестве ввода для оболочки, избегая непечатаемых символов с предложенным $''синтаксисом POSIX .
GNU printfбудет вызываться там только в системах GNU, и если $(printf '%q' "$myvar")он запускается в оболочке, где printfон не встроен. Большинство снарядов уже построены printf. Не все поддерживают %qхотя, и когда они это делают, они цитируют вещи в формате, поддерживаемом соответствующей оболочкой, который может не совпадать с понимаемым bash. На самом деле, bashs printfне может правильно процитировать вещи даже для себя для некоторых значений $myvarв некоторых локалях.
Стефан Шазелас
По bash-4.3крайней мере, это все еще уязвимость внедрения myvar=$'\xa3``reboot`\xa3`' команд, например, в локали zh_HK.big5hkscs.
Стефан Шазелас
3
Прежде всего, как уже отмечали другие, ваша cdкоманда бесполезна, поскольку она происходит в контексте оболочки, которая немедленно завершается. Но в целом вопрос имеет смысл. Вам нужен способ заключить в кавычки произвольную строку , чтобы ее можно было использовать в контексте, где она будет интерпретироваться как строка в кавычках. У меня есть пример этого на моей странице с хитростями :
quote (){ printf %s\\n "$1"| sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/";}
То, что предлагает Стефан Шазелас, безусловно, лучший способ сделать это. Я просто предоставлю ответ о том, как безопасно цитировать синтаксис раскрытия параметров, а не использовать sedподпроцесс, как в ответе R ..
Одиночные кавычки здесь не будут работать, с тех пор ваша переменная не будет расширена. Если вы уверены, что переменная для вашего пути очищена, самое простое решение - просто добавить кавычки в результирующее расширение, как только оно окажется в новой оболочке bash:
По-прежнему уязвимость, связанная с внедрением команд, например, для значений $myvarlike $(reboot)или"; reboot; #
Стефан Шазелас
1
использование sudo bash -c "cd -P -- '$myvar'"ограничило бы проблему только значениями, $myvar которые содержат одинарные кавычки, что было бы легче дезинфицировать.
cd
Имеет только эффект внутриbash -c
оболочки.sudo bash -c
мне командной строке есть расширение переменной до путь, который может содержать пробелы.Ответы:
В этом коде нет разделения слов (как в функции, которая разделяет переменные при раскрытии без кавычек)
$myvar
и без кавычек.Однако существует уязвимость, связанная с внедрением команд,
$myvar
которая расширяется перед передачей вbash
. Таким образом, его содержание интерпретируется как код bash!Пробелы в них приведут к передаче нескольких аргументов
cd
не из-за разделения слов , а потому, что они будут проанализированы как несколько токенов в синтаксисе оболочки. Со значениемbye;reboot
, это перезагрузит! ¹Здесь вы бы хотели:
(где вы передаете содержимое в
$myvar
качестве первого аргумента этого встроенного скрипта; обратите внимание, как$myvar
и$1
были процитированы для их соответствующей оболочки, чтобы предотвратить расщепление IFS-слов (и глобализация)).Или:
(где вы передаете содержимое
$myvar
переменной среды).Конечно, вы не добьетесь ничего полезного, запустив только
cd
этот встроенный скрипт (кроме проверки,root
можно лиcd
туда войти). Предположительно, вы хотите, чтобы этот скриптcd
тут же делал что-то еще, например:Если намерение состояло в том, чтобы использовать ,
sudo
чтобы иметь возможностьcd
в каталог , который вы в противном случае не имеют доступа к, то , что не может реально работать.запустит интерактив
bash
с текущим каталогом в$myvar
. Но эта оболочка будет работать какroot
.Вы могли бы сделать:
Чтобы получить непривилегированный интерактив
bash
с текущим каталогом$myvar
, но если у вас не было разрешенийcd
на этот каталог, вы не сможете ничего сделать в этом каталоге, даже если это ваш текущий рабочий каталог.Исключением может быть, если у вас есть разрешение на поиск для самого каталога, но не для одного из компонентов каталога его пути:
¹ Строго говоря, для значений
$myvar
like$(seq 10)
(в буквальном смысле слова), конечно, произойдет разделение слов при расширении этой подстановки командbash
оболочкой, начинающейся какroot
источник
Есть новая (bash 4.4) магия цитирования, которая позволяет вам более прямо делать то, что вы хотите. В зависимости от более широкого контекста, использование одного из других методов может быть лучше, но оно работает в этом ограниченном контексте.
источник
Если вы не можете доверять содержимому
$myvar
, единственный разумный подход - использовать GNUprintf
для создания его экранированной версии:Как
printf
написано на странице руководства :источник
printf
будет вызываться там только в системах GNU, и если$(printf '%q' "$myvar")
он запускается в оболочке, гдеprintf
он не встроен. Большинство снарядов уже построеныprintf
. Не все поддерживают%q
хотя, и когда они это делают, они цитируют вещи в формате, поддерживаемом соответствующей оболочкой, который может не совпадать с понимаемымbash
. На самом деле,bash
sprintf
не может правильно процитировать вещи даже для себя для некоторых значений$myvar
в некоторых локалях.bash-4.3
крайней мере, это все еще уязвимость внедренияmyvar=$'\xa3``reboot`\xa3`'
команд, например, в локали zh_HK.big5hkscs.Прежде всего, как уже отмечали другие, ваша
cd
команда бесполезна, поскольку она происходит в контексте оболочки, которая немедленно завершается. Но в целом вопрос имеет смысл. Вам нужен способ заключить в кавычки произвольную строку , чтобы ее можно было использовать в контексте, где она будет интерпретироваться как строка в кавычках. У меня есть пример этого на моей странице с хитростями :С помощью этой функции вы можете сделать:
источник
То, что предлагает Стефан Шазелас, безусловно, лучший способ сделать это. Я просто предоставлю ответ о том, как безопасно цитировать синтаксис раскрытия параметров, а не использовать
sed
подпроцесс, как в ответе R ..Вывод этого скрипта:
источник
Да, есть разделение слов.
Ну, технически, командная строка разбивается на bash при разборе строки.
Давайте сначала получим правильное цитирование:
Самое простое (и небезопасное) решение, позволяющее команде работать, как я полагаю, вы захотите, это:
Давайте подтвердим, что происходит (при условии
myvar="/path to/my directory"
):Как видите, строка пути была разбита на пробелы. А также:
Не разделен.
Однако команда (как написано) небезопасна. Лучшее использование:
Это защитит компакт-диск от файлов, начинающихся с тире (-) или следующих ссылок, которые могут привести к проблемам.
Это сработает, если вы можете верить, что строка в
$myvar
является путем.Однако «внедрение кода» все еще возможно, поскольку вы «выполняете строку»:
Вам нужно более сильное цитирование строки, например:
Как вы можете видеть выше, значение не интерпретировалось, а просто использовалось как
"$1'
.Теперь мы можем (безопасно) использовать sudo:
Если есть несколько аргументов, вы можете использовать:
источник
Одиночные кавычки здесь не будут работать, с тех пор ваша переменная не будет расширена. Если вы уверены, что переменная для вашего пути очищена, самое простое решение - просто добавить кавычки в результирующее расширение, как только оно окажется в новой оболочке bash:
источник
$myvar
like$(reboot)
или"; reboot; #
sudo bash -c "cd -P -- '$myvar'"
ограничило бы проблему только значениями,$myvar
которые содержат одинарные кавычки, что было бы легче дезинфицировать.