Вот команда, которую я использовал для проверки оболочки bash на наличие ошибки Shellshock:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Может ли кто-нибудь подробно объяснить команду?
решение1
Этот ответ является производным оторигинальная статья в Fedora MagazineМэтью Миллер, лицензированоCreative Commons Attribution-Share Alike 4.0лицензия.
Позволь мне объяснить:
env x='() { :;}; echo OOPS' bash -c :
В уязвимой системе это выведет сообщение «OOPS», но при этом произойдет тихое завершение работы, если bash был исправлен.
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Это выведет сообщение «OOPS» на уязвимой системе, но выведет сообщение, “this is a test”
если bash был исправлен.
И вы, вероятно, слышали, что это как-то связано с переменными окружения. Но почему код в переменных окружения выполняется? Ну, так не должно быть — но из-за функции, которую я склонен назвать слишком умной для ее же блага, есть место для изъяна. Bash — это то, что вы видите как приглашение терминала, но это также язык сценариев, и он может определять функции. Вы делаете это так:
$ Ubuntu() { echo "Ubuntu is awesome."; }
и затем у вас есть новая команда. Помните, что echo
здесь это еще не выполняется на самом деле; это просто сохранено как то, что произойдет, когда мы запустим нашу новую команду. Это будет важно через минуту!
$ Ubuntu
Ubuntu is awesome.
Полезно! Но, скажем, по какой-то причине нам нужно выполнить новый экземпляр bash как подпроцесс и мы хотим запустить мою потрясающую новую команду в нем. Оператор bash -c somecommand
делает именно это: запускает указанную команду в новой оболочке:
$ bash -c Ubuntu
bash: Ubuntu: command not found
Ох. Печально. Дочерний элемент не унаследовал определение функции. Но он наследует окружение — набор пар ключ-значение, которые были экспортированы из оболочки. (Это совершенно 'nuther-концепция; если вы с ней не знакомы, доверьтесь мне на данный момент.) И, оказывается, bash также может экспортировать функции. Итак:
$ export -f Ubuntu
$ bash -c Ubuntu
Ubuntu is awesome.
Это все хорошо и замечательно — за исключением того, что механизм, с помощью которого это достигается,какой-то подозрительный. По сути, поскольку нет магии Linux/Unix для выполнения функций в переменных окружения, функция экспорта на самом деле просто создает обычную переменную окружения, содержащую определение функции. Затем, когда вторая оболочка считывает «входящую» среду и встречает переменную с содержимым, похожим на функцию, она оценивает ее.
В теории этосовершенно безопасно, потому что, помните, определение функции на самом деле невыполнить это. За исключением того, что — и именно поэтому мы здесь — в коде была ошибка, из-за которой оценка не останавливалась при достижении конца определения функции. Она просто продолжала работать.
Этого никогда не произойдет, если функция, сохраненная в переменной окружения, создана легитимно, с помощью export -f
. Но зачем быть легитимным? Злоумышленник может просто придумать любую старую переменную окружения, и если она будет выглядеть как функция, новые оболочки bash подумают, что это так!
Итак, в нашем первом примере:
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Команда env
запускает команду с заданным набором переменных. В этом случае мы устанавливаем x
что-то, что выглядит как функция. Функция — это просто один :
, который на самом деле является простой командой, которая определена как ничего не делающая. Но затем, после which, semi-colon
который сигнализирует об окончании определения функции, идет команда echo
. Она не должна быть там, но ничто не мешает нам сделать это.
Затем команда, заданная для запуска в этой новой среде, представляет собой новую оболочку bash, снова с командой « echo this is a test
» или «ничего не делать :
», после чего она завершит работу, совершенно безвредно.
Но — упс! Когда эта новая оболочка запускается и считывает среду, она добирается до переменной x
, и поскольку она выглядит как функция, она ее оценивает. Определение функции безвредно загружается — и затем также запускается наша вредоносная полезная нагрузка. Так что, если вы запустите вышеописанное в уязвимой системе, вы получите “OOPS”
распечатку обратно. Или злоумышленник может сделать гораздо хуже, чем просто распечатать что-то.
решение2
Внепатченная версияbash
он сохраняет экспортированные определения функций как переменные среды.
Сохраните функцию x
как,
$ x() { bar; }
$ export -f x
И проверьте его определение как,
$ env | grep -A1 x
x=() { bar
}
Так что можно было бы использовать это, определяя свои собственные переменные окружения и интерпретируя их как определения функций. Например, это env x='() { :;}'
будет рассматриваться как
x() { :;
}
Что делает команда проверки контузии,
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
От man env
,
env
- запустить программу в измененной среде.:
ничего не делает, кроме как выходит со статусом выхода0
. см.болееКогда новый экземпляр непатченного bash запускается как
bash -c "echo this is a test"
, созданная переменная окружения обрабатывается как функция и загружается. Соответственно, получается вывод
уязвимый Это тест
Примечание:Эхо за пределами определения функции было неожиданно выполнено во время запуска bash. Определение функции — это всего лишь шаг к выполнению оценки и эксплуатации, само определение функции и используемая переменная окружения являются произвольными. Оболочка просматривает переменные окружения, видит x, который, похоже, соответствует ограничениям, известным ей относительно того, как выглядит определение функции, и оценивает строку, непреднамеренно также выполняя эхо (которое может быть любой командой, вредоносной или нет). Также см.этот