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 ( envpparametre çok görülmese de, mainC 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 taşağıdaki şekilde ihracat yapalım :
$ echo $t
hi there
$ export t
$ bash
$ echo $t
hi there
$ exit
Oysa yukarıdaki talt kabukta tanımlanmadıysa, şimdi dışa aktardıktan sonra görünür ( export -n tdış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 fnaktarma işlevi , kabuk değişkeninin dışa aktarmasının tyukarıda olduğu gibi bir ortam değişkenine dönüştürülmesidir . fnYerel 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 fnhem 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
fnYukarı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 fnyukarı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 fncari kabuk mevcuttur. Ama bir "alt ** kabuk" ortaya çıkarsanız, o zaman olur.
Fonksiyonun dışa aktarımını iptal edelim fnve yeni normal fn(yukarıda gösterildiği gibi) bozulmadan bırakalım .
$ export -nf fn
Artık işlev fnartık dışa aktarılmıyor, ancak normal değişken değişiyor fnve () { 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 exbir fonksiyon olarak yorumlanan alt kabuğa geçildi, exancak 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. trueve :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, envkomut (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 -ctek 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 testbaş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 fsadece :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 xbasit geçerli bir fonksiyon ile düzenli bir değişken olarak ihraç edilir echo vulnerable. Bu bash'a geçirilir ve bash xbir fonksiyon olarak yorumlanır (umurumuzda değil) daha sonra belki de echo vulnerablemuşamba mevcutsa çalıştırır .
this is a testMesajı kaldırarak bir astarı biraz kısaltabiliriz :
$ env x='() { :;}; echo vulnerable' bash -c :
Bu canımı sıkmaz this is a testama 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"