Bunu, yukarıda Chris Down tarafından verilen mükemmel cevabın bir öğretici tarzı yeniden yazılması olarak yazdım.
Bash'de bunun gibi kabuk değişkenleriniz olabilir
$ t="hi there"
$ echo $t
hi there
$
Varsayılan olarak, bu değişkenler alt işlemler tarafından miras alınmaz.
$ bash
$ echo $t
$ exit
Ancak, bunları dışa aktarma için işaretlerseniz, bash, alt işlemlerin ortamına girecekleri anlamına gelen bir bayrak belirler ( envp
parametre çok görülmese de, main
C programınızda üç parametre vardır: main(int argc, char *argv[], char *envp[])
bu son işaretçi dizisi bir dizidir Kabuk değişkenlerinin tanımlarını içeren).
Öyleyse t
aşağıdaki şekilde ihracat yapalım :
$ echo $t
hi there
$ export t
$ bash
$ echo $t
hi there
$ exit
Oysa yukarıdaki t
alt kabukta tanımlanmadıysa, şimdi dışa aktardıktan sonra görünür ( export -n t
dışa aktarmayı durdurmak istiyorsanız kullanın).
Ancak bash'deki fonksiyonlar farklı bir hayvandır. Onları böyle ilan edersiniz:
$ fn() { echo "test"; }
Ve şimdi, işlevi başka bir kabuk komutundaymış gibi çağırarak çağırmanız yeterlidir:
$ fn
test
$
Bir kez daha, bir deniz kabuğu çıkarırsanız, fonksiyonumuz dışa aktarılmaz:
$ bash
$ fn
fn: command not found
$ exit
Bir işlevi dışa aktarabiliriz export -f
:
$ export -f fn
$ bash
$ fn
test
$ exit
İşin en zor kısmı: benzeri bir dışa fn
aktarma işlevi , kabuk değişkeninin dışa aktarmasının t
yukarıda olduğu gibi bir ortam değişkenine dönüştürülmesidir . fn
Yerel bir değişken olduğunda bu olmaz , ancak dışa aktardıktan sonra onu kabuk değişkeni olarak görebiliriz. Ancak, olabilir de aynı adla normal (yani olmayan fonksiyonu) kabuk değişkeni var. bash değişkenin içeriğine bağlı olarak ayırt eder:
$ echo $fn
$ # See, nothing was there
$ export fn=regular
$ echo $fn
regular
$
Artık env
, dışa aktarma için işaretlenmiş tüm kabuk değişkenlerini ve hem normal fn
hem de işlevin ortaya fn
çıktığını göstermek için kullanabiliriz:
$ env
.
.
.
fn=regular
fn=() { echo "test"
}
$
Bir alt kabuk her iki tanımı da alacaktır: biri normal değişken, biri işlev olarak:
$ bash
$ echo $fn
regular
$ fn
test
$ exit
fn
Yukarıda yaptığımız gibi veya doğrudan normal değişken ataması olarak tanımlayabilirsiniz :
$ fn='() { echo "direct" ; }'
Not Bu yapılacak sıradışı bir şeydir! Normalde işlevi fn
yukarıda fn() {...}
sözdiziminde yaptığımız gibi tanımlardık . Ancak bash onu çevreye ihraç ettiğinden, yukarıdaki normal tanımları doğrudan “kısaltabiliriz”. (Sezginizi sayaç belki) unutmayın bu mu değil yeni bir fonksiyonun neden fn
cari kabuk mevcuttur. Ama bir "alt ** kabuk" ortaya çıkarsanız, o zaman olur.
Fonksiyonun dışa aktarımını iptal edelim fn
ve yeni normal fn
(yukarıda gösterildiği gibi) bozulmadan bırakalım .
$ export -nf fn
Artık işlev fn
artık dışa aktarılmıyor, ancak normal değişken değişiyor fn
ve () { echo "direct" ; }
içinde var.
Şimdi bir alt kabuk, ()
onunla başlayan normal bir değişken gördüğünde , gerisini bir fonksiyon tanımı olarak yorumlar. Ancak bu yalnızca yeni bir kabuk başladığında gerçekleşir. Yukarıda gördüğümüz gibi, sadece normal bir kabuk değişkeni tanımlamak, ()
fonksiyon gibi davranmasına neden olmaz. Bir deniz kabuğu başlatmak zorundasın.
Ve şimdi "kabuklu" böcek:
Az önce gördüğümüz gibi, yeni bir kabuk ()
ondan başlayarak normal bir değişkenin tanımını aldığında onu bir işlev olarak yorumluyor. Bununla birlikte, işlevi tanımlayan kapanış ayracından sonra daha fazla varsa , orada ne varsa onu da uygular .
Bunlar bir kez daha gereksinimlerdir:
- Yeni bash doğuyor
- Bir ortam değişkeni yutulur
- Bu ortam değişkeni "()" ile başlar ve sonra ayraçların içinde bir işlev gövdesi içerir ve daha sonra komutları vardır.
Bu durumda, savunmasız bir bash bu komutları yerine getirir.
Örnek:
$ export ex='() { echo "function ex" ; }; echo "this is bad"; '
$ bash
this is bad
$ ex
function ex
$
Dışa aktarılan normal değişken ex
bir fonksiyon olarak yorumlanan alt kabuğa geçildi, ex
ancak takip komutları ( this is bad
) alt kabuğun doğurduğu şekilde gerçekleştirildi.
Kaygan tek hat testinin açıklanması
Shellshock kırılganlığının test edilmesi için popüler bir tek gömlek @ jippie'nin sorusunda bahsetti:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
İşte bir parçalama: ilk :
olarak bash sadece bir steno true
. true
ve :
her ikisi de, bash olarak (tahmin ettiğiniz gibi) doğru olarak değerlendirilir:
$ if true; then echo yes; fi
yes
$ if :; then echo yes; fi
yes
$
İkincisi, env
komut (bash'a da eklenir) çevre değişkenlerini (yukarıda gördüğümüz gibi) yazdırır, ancak aynı zamanda verilen bir değişkenle (veya değişkenlere) tek bir komutu çalıştırmak için kullanılabilir ve bu komuttan bash -c
tek bir komut çalıştırır. Komut satırı:
$ bash -c 'echo hi'
hi
$ bash -c 'echo $t'
$ env t=exported bash -c 'echo $t'
exported
$
Böylece bütün bunları birlikte dikmek, bash'ı komut olarak çalıştırabiliriz, yapması gereken bazı aptalca şeyler verebiliriz ve onunla bash -c echo this is a test
başlayan bir değişkeni dışa aktarabiliriz, ()
böylece alt kabuk bir fonksiyon olarak yorumlanır. Eğer mermi kovanı mevcutsa, derhal alt kabuktaki herhangi bir takip komutunu da yerine getirecektir. Geçtiğimiz işlev bizim için önemli olmadığı için (ancak ayrıştırılması gerekir) akla gelebilecek en kısa geçerli işlevi kullanırız:
$ f() { :;}
$ f
$
Buradaki işlev f
sadece :
true döndüren ve çıkan komutu çalıştırır . Şimdi bazı "kötülükler" komutunu ekleyiniz ve normal bir değişkeni bir alt kabuğa veriniz ve kazanırsınız. İşte yine tek gömlek:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Bu yüzden sonuna kadar tacked x
basit geçerli bir fonksiyon ile düzenli bir değişken olarak ihraç edilir echo vulnerable
. Bu bash'a geçirilir ve bash x
bir fonksiyon olarak yorumlanır (umurumuzda değil) daha sonra belki de echo vulnerable
muşamba mevcutsa çalıştırır .
this is a test
Mesajı kaldırarak bir astarı biraz kısaltabiliriz :
$ env x='() { :;}; echo vulnerable' bash -c :
Bu canımı sıkmaz this is a test
ama sessiz :
komutu yine çalıştırır. (Eğer -c :
oradan ayrılırsanız , alt kabuğa oturtulur ve manuel olarak çıkmak zorunda kalırsınız.) Belki de en kullanıcı dostu versiyon şudur:
$ env x='() { :;}; echo vulnerable' bash -c "echo If you see the word vulnerable above, you are vulnerable to shellshock"