Ý nghĩa bảo mật của việc sử dụng dữ liệu không được xác thực trong đánh giá số học Shell


17

Trong một bình luận cho một câu hỏi gần đây , Stéphane Chazelas đề cập rằng có những hàm ý bảo mật đối với dấu ngoặc kép số học như:

x=$((1-$x))

trên hầu hết các vỏ.

Các kỹ năng Google của tôi dường như bị hoen rỉ và tôi không thể tìm thấy bất cứ điều gì. Ý nghĩa bảo mật của dấu ngoặc kép số học là gì?

Câu trả lời:


22

Vấn đề là trong trường hợp nội dung của $xnó không được vệ sinh và chứa dữ liệu có khả năng nằm dưới sự kiểm soát của kẻ tấn công trong trường hợp mã shell có thể sẽ được sử dụng trong bối cảnh leo thang đặc quyền (ví dụ: tập lệnh được gọi bởi setuid ứng dụng, tập lệnh sudoers hoặc được sử dụng để xử lý dữ liệu ngoài mạng (CGI, DHCP hook ...) trực tiếp hoặc gián tiếp).

Nếu:

x='(PATH=2)'

Sau đó:

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

có tác dụng phụ của việc thiết PATHđể 2(một đường dẫn tương đối mà rất có thể là dưới sự kiểm soát của những kẻ tấn công). Bạn có thể thay thế PATHbằng LD_LIBRARY_PATHhoặc IFS... Điều tương tự xảy ra với x=$((1-x))bash, zsh hoặc ksh (không phải dấu gạch ngang cũng như yash chỉ chấp nhận các hằng số trong các biến ở đó).

Lưu ý rằng:

x=$((1-$x))

sẽ không hoạt động chính xác cho các giá trị âm của $xmột số shell triển khai toán tử (tùy chọn theo POSIX) --(giảm dần) x=-1, như có nghĩa là yêu cầu shell đánh giá 1--1biểu thức số học). "$((1-x))"không có vấn đề như xđược mở rộng như là một phần của (không phải trước đây) việc đánh giá số học.

Trong bash, zshksh(không dashhay yash), nếu xlà:

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

Sau đó, việc mở rộng $((1-$x))hoặc $((1-x))khiến unamelệnh đó được thực thi (for zsh, acần phải là một biến mảng, nhưng người ta có thể sử dụng psvarví dụ cho điều đó).

Nói tóm lại, người ta không nên sử dụng uninitialised hoặc không vệ sinh dữ liệu bên ngoài trong các biểu thức số học trong vỏ (lưu ý rằng đánh giá số học có thể được thực hiện bằng $((...))(aka $[...]trong bashhoặc zsh) mà còn phụ thuộc vào vỏ trong let, [/ test, declare/typeset/export..., return, break, continue, exit, printf, printnội trang, chỉ mục mảng ((..))[[...]]cấu trúc để đặt tên cho một số).

Để kiểm tra xem một biến có chứa số nguyên thập phân bằng chữ hay không, bạn có thể sử dụng POSIXly:

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

Coi chừng rằng [0-9]ở một số địa phương khớp với hơn 0123456789. [[:digit:]]sẽ ổn thôi nhưng tôi sẽ không đặt cược vào nó.

Cũng cần nhớ rằng các số có số 0 đứng đầu được coi là số bát phân trong một số ngữ cảnh ( 010đôi khi là 10, đôi khi là 8) và hãy cẩn thận rằng kiểm tra ở trên sẽ cho phép các số có khả năng lớn hơn số nguyên tối đa được hệ thống của bạn hỗ trợ (hoặc bất kỳ ứng dụng nào bạn sẽ sử dụng số nguyên đó trong; bash ví dụ xử lý 18446744073709551616 là 0 như 2 64 ). Vì vậy, bạn có thể muốn thêm kiểm tra bổ sung trong trường hợp đó ở trên như:

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

Ví dụ:

$ 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

Đọc thêm tại:


x='P=3'; : $(($x + 5))sẽ thiết lập Pđến 8, nhưng x='P=3'; : $((x + 5))sẽ thiết lập Pđể 3(trong zsh, kshhoặc bash). "Điều tương tự xảy ra với $((x + 1))..." hiện không chính xác; nó sẽ thiết lập PATHđể 2, như thuở xưa.
mosvy

@mosvy, cảm ơn ngay (và cho lần chỉnh sửa trước đó của bạn). Sửa chữa ngay.
Stéphane Chazelas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.