Як явно і безпечно змусити використовувати вбудовану команду в bash


19

Існує аналогічне запитання, яке стосується сценарію "обгортання", де ви хочете замінити, наприклад, cdкоманду, яка викликає вбудований cd.

Однак, зважаючи на оболонку та інші та знаючи, що баш імпортує функції з навколишнього середовища, я зробив кілька тестів, і я не можу знайти спосіб безпечно викликати вбудований cdз мого сценарію.

Розглянемо це

cd() { echo "muahaha"; }
export -f cd

Будь-які сценарії, викликані в цьому середовищі, що використовують, cdбудуть порушені (врахуйте ефекти чогось подібного cd dir && rm -rf .).

Існують команди для перевірки типу команди (зручно називатися type) та команди для виконання вбудованої версії, а не функції ( builtinта command). Але ось ось вони можуть бути відмінені і за допомогою функцій

builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }

Вийде наступне:

$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha

Чи є спосіб безпечно змусити bash використовувати вбудовану команду чи принаймні виявити, що команда не є вбудованою, не очищаючи все середовище?

Я розумію, якщо хтось контролює ваше оточення, ви, ймовірно, все одно накрутили, але принаймні для псевдонімів ви маєте можливість не називати псевдонім, вставляючи його \перед цим.


Ви можете запустити скрипт , використовуючи envкоманду перш, як це:env -i <SCRIPT.sh>
Аркадіуш Drabczyk

Тільки якщо envвін також не визначений як функція. Це жахливо. Я спершу подумав, що допоможуть спеціальні символи - дзвінки з повним шляхом, що включає /використання .джерела тощо. Але їх також можна використовувати для імен функцій! Ви можете перезначити будь-яку функцію, яку хочете, але важко повернутися до виклику вихідної команди.
Оріон

1
Щоправда, але якщо ви збираєтеся запускати будь-який скрипт на компрометованій машині, ви все одно накрутитеся. Крім того, напишіть свій сценарій, #/bin/shякщо це не інтерактивна оболонка за замовчуванням.
Аркадіуш Драбчик

Відповіді:


16

Олів'є D майже правильно, але ви повинні встановити POSIXLY_CORRECT=1перед запуском unset. POSIX має поняття " Спеціальні вбудовані" , і bash це підтримує . unsetє одним з таких вбудованих. Шукати SPECIAL_BUILTINв builtins/*.cв джерелі Баш для списку, він включає в себе set, unset, export, evalі source.

$ unset() { echo muahaha-unset; }
$ unset unset
muahaha-unset
$ POSIXLY_CORRECT=1
$ unset unset

Шахрай unsetтепер був видалений з середовища, якщо скинути command, type, builtinто ви повинні бути в змозі продовжувати, але unset POSIXLY_CORRECTякщо ви покладаєтеся на НЕ-POSIX поведінки або розширені функції Баш.

Це не стосується псевдонімів, тому ви повинні використовувати, \unsetщоб бути впевненим, що він працює в інтерактивній оболонці (або завжди, якщо expand_aliasesце діє).

Для параноїка це має виправити все, я думаю:

POSIXLY_CORRECT=1
\unset -f help read unset
\unset POSIXLY_CORRECT
re='^([a-z:.\[]+):' # =~ is troublesome to escape
while \read cmd; do 
    [[ "$cmd" =~ $re ]] && \unset -f ${BASH_REMATCH[1]}; 
done < <( \help -s "*" )

( while, do, doneІ [[є зарезервованими словами і не потрібні запобіжні заходи.) Зверніть увагу , що ми використовуємо , unset -fщоб бути впевненим в невстановлених функцій, хоча змінні і функції поділяють той же простір імен , що це можливо для обох існувати одночасно (завдяки Етан Рейснер) , в цьому випадку невдала двічі також зробить трюк. Ви можете позначати функцію лише читати, bash не перешкоджає відключенню функції readonly аж до включення bash-4.2, bash-4.3 заважає вам, але він все ще шанує спеціальні вбудовані, коли POSIXLY_CORRECTвстановлено.

Читання POSIXLY_CORRECTлише не є справжньою проблемою, це не булева або прапор, якщо його наявність увімкнено режим POSIX, тому, якщо він існує як лише для читання, ви можете розраховувати на функції POSIX, навіть якщо значення порожнє або 0. Вам просто потрібно буде зніміть проблемні функції іншим способом, ніж вище, можливо, із деяким вирізанням та вставкою:

\help -s "*" | while IFS=": " read cmd junk; do echo \\unset -f $cmd; done

(і ігноруйте будь-які помилки) або вступайте в якісь інші сценарії .


Інші примітки:

  • functionце зарезервоване слово, воно може бути псевдонімом, але не перекрито функцією. (Згладжування functionзлегка клопітке, оскільки \function не прийнятне як спосіб його обходу)
  • [[, ]]є зарезервованими словами, вони можуть бути псевдонімом (який буде проігноровано), але не замінити функцією (хоча функції можуть бути названі так)
  • (( не є дійсним іменем функції, ні псевдонімом

Цікаво, дякую! Мені здається дивним, що баш за замовчуванням не захищає unsetet al від перезапису.
falstro

Для цього потрібен -fаргумент, unsetчи не так? В іншому випадку, якщо визначена і змінна, і функція, названа так само, як і вбудований, тоді unsetвиберіть змінну для зняття спочатку. Також це не вдається, якщо встановлена ​​будь-яка з затемнюючих функцій, readonlyчи не так? (Хоча це виявляється і може бути допущена фатальна помилка.) Також це не вистачає [вбудованого, здається.
Ітан Рейснер

1
Я не думаю, що \unset -f unsetмає сенс, враховуючи, що це буде зроблено в циклі читання. Якщо unsetце функція, ви \unsetзазвичай вирішите її замість вбудованої, але ви можете використовувати її \unsetбезпечно, поки діє режим POSIX. Явний виклик \unset -fна [, .і :може бути гарною ідеєю , хоча, як ваші регулярних виразів виключає їх. Я також додав -fби до \unsetциклу, а \unset POSIXLY_CORRECTпісля циклу, замість того, як раніше. \unalias -a(після \unset -f unalias) також дозволяє безпечно відмовитися від втечі за наступними командами.
Адріан Гюнтер

1
@ AdrianGünter Спробуйте:, [[ ${POSIXLY_CORRECT?non-POSIX mode shell is untrusted}x ]]це призведе до виходу неінтерактивного скрипту із вказаною помилкою, якщо змінна не встановлена, або продовжується, якщо вона встановлена ​​(порожня або будь-яке значення).
mr.spuratic

1
"Ви повинні використовувати \unset" ... Слід зазначити, що цитування будь-яких символів (ів) буде працювати, щоб уникнути розширення псевдоніму, не лише першого. un"se"tпрацювало б так само добре, хоча і менш читано. "Перше слово кожної простої команди, якщо не цитується, перевіряється, чи є у неї псевдонім." - Bash Ref
Робін А. Мід

6

Я усвідомлюю, якщо хтось контролює ваше оточення, ви, ймовірно, все одно накрутили

Так, це. Якщо ви запускаєте скрипт у невідомому середовищі, всі речі можуть піти не так, починаючи з того, LD_PRELOADщо процес оболонки виконує довільний код, перш ніж він навіть прочитає ваш сценарій. Спроба захиститися від ворожої обстановки зсередини сценарію марна.

Судо проводить санітарну обробку навколишнього середовища, видаляючи все, що схоже на визначення функції башма, вже більше десяти років. Починаючи з Shellshock , інші середовища, які запускають скрипт оболонки в не повністю надійному середовищі, наслідували цю справу.

Ви не можете безпечно запускати скрипт у середовищі, встановленому ненадійною сутністю. Тож турбуватися про визначення функцій не є результативним. Санітизуйте своє оточення, роблячи так, змінні, які bash інтерпретують як визначення функцій.


1
Я цілком не згоден з цим. Безпека не є бінарною пропозицією, зосередженою навколо "санітарної" або "несанізованої". Йдеться про усунення можливостей для експлуатації. І, на жаль, складність сучасних систем означає, що існує багато можливостей експлуатації, які потрібно правильно заблокувати. Багато можливостей експлуатації зосереджуються навколо нешкідливих нападів, що здаються вгору за течією, такі як зміна змінної PATH, переосмислення вбудованих функцій і т.д.
Dejay Clayton

@DejayClayton Я повністю згоден з вашим коментарем, за винятком першого речення, тому що я не бачу, як це жодним чином суперечить моїй відповіді. Вилучення можливості експлуатації допомагає, але не видаляти лише половину її, коли тривіальний виправлення в атаці дозволяє їй продовжувати працювати.
Жил 'ТАК - перестань бути злим'

Моя думка полягає в тому, що ви не можете просто «оздоровити своє оточення», а потім перестати турбуватися про різні вектори нападу. Іноді платять за "захист від ворожої обстановки зсередини сценарію". Навіть якщо ви вирішите проблему "визначення функції", вам все одно слід турбуватися про такі речі, як, наприклад, наявність PATH, де хтось може помістити в каталог спеціальний сценарій під назвою "cat" або "ls", а потім будь-який сценарій, який викликає "cat" "або" ls "замість" / bin / cat "і" / bin / ls "ефективно здійснює подвиг.
Dejay Clayton

@DejayClayton Очевидно, що санітарна обстановка не допомагає проти векторів нападу, не пов'язаних із середовищем. (Наприклад, скрипт , який викликає /bin/catв ізольованому оточенні міг називати що - або.) Санобробки оточення дає вам розумне PATH(припускаючи , що ви робите це правильно, звичайно). Я досі не бачу вашої точки зору.
Жил 'ТАК - перестань бути злим'

Враховуючи, що PATH - це одна з найбільших можливостей для експлуатації та що багато сумнівних практик PATH задокументовано як рекомендовані поради навіть у блогах із безпеки, а також враховуючи, що інколи встановлені додатки змінюють порядок PATH для забезпечення роботи таких додатків, я не можу зрозуміти, як захисне кодування в сценарії було б поганою ідеєю. Те, що ви вважаєте здоровим PATH, насправді може бути вразливим до подвигів, з якими ви не стикалися.
Dejay Clayton

1

Ви можете використовувати unset -fдля видалення вбудованих функцій, команд та типів.


2
вибачте, unset() { true; }піклується про це.
falstro

1
Чорт! І перелік визначених функцій також покладається на вбудований. Я здаюся!
odc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.