Giải thích về lệnh để kiểm tra shellshock


32

Đây là lệnh tôi đã sử dụng để kiểm tra shell bash của mình để tìm lỗi Shellshock:

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

Bất cứ ai có thể xin vui lòng giải thích các lệnh chi tiết?


4
Đồng thời xem: unix.stackexchange.com/q/157329/70524 - Câu trả lời của Fixee có thể giúp ích.
muru

Câu trả lời:


45

Câu trả lời này là một dẫn xuất của một bài viết gốc trên Tạp chí Fedora của Matthew Miller, được cấp phép theo giấy phép Creative Commons Attribution-Share Alike 4.0 .

Hãy để tôi giải thích:

env x='() { :;}; echo OOPS' bash -c :

Điều này sẽ in ra OOPS 'trên một hệ thống dễ bị tấn công, nhưng thoát ra một cách im lặng nếu bash đã được vá.

env x='() { :;}; echo OOPS' bash -c "echo this is a test"

Điều này sẽ in ra OOPS 'trên một hệ thống dễ bị tấn công, nhưng in “this is a test”nếu bash đã được vá.

Và có lẽ bạn đã nghe nói rằng nó có liên quan đến các biến môi trường. Nhưng, tại sao mã trong các biến môi trường được thực thi? Chà, đáng ra không phải vậy - nhưng, vì một tính năng mà tôi muốn gọi là quá thông minh vì lợi ích của chính nó, có một số chỗ cho một lỗ hổng. Bash là những gì bạn thấy như một dấu nhắc thiết bị đầu cuối, nhưng nó cũng là một ngôn ngữ kịch bản và có khả năng xác định các chức năng. Bạn làm như thế này:

$ Ubuntu()  { echo "Ubuntu is awesome."; }

và sau đó bạn có một lệnh mới. Hãy nhớ rằng echoở đây chưa thực sự chạy; nó chỉ được lưu như những gì sẽ xảy ra khi chúng ta chạy lệnh mới. Điều này sẽ quan trọng trong một phút!

$ Ubuntu
 Ubuntu is awesome.

Hữu ích! Nhưng, giả sử, vì một số lý do, chúng ta cần thực thi một phiên bản mới của bash, như là một quy trình con và muốn chạy lệnh mới tuyệt vời của tôi theo đó. Câu lệnh bash -c somecommandthực hiện chính xác điều này: chạy lệnh đã cho trong shell mới:

$ bash -c Ubuntu
  bash: Ubuntu: command not found

Ôi. Buồn. Đứa trẻ không kế thừa định nghĩa hàm. Nhưng, nó vốn là môi trường - một tập hợp các cặp khóa-giá trị đã được xuất từ ​​trình bao. (Đây là một khái niệm hoàn toàn mới; nếu bạn chưa quen với điều này, hãy tin tôi ngay bây giờ.) Và, hóa ra, bash cũng có thể xuất các hàm. Vì thế:

$ export -f Ubuntu
$ bash -c Ubuntu
  Ubuntu is awesome.

Đó là tất cả tốt và tốt - ngoại trừ cơ chế mà điều này được thực hiện là tinh ranh . Về cơ bản, vì không có phép thuật Linux / Unix để thực hiện các chức năng trong các biến môi trường, nên hàm xuất thực sự chỉ tạo ra một biến môi trường thông thường có chứa định nghĩa hàm. Sau đó, khi lớp vỏ thứ hai đọc môi trường vào đến của Edward và gặp một biến có nội dung trông giống như một hàm, nó sẽ đánh giá nó.

Về lý thuyết, điều này là hoàn toàn an toàn , bởi vì, hãy nhớ, xác định một chức năng không thực sự thực hiện nó . Ngoại trừ - và đây là lý do tại sao chúng tôi ở đây - có một lỗi trong mã nơi đánh giá không dừng lại khi kết thúc định nghĩa hàm. Nó chỉ kepts đi.

Điều đó sẽ không bao giờ xảy ra khi hàm được lưu trữ trong một biến môi trường được tạo ra một cách hợp pháp, với export -f. Nhưng, tại sao lại hợp pháp? Kẻ tấn công có thể tạo ra bất kỳ biến môi trường cũ nào, và nếu nó trông giống như một hàm, các bash shell mới sẽ nghĩ như vậy!

Vì vậy, trong ví dụ đầu tiên của chúng tôi:

env x='() { :;}; echo OOPS' bash -c "echo this is a test"

Các envlệnh chạy một lệnh với một bộ biến nhất định. Trong trường hợp này, chúng tôi đang thiết lập xmột cái gì đó trông giống như một chức năng. Hàm này chỉ là một lệnh đơn :, đây thực sự là một lệnh đơn giản được định nghĩa là không làm gì cả. Nhưng sau đó, sau khi semi-colonbáo hiệu kết thúc định nghĩa hàm, có một echolệnh. Điều đó không được phép ở đó, nhưng không có gì ngăn cản chúng tôi làm điều đó.

Sau đó, lệnh được đưa ra để chạy với môi trường mới này là một bash shell mới, một lần nữa với lệnh echo this is a testđiều chỉnh hoặc điều không làm gì :, sau đó nó sẽ thoát ra, hoàn toàn vô hại.

Nhưng - ôi! Khi lớp vỏ mới đó khởi động và đọc môi trường, nó sẽ đến xbiến và vì nó trông giống như một hàm, nên nó đánh giá nó. Định nghĩa hàm được tải vô hại - và sau đó tải trọng độc hại của chúng tôi cũng được kích hoạt. Vì vậy, nếu bạn chạy phần trên trên một hệ thống dễ bị tấn công, bạn sẽ được “OOPS”in lại cho bạn. Hoặc, một kẻ tấn công có thể làm điều tồi tệ hơn nhiều so với chỉ in những thứ.


1
Manyas gracias cho một lời giải thích tuyệt vời về lý do tại sao điều này làm việc.
Doug R.

2
Lưu ý rằng envkhông cần thiết. Bạn có thể nhận được kết quả tương tự (đạt / không phụ thuộc vào việc Bash đã được cập nhật hay chưa) bằng cách sử dụng lệnh mà không có nó : x='() { :;}; echo OOPS' bash -c "echo this is a test". Điều này là do trước một lệnh có gán biến sẽ chuyển biến đó và giá trị của nó vào bash -c "..."môi trường của lệnh ( trong trường hợp này).
Tạm dừng cho đến khi có thông báo mới.

1
... nhưng nó có thể là cần thiết trong một số bản vá gần đây. Mọi thứ đang thay đổi.
Tạm dừng cho đến khi có thông báo mới.

4
@DennisWilliamson Việc envcó cần thiết hay không được xác định bởi lớp vỏ mà người ta chạy thử, không phải lớp vỏ đang được thử. (Chúng có thể giống nhau. Ngay cả khi đó, chúng tôi đang kiểm tra cách bash xử lý môi trường của chính nó .) Các kiểu vỏ Bourne chấp nhận NAME=value commandcú pháp; Vỏ kiểu C (ví dụ csh, tcsh) không. Vì vậy, bài kiểm tra có tính di động cao hơn một chút env(với chi phí đôi khi tạo ra sự nhầm lẫn về cách thức hoạt động).
Eliah Kagan

2

Trong phiên bản chưa được vá củabash nó lưu trữ các định nghĩa hàm xuất dưới dạng các biến môi trường.

Lưu trữ một chức năng xnhư,

$ x() { bar; }
$ export -f x

Và kiểm tra định nghĩa của nó là,

$ env | grep -A1 x
x=() {  bar
}

Vì vậy, người ta có thể khai thác điều này bằng cách xác định các biến môi trường của riêng mình và diễn giải chúng như các định nghĩa hàm. Ví dụ env x='() { :;}'sẽ được coi là

x() { :;
}

Lệnh kiểm tra shellshock làm gì,

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

Từ man env,

  1. env - chạy một chương trình trong một môi trường sửa đổi.

  2. :không làm gì ngoài lối thoát với trạng thái thoát 0. xem thêm

  3. Khi một phiên bản mới của bash chưa được khởi chạy là bash -c "echo this is a test", biến môi trường được tạo ra được coi là một hàm và được tải. Theo đó, người ta nhận được đầu ra

    dễ bị tổn thương
    đây là một bài kiểm tra

Lưu ý: Tiếng vang bên ngoài định nghĩa chức năng đã được thực hiện bất ngờ trong quá trình khởi động bash. Định nghĩa hàm chỉ là một bước để đánh giá và khai thác xảy ra, chính định nghĩa hàm và biến môi trường được sử dụng là tùy ý. Shell nhìn vào các biến môi trường, thấy x, trông giống như nó đáp ứng các ràng buộc mà nó biết về định nghĩa hàm trông như thế nào và nó đánh giá dòng, vô tình cũng thực hiện echo (có thể là bất kỳ lệnh nào, độc hại hay không) . Cũng thấy điều này


Tôi vẫn thấy rằng bất kỳ hàm bash nào được xác định, nếu xuất được đánh giá trong shell con trong phiên bản vá của bash. Xem điều này: chayan @ chayan: ~ / testr $ test () {echo "anything"; }; kiểm tra xuất khẩu; bash -c test Ouput: bất cứ điều gì Vì vậy, câu trả lời của bạn có phần không được định hướng đúng. Tôi nghĩ rằng lời giải thích của kasiyA về việc mở rộng biến vượt ra ngoài định nghĩa của nó là chính xác.
heemayl

@heemayl hành vi này là tự nhiên. Nhưng nếu bạn thử env test='() { echo "anything"; }' bash -c "echo otherthing"bạn sẽ thấy ở đầu ra otherthing. Điều đó được sửa chữa trong bản vá. cảm thấy tự do nếu tôi vẫn không rõ ràng.
souravc

Hãy làm cho tôi rõ ràng một lần nữa. Trong bình luận cuối cùng của bạn, chúng tôi về cơ bản là xác định hàm và sau đó báo bash để thực hiện echo. Trong ví dụ này, chúng tôi đã không gọi hàm trong bash. Điều này sẽ không có cùng một đầu ra trong cả bash vá và không vá? Tôi có một khái niệm rằng lỗi về cơ bản là bash đang thực thi các lệnh được đặt sau định nghĩa hàm trong khi hàm không bao giờ được gọi ở bất cứ đâu sau này nếu chúng ta thực hiện điều này env test = '() {echo "anything"; }; echo "foo" 'bash -c "echo otherthing". Hãy làm rõ tôi trong bối cảnh này.
heemayl

@heemayl Tôi đã chỉnh sửa câu trả lời của mình, hy vọng bây giờ thì rõ ràng. Bạn đúng trong ví dụ trong nhận xét cuối cùng của tôi, chúng tôi chưa gọi hàm. Nhưng sự khác biệt là trong một unpatched bashbạn có thể gọi hàm như được định nghĩa, nhưng trong một bản vá bash, định nghĩa không có ở đó.
souravc

@heemayl: Không, điều đó không chính xác. Một Bash đã vá sẽ vẫn truyền định nghĩa hàm vào môi trường của trẻ. Sự khác biệt mà bản vá tạo ra là mã tuân theo định nghĩa hàm ( echo vulnerable) không được thực thi. Lưu ý rằng trong các bản vá mới nhất, hàm đã qua phải có tiền tố cụ thể ( env 'BASH_FUNC_x()'='() { :;}; echo vulnerable' bash -c "echo this is a test"). Một số bản vá gần đây có thể sử dụng %%thay vì đầu tiên ().
Tạm dừng cho đến khi có thông báo mới.
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.