Implikasi Keamanan menggunakan data yang tidak bersih dalam evaluasi Aritmatika Shell

17

Dalam komentar untuk pertanyaan baru - baru ini , Stéphane Chazelas menyebutkan bahwa ada implikasi keamanan terhadap aritmatika kurung ganda seperti:

x=$((1-$x))

pada kebanyakan kerang.

Keterampilan Google saya tampaknya berkarat dan saya tidak dapat menemukan apa pun. Apa implikasi keamanan aritmetika kurung ganda?

garethTheRed
sumber

Jawaban:

22

Masalahnya adalah dalam kasus di mana konten $xbelum disanitasi dan berisi data yang berpotensi berada di bawah kendali penyerang dalam kasus kode shell mungkin akhirnya digunakan dalam konteks eskalasi hak istimewa (misalnya skrip yang dipanggil oleh setuid aplikasi, skrip sudoers atau digunakan untuk memproses data di luar jaringan (CGI, DHCP hook ...) secara langsung atau tidak langsung).

Jika:

x='(PATH=2)'

Kemudian:

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

memiliki efek samping pengaturan PATHke 2(jalur relatif yang bisa sangat di bawah kendali penyerang). Anda dapat mengganti PATHdengan LD_LIBRARY_PATHatau IFS... Hal yang sama terjadi dengan x=$((1-x))di bash, zsh atau ksh (bukan dash atau yash yang hanya menerima konstanta numerik dalam variabel di sana).

Perhatikan bahwa:

x=$((1-$x))

tidak akan berfungsi dengan baik untuk nilai negatif $xdi beberapa shell yang mengimplementasikan --operator ( opsional sesuai POSIX) (pengurangan) (seperti halnya x=-1, itu berarti meminta shell untuk mengevaluasi 1--1ekspresi aritmatika). "$((1-x))"tidak memiliki masalah seperti xyang diperluas sebagai bagian dari (bukan sebelumnya) evaluasi aritmatika.

In bash, zshand ksh(not dashor yash), if xadalah:

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

Kemudian perluasan $((1-$x))atau $((1-x))menyebabkan unameperintah itu dieksekusi (untuk zsh, aperlu variabel array, tetapi orang dapat menggunakan psvarmisalnya untuk itu).

Singkatnya, orang tidak boleh menggunakan uninitialised atau non-disterilkan data eksternal dalam ekspresi aritmatika pada kulit (catatan bahwa evaluasi aritmatika dapat dilakukan oleh $((...))(alias $[...]di bashatau zsh) tetapi juga tergantung pada shell di let, [/ test, declare/typeset/export..., return, break, continue, exit, printf, printbawaan, indeks array, ((..))dan[[...]] konstruksi untuk beberapa nama).

Untuk memeriksa apakah suatu variabel berisi angka integer desimal literal, Anda dapat menggunakan POSIXly:

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

Berhati-hatilah karena [0-9]di beberapa lokal cocok dengan lebih dari 0123456789.[[:digit:]] harus OK tapi saya tidak akan bertaruh.

Juga ingat bahwa angka-angka dengan nol di depan diperlakukan sebagai oktal dalam beberapa konteks ( 010kadang-kadang 10, kadang-kadang 8) dan berhati-hatilah bahwa pemeriksaan di atas akan membiarkan angka-angka yang berpotensi lebih besar daripada bilangan bulat maksimum yang didukung oleh sistem Anda (atau aplikasi apa pun yang Anda inginkan) gunakan integer itu di; bash misalnya memperlakukan 18446744073709551616 sebagai 0 karena itu 2 64 ). Jadi, Anda mungkin ingin menambahkan cek tambahan dalam pernyataan kasus di atas seperti:

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

Contoh:

$ 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

Lebih banyak membaca di:

Stéphane Chazelas
sumber
x='P=3'; : $(($x + 5))akan diatur Pke 8, tetapi x='P=3'; : $((x + 5))akan diatur Pke 3(dalam zsh, kshatau bash). "Hal yang sama terjadi dengan $((x + 1))..." tidak benar sekarang; itu akan diatur PATHke 2, pada yang lama.
Mosvy
@mosvy, terima kasih benar (dan untuk edit Anda sebelumnya). Diperbaiki sekarang.
Stéphane Chazelas