Bezpieczeństwo Implikacje korzystania z niezanalizowanych danych w ocenie arytmetyki Shell

17

W komentarzu do ostatniego pytania Stéphane Chazelas wspomina, że ​​istnieją arytmetyki podwójnych nawiasów związane z bezpieczeństwem, takie jak:

x=$((1-$x))

na większości pocisków.

Moje umiejętności Google wydają się zardzewiałe i nic nie mogę znaleźć. Jakie są konsekwencje arytmetyki podwójnych nawiasów dla bezpieczeństwa?

garethTheRed
źródło

Odpowiedzi:

22

Problem występuje w przypadkach, w których zawartość $xnie została zdezynfekowana i zawiera dane, które potencjalnie mogą być pod kontrolą atakującego, w przypadkach, gdy kod powłoki może zostać użyty w kontekście eskalacji uprawnień (na przykład skrypt wywołany przez setuid aplikacji, skryptu sudoers lub używanego do przetwarzania danych poza siecią (CGI, hak DHCP ...) bezpośrednio lub pośrednio).

Gdyby:

x='(PATH=2)'

Następnie:

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

ma efekt uboczny ustawienia PATHna 2(ścieżka względna, która równie dobrze mogłaby być pod kontrolą atakującego). Można wymienić PATHz LD_LIBRARY_PATHlub IFS... To samo dzieje się x=$((1-x))w bash, zsh i ksh (nie pędzić ani Yash który akceptuje tylko stałych liczbowych tam zmiennych).

Uwaga:

x=$((1-$x))

nie będzie działać poprawnie dla ujemnych wartości $xniektórych powłok, które implementują --operator ( opcjonalny zgodnie z POSIX) (dekrementacja) (jak w przypadku x=-1, oznacza to, że powłoka poprosi o ocenę 1--1wyrażenia arytmetycznego). "$((1-x))"nie ma problemu, ponieważ xjest rozszerzany w ramach (nie wcześniej) oceny arytmetycznej.

W bash, zshi ksh(nie dashlub yash), jeżeli xjest:

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

Następnie rozwinięcie $((1-$x))lub $((1-x))powoduje wykonanie tego unamepolecenia (na przykład zsh, amusi być zmienną tablicową, ale można psvarna przykład użyć do tego).

Podsumowując, nie należy używać zainicjalizowana lub nie odkażone danych zewnętrznych w wyrażeniach arytmetycznych w muszli (zauważ, że ocena arytmetyka mogą być wykonywane przez $((...))(aka $[...]w bashlub zsh), ale również w zależności od powłoki na let, [/ test, declare/typeset/export..., return, break, continue, exit, printf, printwbudowane, indeksy tablic ((..))i [[...]]konstrukty, aby wymienić tylko kilka).

Aby sprawdzić, czy zmienna zawiera dosłowną liczbę dziesiętną, można użyć POSIXly:

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

Uwaga: [0-9]w niektórych lokalizacjach pasuje więcej niż 0123456789. [[:digit:]]powinno być OK, ale nie postawiłbym na to.

Pamiętaj również, że liczby z zerami wiodącymi są w niektórych kontekstach traktowane jako ósemkowe ( 010czasami 10, czasem 8) i strzeż się, że powyższe sprawdzenie pozwoli na liczby, które są potencjalnie większe niż maksymalna liczba całkowita obsługiwana przez system (lub jakąkolwiek inną aplikację) użyj tej liczby całkowitej; na przykład bash traktuje 18446744073709551616 jako 0, ponieważ to 2 64 ). Więc możesz chcieć dodać dodatkowe kontrole w powyższym zestawieniu przypadku, np .:

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

Przykłady:

$ 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

Więcej lektur na:

Stéphane Chazelas
źródło
x='P=3'; : $(($x + 5))zostanie ustawiony Pna 8, ale x='P=3'; : $((x + 5))będzie ustawiona Pna 3(w zsh, kshlub bash). „To samo dzieje się z $((x + 1))...” nie jest teraz poprawne; ustawi się PATHna 2, jak dawniej.
mosvy
@mosvy, dziękuję (i za twoją wcześniejszą edycję). Poprawione teraz.
Stéphane Chazelas