Пояснення команди для перевірки оболонки


32

Ось команда, яку я використав для перевірки моєї башти на наявність помилки Shellshock:

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

Може хто-небудь, будь ласка, пояснити команду детально?


4
Також дивіться: unix.stackexchange.com/q/157329/70524 - Відповідь Fixee може допомогти.
муру

Відповіді:


45

Ця відповідь є похідною від оригінальної статті журналу Fedora від Matthew Miller, ліцензованої за ліцензією Creative Commons Attribution-Share Alike 4.0 .

Дозволь пояснити:

env x='() { :;}; echo OOPS' bash -c :

Це надрукує "OOPS" на вразливій системі, але вийдіть мовчки, якщо баш був зафіксований.

env x='() { :;}; echo OOPS' bash -c "echo this is a test"

Це надрукує "OOPS" на вразливій системі, але друкує, “this is a test”якщо баш був зафіксований.

І ви, напевно, чули, що це має щось спільне із змінними середовища. Але чому код у змінних оточуючого середовища виконується? Ну, це не повинно бути, але через особливість, яку я спокусив назвати трохи надто розумною для власного блага, є дещо для дефекту. Bash - це те, що ви бачите як термінальний запит, але він також є мовою сценаріїв і має можливість визначати функції. Ви робите це так:

$ Ubuntu()  { echo "Ubuntu is awesome."; }

і тоді у вас є нова команда. Майте на увазі, що echoтут ще насправді не працює; це просто збережено, як це станеться, коли ми запустимо нову команду. Це буде важливо через хвилину!

$ Ubuntu
 Ubuntu is awesome.

Корисно! Але, скажімо, чомусь нам потрібно виконати новий екземпляр bash, як підпроцес, і хотіти запустити мою приголомшливу нову команду під цим. Оператор bash -c somecommandробить саме так: запускає задану команду в новій оболонці:

$ bash -c Ubuntu
  bash: Ubuntu: command not found

О-о. Сумно. Дитина не успадкувала визначення функції. Але це притаманне середовищу - це набір пар ключових значень, які були експортовані з оболонки. (Це ціла концепція "нутіра"; якщо ви з цим не знайомі, повірте мені зараз.) І, виявляється, баш може також експортувати функції. Так:

$ 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щось, що схоже на функцію. Функція - це лише одна :, яка насправді є простою командою, яка визначається як нічого не робити. Але потім, після semi-colonчого сигналізує про закінчення визначення функції, є echoкоманда. Це не повинно бути там, але нас ніщо не заважає робити це.

Тоді команда, що надається для запуску з цим новим середовищем, - це нова оболонка bash, знову ж таки командою " echo this is a test" або "не робити нічого :", після чого вона вийде абсолютно нешкідливою.

Але - ой! Коли ця нова оболонка запускається і читає середовище, вона потрапляє до xзмінної, і оскільки вона схожа на функцію, вона оцінює її. Визначення функції завантажено нешкідливо - і тоді спрацьовує і наше зловмисне навантаження. Таким чином, якщо ви запускаєте вищезазначене на вразливій системі, ви надрукуєте собі “OOPS”друк. Або зловмисник може зробити набагато гірше, ніж просто друкувати речі.


1
Muchas gracias за відмінне пояснення того, чому це працює.
Дуг Р.

2
Зауважте, що envце не потрібно. Ви можете отримати той же результат (пройшов / не пройшов в залежності від того, чи був оновлений Bash) за допомогою команди без нього: x='() { :;}; echo OOPS' bash -c "echo this is a test". Це тому, що перед командою зі призначенням змінної передається ця змінна та її значення в середовище команди ( bash -c "..."в даному випадку).
Призупинено до подальшого повідомлення.

1
... але це може знадобитися в деяких останніх виправленнях. Речі в потоці.
Призупинено до подальшого повідомлення.

4
@DennisWilliamson Потрібно чи ні env, визначається оболонка, з якої виконується тест, а не оболонка, що тестується. (Вони можуть бути однаковими. Навіть тоді ми перевіряємо, як баш обробляє власне середовище.) Оболонки у стилі Борна приймають NAME=value commandсинтаксис; Оболонки в стилі С (наприклад csh, tcsh) не роблять. Тож тест є трохи більш портативним env(ціною іноді створюють плутанину щодо того, як він працює).
Елія Каган

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,

  1. env - запускати програму в модифікованому середовищі.

  2. :не робити нічого, крім виходу зі статусом виходу 0. побачити більше

  3. Коли новий екземпляр unpatched bash запускається як bash -c "echo this is a test", створена змінна середовище трактується як функція та завантажується. Відповідно, кожен отримує вихід

    вразливі
    це перевірка

Примітка: Відлуння поза визначенням функції несподівано виконується під час запуску bash. Визначення функції - це лише крок для того, щоб отримати оцінку та скористатися експлуатуванням, саме визначення функції та використана змінна середовища є довільними. Оболонка розглядає змінні середовища, бачить х, що схоже на те, що відповідає обмеженням, які вона знає про те, як виглядає визначення функції, і вона оцінює рядок, ненавмисно виконуючи також ехо (що може бути будь-якою командою, шкідливою чи ні) . Також дивіться це


Я все-таки виявив, що будь-яка визначена функція bash, якщо експорт оцінюється в дочірній оболонці у виправленій версії bash. Дивіться це: chayan @ chayan: ~ / testr $ test () {echo "що-небудь"; }; експорт -f тест; bash -c test Ouput: що завгодно Отже, ваша відповідь дещо неправильно спрямована. Пояснення помилки kasiyA як розширення змінної за її межами є правильним, я думаю.
heemayl

@heemayl така поведінка природна. Але якщо ви спробуєте, env test='() { echo "anything"; }' bash -c "echo otherthing"ви побачите на виході otherthing. Це виправлено в патчі. почуваюся вільним, якщо мені все ще не зрозуміло.
souravc

Будь ласка, ще раз уточніть. У вашому останньому коментарі ми в основному визначаємо функцію, а потім говоримо bash виконувати ехо. У цьому прикладі ми не називали функцію в bash. Невже це не матиме однаковий вихід як у виправленому, так і в безпатковому баші? У мене є уявлення, що помилка в основному, як bash, виконує команди, розміщені після визначення функції, тоді як функція ніколи не викликалася ніколи, наприклад, якщо ми робимо це env test = '() {echo "будь-що"; }; echo "foo" 'bash -c "echo otherthing". Будь ласка, уточніть мене в цьому контексті.
heemayl

@heemayl Я відредагував свою відповідь, сподіваюся, зараз це зрозуміло. Ви вірні в прикладі в останньому моєму коментарі, ми не назвали функцію. Але різниця полягає в тому, що в an unpatched bashви можете викликати функцію так, як вона визначена, але в патчі bashсамого визначення немає.
souravc

@heemayl: Ні, це неправильно. Виправлений Bash все одно передасть визначення функції в оточення дитини. Різниця, яку робить патч, полягає в тому, що код, який відповідає визначенню функції ( echo vulnerable), не виконується. Зауважте, що в останніх виправленнях передана функція повинна мати певний префікс ( env 'BASH_FUNC_x()'='() { :;}; echo vulnerable' bash -c "echo this is a test"). Деякі новіші виправлення можуть використовуватись %%замість першого ().
Призупинено до подальшого повідомлення.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.