Tôi đã viết điều này như một bản tóm tắt theo phong cách hướng dẫn về câu trả lời xuất sắc của Chris Down ở trên.
Trong bash bạn có thể có các biến shell như thế này
$ t="hi there"
$ echo $t
hi there
$
Theo mặc định, các biến này không được kế thừa bởi các tiến trình con.
$ bash
$ echo $t
$ exit
Nhưng nếu bạn đánh dấu chúng để xuất, bash sẽ đặt cờ có nghĩa là chúng sẽ đi vào môi trường của các quy trình con (mặc dù envp
tham số không được nhìn thấy nhiều, main
trong chương trình C của bạn có ba tham số: main(int argc, char *argv[], char *envp[])
trong đó mảng con trỏ cuối cùng là một mảng của các biến shell với định nghĩa của chúng).
Vì vậy, hãy xuất khẩu t
như sau:
$ echo $t
hi there
$ export t
$ bash
$ echo $t
hi there
$ exit
Trong khi ở trên t
không được xác định trong lớp con, nó sẽ xuất hiện sau khi chúng tôi xuất nó (sử dụng export -n t
nếu bạn muốn dừng xuất nó).
Nhưng các chức năng trong bash là một động vật khác nhau. Bạn tuyên bố chúng như thế này:
$ fn() { echo "test"; }
Và bây giờ bạn có thể gọi hàm bằng cách gọi nó như thể nó là một lệnh shell khác:
$ fn
test
$
Một lần nữa, nếu bạn sinh ra một mạng con, chức năng của chúng tôi không được xuất:
$ bash
$ fn
fn: command not found
$ exit
Chúng ta có thể xuất một hàm với export -f
:
$ export -f fn
$ bash
$ fn
test
$ exit
Đây là phần khó khăn: một hàm xuất như fn
được chuyển đổi thành biến môi trường giống như xuất khẩu biến shell của chúng ta t
ở trên. Điều này không xảy ra khi fn
là một biến cục bộ, nhưng sau khi xuất chúng ta có thể thấy nó là một biến shell. Tuy nhiên, bạn cũng có thể có một biến shell thông thường (tức là không phải hàm) có cùng tên. bash phân biệt dựa trên nội dung của biến:
$ echo $fn
$ # See, nothing was there
$ export fn=regular
$ echo $fn
regular
$
Bây giờ chúng ta có thể sử dụng env
để hiển thị tất cả các biến shell được đánh dấu để xuất và cả hàm thông thường fn
và hàm fn
hiển thị:
$ env
.
.
.
fn=regular
fn=() { echo "test"
}
$
Một lớp vỏ con sẽ nhập cả hai định nghĩa: một là một biến thông thường và một là một hàm:
$ bash
$ echo $fn
regular
$ fn
test
$ exit
Bạn có thể định nghĩa fn
như chúng tôi đã làm ở trên hoặc trực tiếp dưới dạng gán biến thông thường:
$ fn='() { echo "direct" ; }'
Lưu ý đây là một điều cao bất thường để làm! Thông thường chúng ta sẽ định nghĩa hàm fn
như chúng ta đã làm ở trên với fn() {...}
cú pháp. Nhưng vì bash xuất nó qua môi trường, chúng ta có thể "cắt ngắn" trực tiếp theo định nghĩa thông thường ở trên. Lưu ý rằng (đối chiếu với trực giác của bạn, có lẽ) điều này không dẫn đến một chức năng mới fn
có sẵn trong trình bao hiện tại. Nhưng nếu bạn sinh ra một vỏ ** phụ **, thì nó sẽ.
Chúng ta hãy hủy xuất hàm fn
và giữ nguyên thông thường fn
(như được hiển thị ở trên).
$ export -nf fn
Bây giờ hàm fn
không còn được xuất, nhưng biến thông thường fn
là và nó chứa () { echo "direct" ; }
trong đó.
Bây giờ khi một lớp con nhìn thấy một biến thông thường bắt đầu bằng ()
nó sẽ hiểu phần còn lại là một định nghĩa hàm. Nhưng đây chỉ là khi một vỏ mới bắt đầu. Như chúng ta đã thấy ở trên, chỉ cần xác định một biến shell thông thường bắt đầu bằng ()
không làm cho nó hoạt động như một hàm. Bạn phải bắt đầu một subshell.
Và bây giờ là lỗi "shellshock":
Như chúng ta vừa thấy, khi một shell mới ăn vào định nghĩa của một biến thông thường bắt đầu với ()
nó sẽ diễn giải nó như là một hàm. Tuy nhiên, nếu có nhiều hơn được đưa ra sau dấu ngoặc đóng định nghĩa hàm, nó cũng thực thi bất cứ thứ gì có ở đó.
Đây là những yêu cầu, một lần nữa:
- Bash mới được sinh ra
- Một biến môi trường được tiêu hóa
- Biến môi trường này bắt đầu bằng "()" và sau đó chứa phần thân hàm bên trong dấu ngoặc, và sau đó có các lệnh sau đó
Trong trường hợp này, một bash dễ bị tổn thương sẽ thực thi các lệnh sau.
Thí dụ:
$ export ex='() { echo "function ex" ; }; echo "this is bad"; '
$ bash
this is bad
$ ex
function ex
$
Biến xuất thường xuyên ex
được chuyển đến lớp con được hiểu là hàm ex
nhưng các lệnh trailing được thực thi ( this is bad
) khi lớp con sinh ra.
Giải thích về bài kiểm tra một dòng trơn
Một phần mềm phổ biến để kiểm tra lỗ hổng Shellshock là phần được trích dẫn trong câu hỏi của @ jippie:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Đây là một sự cố: đầu tiên :
trong bash chỉ là một tốc ký true
. true
và :
cả hai đều đánh giá (bạn đoán nó) đúng, trong bash:
$ if true; then echo yes; fi
yes
$ if :; then echo yes; fi
yes
$
Thứ hai, env
lệnh (cũng được tích hợp vào bash) in các biến môi trường (như chúng ta đã thấy ở trên) nhưng cũng có thể được sử dụng để chạy một lệnh với một biến xuất (hoặc biến) được cung cấp cho lệnh đó và bash -c
chạy một lệnh từ lệnh đó dòng lệnh:
$ bash -c 'echo hi'
hi
$ bash -c 'echo $t'
$ env t=exported bash -c 'echo $t'
exported
$
Vì vậy, khâu tất cả các công cụ này lại với nhau, chúng ta có thể chạy bash như một lệnh, cung cấp cho nó một số thứ giả để làm (như bash -c echo this is a test
) và xuất một biến bắt đầu bằng ()
để lớp con sẽ hiểu nó là một hàm. Nếu shellshock có mặt, nó cũng sẽ ngay lập tức thực hiện bất kỳ lệnh trailing nào trong subshell. Vì hàm chúng tôi chuyển không liên quan đến chúng tôi (nhưng phải phân tích cú pháp!), Chúng tôi sử dụng hàm hợp lệ ngắn nhất có thể tưởng tượng:
$ f() { :;}
$ f
$
Hàm f
ở đây chỉ thực thi :
lệnh, trả về true và thoát. Bây giờ hãy thêm vào lệnh "ác" đó và xuất một biến thông thường sang một mạng con và bạn thắng. Đây là một lần nữa:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Vì vậy, x
được xuất như một biến thông thường với một hàm hợp lệ đơn giản được echo vulnerable
xử lý đến cuối. Điều này được truyền cho bash và bash diễn giải x
như là một hàm (mà chúng ta không quan tâm) sau đó có thể thực thi echo vulnerable
nếu shellshock có mặt.
Chúng tôi có thể rút ngắn một lớp lót một chút bằng cách xóa this is a test
tin nhắn:
$ env x='() { :;}; echo vulnerable' bash -c :
Điều này không làm phiền với this is a test
nhưng chạy :
lệnh im lặng một lần nữa. (Nếu bạn rời khỏi -c :
thì bạn ngồi trong subshell và phải thoát bằng tay.) Có lẽ phiên bản thân thiện với người dùng nhất sẽ là phiên bản này:
$ env x='() { :;}; echo vulnerable' bash -c "echo If you see the word vulnerable above, you are vulnerable to shellshock"