Делает ли оценка вывода "ls" сценарий уязвимым для внедрения кода?

awk '$3 ~ /^S/||/^M/||/^D/{print $0}' filename
2
03.02.2021, 16:50
2 ответа

filename... dangerous to eval

Конечно.

$ touch 'file $(date >&2).txt'
$ bash -c 'eval ls *'
Wed 03 Feb 2021 06:07:08 PM EET
ls: cannot access 'file': No such file or directory
ls: cannot access '.txt': No such file or directory

Не evalвещи.

or backtick the output of ls in a bash script?

Я не совсем понимаю, что это значит.

Если вы имеете в виду то, что у вас было в качестве примера,

hello=(`ls -t`)

или с более разумным синтаксисом,

files=( $(ls -t) )

, то вы просто получаете вывод lswordsplit в массив.

$ declare -p files
declare -a files=([0]="file" [1]="\$(date" [2]=">&2).txt")

Самая большая проблема здесь, еще до возможной инъекции команды, заключается в том, что пробел в имени файла сломал его , мы получили две записи массива вместо одной. См. страницу о разборе ls на вики Грега. Нет, вы не можете обойти это, добавляя кавычки, разделение слов так не работает.

Поэтому не используйте здесь ls. Просто позвольте оболочке сгенерировать список имен файлов:

files=(*)
declare -p files
declare -a files=([0]="file \$(date >&2).txt")

Единственная проблема заключается в том, что Bash не дает хорошего способа сортировки файлов по дате, поэтомуls -tвыглядит заманчиво.Хорошей альтернативой является указание даты в самом имени файла , чтобы сортировка по умолчанию давала вам сортировку по дате , или использование Zsh, так как он может сортировать по дате . Или сделайте уродливые хаки для решения проблемы (предостережение, я не тестировал это решение ).

Та же проблема с evalвозникает, если вам нужно передать имя файла чему-либо, что принимает только сценарий оболочки, например

ssh somehost "do something with $file"      # wrong
ssh somehost "do something with '$file'"    # still wrong, the name
                                            # could contain single ticks

It seems like the filesystem sanitizes special characters, spaces for instance, by wrapping the filenames in quotes. Will it catch all such things?

О боже, о нет, это не так. Если бы файловая система сделала что-то, чтобы предотвратить сохранение специальных символов в оболочке, половина сообщений в unix.SE не понадобилась бы.

Если вы хотите испытать боль от слишком большого количества знаний, вот эссе Дэвида Уилера об этом:Исправление имен файлов Unix/Linux/POSIX :Управляющие символы (, такие как перевод строки ), начальные тире и другие проблемы

Есть еще один, написанный им, Имена файлов и пути в оболочке :Как это сделать правильно . Многое из этого также обсуждалось здесь, на unix.SE.

Кроме того, кавычки не помогают.

$ touch '"quoted name"' 'othername'   # two files
$ printf "%s\n" $(ls)                 # oops
othername
"quoted
name"
$ printf "%s\n" *                     # this works better
othername
"quoted name"

Потому что, когда происходит разделение слов, кавычки — это просто обычный символ. (Если вы не установите IFSдля включения кавычек, что, вероятно, только усугубит ситуацию. )Кроме того, даже если имя заключено в кавычки, оно все равно может иметь кавычки посередине , нарушая это правило. Вам также нужно будет позаботиться о побеге или правильно процитировать их.

Цитаты делает GNU ls, в зависимости от версии и настроек:

$ ls -l
total 0
-rw-rw-r-- 1 ilkkachu ilkkachu 0 Feb  3 18:30  othername
-rw-rw-r-- 1 ilkkachu ilkkachu 0 Feb  3 18:30 '"quoted name"'

То же, что и ls --quoting-style=shell. Между прочим, кажется, что это правильно для всех новых строк, знаков доллара и кавычек. Но доверяете ли вы ему, чтобы сделать это правильно? Если вы это сделаете, и вы знаете, как правильно их использовать, вы сможете использовать их для получения отсортированного списка.

4
18.03.2021, 22:32
hello=(`ls -t`)

Эта форма кажется безопасной. Bash выполнит просто split + glob для результатов подстановки команд, а не интерпретирует это как синтаксис :

.
a=(`echo '[0]=1'`)
typeset -p a

declare -a a=([0]="[0]=1")  # aha!

Тем не менее, (непонятные)declare "var=val"или local "var=val"формы не являются таковыми, поскольку они работают аналогичноeval "var=val":

cd "$(mktemp -d)"
touch '$(yes BOOBS >&2&)'
declare -a "a=($(ls))"

BOOBS
BOOBS
BOOBS
...

То же, что и declare -a a="($(ls))", declare -a a="(`ls`)"и т. д.

Или даже с не -цитируемыми формами, при условии, что переменная уже была объявлена ​​как массив:

cd "$(mktemp -d)"
a=(1 2 3)
touch '($(yes BOOBS >&2&))'
declare a=$(ls)  # I forgot that a was an array

BOOBS
BOOBS
BOOBS
...
1
18.03.2021, 22:32

Теги

Похожие вопросы