Наслідки безпеки використання несанітизованих даних при оцінці арифметики Shell


17

У коментарі до нещодавнього запитання Стефан Шазелас згадує, що для подвійної арифметики в дужках є наслідки для безпеки, такі як:

x=$((1-$x))

на більшості снарядів.

Мої навички Google здаються іржавими, і я нічого не можу знайти. Які наслідки для арифметики подвійних дужок є для безпеки?

Відповіді:


22

Проблема полягає в тих випадках, коли вміст $xне був дезінфікований і містить дані, які потенційно можуть бути під контролем зловмисника у випадках, коли код оболонки може в кінцевому підсумку використовуватися в контексті ескалації привілеїв (наприклад, скрипт, на який посилається setuid додаток, скрипт sudoers або використовується для обробки даних, що виходять за межі мережі (CGI, DHCP гак ...) прямо чи опосередковано).

Якщо:

x='(PATH=2)'

Потім:

x=$((1-$x)))

має побічний ефект встановлення PATHна 2(відносний шлях, який цілком може бути під контролем нападника). Ви можете замінити PATHна LD_LIBRARY_PATHабо IFS... Те ж саме відбувається з x=$((1-x))bash, zsh або ksh (не тире чи yash, які приймають лише числові константи у змінних).

Зауважте, що:

x=$((1-$x))

не працюватимуть належним чином для від'ємних значень $xу деяких оболонках, які реалізують --оператор ( необов'язково відповідно до POSIX) (декремент) (як у випадку x=-1, це означає, що попросити оболонку оцінити 1--1арифметичний вираз). "$((1-x))"не має проблеми, оскільки xвона розширюється як частина (не раніше) арифметичної оцінки.

В bash, zshі ksh(ні dashабо yash), якщо xє:

x='a[0$(uname>&2)]'

Тоді розширення $((1-$x))або $((1-x))спричиняє виконання цієї unameкоманди (бо zsh, aповинно бути змінною масиву, але для цього можна використовувати, psvarнаприклад).

Таким чином, не слід використовувати неініцалізірованние або не продезінфікують зовнішні дані в арифметичних виразах в оболонках (зверніть увагу , що арифметична оцінка може бути зроблена шляхом $((...))(він же $[...]в bashабо zsh) , але і в залежності від оболонки в let, [/ test, declare/typeset/export..., return, break, continue, exit, printf, printвбудовані, індекси масиву ((..))та [[...]]конструкції, щоб назвати декілька).

Щоб перевірити, чи змінна містить буквальне десяткове ціле число, ви можете використовувати POSIXly:

case $var in
  ("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac

Будьте уважні, що [0-9]в деяких локальних збігах більше 0123456789. [[:digit:]]повинно бути гаразд, але я б не став на це.

Також пам’ятайте, що числа з провідними нулями в деяких контекстах розглядаються як восьмеричні ( 010іноді це 10, іноді 8), і будьте обережні, що перевірка вище дозволить пропустити цифри, які потенційно перевищують максимальне ціле число, що підтримується вашою системою (або будь-яке додаток, яке ви хочете використовувати це ціле число; bash, наприклад, розглядає 18446744073709551616 як 0, як це 2 64 ). Тому ви можете додати додаткові чеки у цій заяві вище, наприклад:

(0?* | -0?*)
  echo >&2 'Only decimal numbers without leading 0 accepted'; exit 1;;
(-??????????* | [!-]?????????*)
  echo >&2 'Only numbers from -999999999 to 999999999 supported'; exit 1;;

Приклади:

$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux

Більше читання на:


x='P=3'; : $(($x + 5))буде встановлено Pу 8, але x='P=3'; : $((x + 5))встановиться Pу 3zsh, kshабо bash). "Те саме відбувається і з $((x + 1))..." зараз невірно; він буде встановлений PATHв 2, як у давнину.
mosvy

@mosvy, правильно дякую (і за попередню редакцію). Виправлено зараз.
Стефан Хазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.