Dahili komutun bash'de kullanımını açık ve güvenli bir şekilde nasıl zorlarım


19

Bir var benzer bir soru bu örneğin değiştirmek istiyorum 'sarma' senaryosu ile fırsatlar cdyerleşiğini çağıran bir komutla cd.

Ancak, shellshock ve arkadaşlarının ışığında ve bash'ın çevreden işlevleri aldığını bilerek, birkaç test yaptım ve yerleşik kodumu güvenli bir şekilde çağırmak için bir yol bulamıyorum cd.

Bunu düşün

cd() { echo "muahaha"; }
export -f cd

Bu ortamda kullanarak çağrılan komut dosyaları cdbozulur (benzer bir şeyin etkilerini göz önünde bulundurun cd dir && rm -rf .).

Bir komutun türünü (uygun olarak adlandırılır type) kontrol eden komutlar ve bir işlev ( builtinve command) yerine yerleşik sürümü yürütme komutları vardır . Ancak, bak ve bunlar, fonksiyonlar kullanılarak da geçersiz kılınabilir

builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }

Aşağıdakileri verecektir:

$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha

Tüm ortamı temizlemeden bash'ı yerleşik komutu kullanmaya zorlamak veya en azından bir komutun yerleşik olmadığını algılamanın bir yolu var mı?

Birisi ortamınızı kontrol ederse muhtemelen zaten vidalandığınızı anlıyorum, ancak en azından takma adlar için, takma adını \önüne ekleyerek çağırma seçeneğiniz var .


daha envönce şu komutu kullanarak komut dosyanızı çalıştırabilirsiniz :env -i <SCRIPT.sh>
Arkadiusz Drabczyk

Sadece envbir işlev olarak yeniden tanımlanmamışsa. Bu çok korkutucu. Öncelikle özel karakterlerin yardımcı olacağını düşündüm - kaynağa /kullanarak .vb. İçeren tam yolla çağrı . Ancak bunlar işlev adları için de kullanılabilir! Sen edebilirsiniz İstediğiniz fonksiyonu yeniden tanımlamak, ancak orijinal komutunu çağırarak geri almak zordur.
orion

1
Doğru, ancak güvenliği ihlal edilmiş bir makinede herhangi bir komut dosyası çalıştıracaksanız, zaten vidalanmış olursunuz. Alternatif olarak, #/bin/shbu komut dosyasını varsayılan etkileşimli kabuk değilse yazın.
Arkadiusz Drabczyk

Yanıtlar:


16

Olivier D neredeyse doğrudur, ama koşmadan POSIXLY_CORRECT=1önce ayarlamanız gerekir unset. POSIX'in Özel Yerleşikler kavramı vardır ve bash bunu destekler . unsetböyle bir yapıdır. Ara SPECIAL_BUILTINyılında builtins/*.clistesi için bash kaynağı, içerdiği set, unset, export, evalve source.

$ unset() { echo muahaha-unset; }
$ unset unset
muahaha-unset
$ POSIXLY_CORRECT=1
$ unset unset

Sahtekar unsetşimdi unset eğer çevreden kaldırıldı command, type, builtindaha sonra devam etmek mümkün olmalıdır, ancak unset POSIXLY_CORRECTolmayan POSIX davranışı veya gelişmiş bash özellikleri dayanarak eğer.

Bu , diğer adları ele almaz , bu nedenle \unsetetkileşimli kabukta çalıştığından emin olmak için kullanmalısınız (veya her zaman, expand_aliasesyürürlükte ise).

Paranoid, bu olmalıdır her şeyi düzeltmek, ben düşünüyorum:

POSIXLY_CORRECT=1
\unset -f help read unset
\unset POSIXLY_CORRECT
re='^([a-z:.\[]+):' # =~ is troublesome to escape
while \read cmd; do 
    [[ "$cmd" =~ $re ]] && \unset -f ${BASH_REMATCH[1]}; 
done < <( \help -s "*" )

( while, do, doneVe [[kelimeleri ayrılmıştır ve önlemler gerekmez.) Kullandığımız Not unset -ftanımsız işlevlere emin olmak için, değişkenler ve fonksiyonlar aynı ad paylaşan rağmen ikisinin de aynı anda (Etan Reisner sayesinde) durumda var olması için mümkün iki kez ayar yapmak da hile yapar. Sen olabilir , bash size bir salt okunur işlevini unsetting ve bash-4.2, bash-4.3 engellemez gelmez dahil engellemez salt okunur bir işlev işaretlemek ama ne zaman hala özel yerleşiklerinden onurlandırıyor POSIXLY_CORRECTayarlanır.

Bir salt okunur POSIXLY_CORRECTgerçek bir sorun değildir, bu bir boolean değildir veya varlığını işaretlemek POSIX modunu etkinleştirir, bu nedenle bir salt okunur olarak mevcutsa, değer boş veya 0 olsa bile POSIX özelliklerine güvenebilirsiniz. belki bazı kes ve yapıştır ile sorunlu işlevleri yukarıda belirtilenden farklı bir şekilde ayarlayın:

\help -s "*" | while IFS=": " read cmd junk; do echo \\unset -f $cmd; done

(ve hataları görmezden gelmeyin ) veya başka komut dosyalarına katılın .


Diğer notlar:

  • functionayrılmış bir kelimedir, diğer adla değiştirilebilir, ancak bir işlevle geçersiz kılınamaz. (Aliasing functionçünkü hafif zahmetli \function değildir atlayarak bir yolu olarak kabul edilebilir)
  • [[, ]]ayrılmış kelimelerdir, takma adla (yok sayılacak) ancak bir işlevle geçersiz kılınamaz (işlevler bu şekilde adlandırılabilir)
  • (( bir işlev veya geçerli bir ad değil

İlginç, teşekkürler! Bana bash'ın ve diğerlerinin üzerine yazılmamaya karşı koruma vermemesi garip geliyor unset.
falstro

Bunun -ftartışmaya ihtiyacı unsetvar değil mi? Aksi takdirde, hem yerleşik ile aynı adlı bir değişken hem de işlev tanımlanırsa, önce belirlenecek unsetdeğişkeni seçer. Ayrıca, gizleme işlevlerinden herhangi biri ayarlanmışsa bu başarısız olur readonly, değil mi? (Bu algılanabilir ve ölümcül bir hata yapılabilir.) Ayrıca bu [göründüğü yerleşik özlüyor .
Etan Reisner

1
\unset -f unsetOkuma döngüsünde yapılacak göz önüne alındığında, mantıklı olduğunu düşünmüyorum . Eğer unsetbir işlev \unsetnormalde yerleşik yerine çözemezsiniz, ancak \unsetPOSIX modu etkin olduğu sürece güvenle kullanabilirsiniz . Açıkça çağıran \unset -füzerinde [, .ve :senin regex dışlar onları da olsa iyi bir fikir olabilir. Ben de eklersiniz -fiçin \unsetdöngü içinde ve yatak \unset POSIXLY_CORRECTyerine daha önce, döngü sonra. \unalias -a(after \unset -f unalias) ayrıca sonraki komutlarda güvenli bir şekilde kaçmayı sağlar.
Adrian Günter

1
@ AdrianGünter Deneyin: [[ ${POSIXLY_CORRECT?non-POSIX mode shell is untrusted}x ]]Bu, etkileşimli olmayan bir komut dosyasının, değişken ayarlanmamışsa belirtilen hatayla çıkmasına veya ayarlanmışsa (boş veya herhangi bir değer) devam etmesine neden olur.
mr.spuratic

1
"kullanmalısınız \unset" ... Unutulmamalıdır ki, herhangi bir karakter (ler) den alıntı yapmak, sadece birincisi değil, takma ad genişlemesini önlemek için işe yarayacaktır. un"se"tdaha az okunabilir olsa da, aynı şekilde çalışır. "Her basit komutun ilk sözcüğü, belirtilmemişse, bir takma adı olup olmadığını kontrol eder." - Bash Ref
Robin A. Meade

6

Birisi çevrenizi kontrol ederse muhtemelen berbat olduğunuzu anlıyorum

Evet bu. Bilinmeyen bir ortamda bir komut dosyası çalıştırırsanız LD_PRELOAD, kabuk işleminin komut dosyanızı okumadan önce rasgele kod yürütmesine neden olmaktan başlayarak her şey ters gidebilir . Komut dosyasının içinden düşmanca bir ortama karşı koruma teşebbüsü boştur.

Sudo, on yıldan uzun bir süredir bash işlev tanımına benzeyen her şeyi kaldırarak çevreyi dezenfekte ediyor. Shellshock'tan beri , tam olarak güvenilir olmayan bir ortamda kabuk komut dosyası çalıştıran diğer ortamlar da bunu izledi.

Güvenilmeyen bir varlık tarafından ayarlanan bir ortamda komut dosyasını güvenli bir şekilde çalıştıramazsınız. Bu nedenle işlev tanımları hakkında endişe duymak verimli değildir. Ortamınızı sterilize edin ve böylelikle bash işlev tanımları olarak yorumlanacak değişkenler.


1
Buna tamamen katılmıyorum. Güvenlik, "sterilize edilmiş" veya "onaylanmamış" merkezli bir ikili öneri değildir. Bu, sömürü fırsatlarını kaldırmakla ilgilidir. Ne yazık ki, modern sistemlerin karmaşıklığı, düzgün bir şekilde kilitlenmesi gereken birçok sömürü fırsatı olduğu anlamına gelir. Sömürü fırsatlarının birçoğu, PATH değişkenini değiştirmek, yerleşik işlevleri yeniden tanımlamak, vb. Gibi zararsız görünen yukarı akış saldırıları etrafında odaklanır.
Dejay Clayton

@DejayClayton İlk cümle hariç yorumunuza tamamen katılıyorum, çünkü cevabımın hiçbir şekilde nasıl çeliştiğini görmüyorum. Bir sömürü fırsatını kaldırmak yardımcı olur, ancak saldırıda önemsiz bir ayarın çalışmaya devam etmesine izin verdiği yerde yarısını kaldırmamak.
Gilles 'SO- kötü olmayı bırak

Demek istediğim, sadece "ortamınızı sterilize edemezsiniz" ve sonra çeşitli saldırı vektörleri hakkında endişelenmeyi bırakamazsınız. Bazen "senaryonun içinden düşmanca bir ortama karşı korunmak" gerekir. "İşlev tanımı" sorununu çözseniz bile, birisinin bir dizine "cat" veya "ls" adlı özel bir komut dosyası ve daha sonra "cat" ı çağıran herhangi bir komut dosyası bulabileceği PATH gibi şeyler hakkında endişelenmeniz gerekir. "veya" ls "yerine" / bin / cat "ve" / bin / ls "etkin bir istismar yürütüyor.
Dejay Clayton

@DejayClayton Açıkça çevreyi dezenfekte etmek, çevre ile ilgisi olmayan saldırı vektörlerine yardımcı olmaz. (Örneğin /bin/cat, bir chroot'u çağıran bir komut dosyası herhangi bir şeyi çağırıyor olabilir.) Çevreyi sterilize etmek size bir aklı başında gelir PATH(tabii ki doğru yaptığınızı varsayarsak). Hala ne demek istediğini görmüyorum.
Gilles 'SO- kötü olmayı bırak'

PATH'ın istismarlar için en büyük fırsatlardan biri olduğunu ve birçok şüpheli PATH uygulamasının güvenlik bloglarında bile önerilen tavsiye olarak belgelendiğini ve bazen yüklü uygulamaların bu tür uygulamaların çalışmasını sağlamak için PATH'ı yeniden sıraladığını düşünerek, bir senaryoda savunma kodlaması kötü bir fikir olabilir. Aklı başında bir PATH olduğunu düşündüğünüz şey aslında karşılaşmadığınız saldırılara karşı savunmasız olabilir.
Dejay Clayton

1

unset -fYerleşik, komut ve tür işlevlerini kaldırmak için kullanabilirsiniz .


2
üzgünüm, unset() { true; }bununla ilgilenir.
falstro

1
Lanet olsun! Tanımlı fonksiyonları listelemek de bir yerleşik olana dayanır. Pes ediyorum!
odc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.