it-swarm-tr.com

Shell komut dosyalarında setuid'e izin ver

setuid izin biti Linux'a yürütücü yerine sahibinin etkin kullanıcı kimliğine sahip bir program çalıştırmasını söyler:

> cat setuid-test.c

#include <stdio.h>
#include <unistd.h>

int main(int argc, char** argv) {
    printf("%d", geteuid());
    return 0;
}

> gcc -o setuid-test setuid-test.c
> ./setuid-test

1000

> Sudo chown nobody ./setuid-test; Sudo chmod +s ./setuid-test
> ./setuid-test

65534

Ancak, bu yalnızca yürütülebilir dosyalar için geçerlidir; Kabuk komut dosyaları setuid bitini yok sayar:

> cat setuid-test2

#!/bin/bash
id -u

> ./setuid-test2

1000

> Sudo chown nobody ./setuid-test2; Sudo chmod +s ./setuid-test2
> ./setuid-test2

1000

Wikipedia diyor :

Güvenlik hataları olasılığının artması nedeniyle, birçok işletim sistemi yürütülebilir Shell komut dosyalarına uygulandığında setuid özniteliğini yoksayar.

Bu riskleri kabul etmeye istekli olduğumu varsayarsak, Linux'a setuid bitini çalıştırılabilir dosyalarda olduğu gibi Shell betiklerinde de aynı şekilde ele almasını söylemenin bir yolu var mı?

Değilse, bu sorun için ortak bir geçici çözüm var mı? Şu anki çözümüm, sudoers 'nin belirli bir komut dosyasını çalışmasını istediğim kullanıcı olarak çalıştırmasına izin vermek için ALL girişi eklemektir. Parola İstemi'ni önlemek için NOPASSWD ile. Bunun ana dezavantajı, bunu her yapmak istediğimde bir sudoers girişine ihtiyaç duyulması ve arayan kişinin Sudo some-script yerine _ some-script

195
Michael Mrozek

Linux, yorumlanan tüm yürütülebilir dosyalarda (yani #! Satırından başlayarak yürütülebilir dosyalar) setuid¹ bitini yoksayar. comp.unix.questions SSS , setuid Shell betiklerindeki güvenlik sorunlarını açıklar. Bu problemler iki çeşittir: Shebang ve Shell ile ilgili; Aşağıda daha fazla ayrıntıya giriyorum.

Güvenliği önemsemiyorsanız ve setuid komut dosyalarına izin vermek istiyorsanız, Linux altında çekirdeği yamalamanız gerekir. 3.x çekirdekleri itibarıyla install_exec_creds işlevine load_script işlevine çağrı eklemeniz gerektiğini düşünüyorum. open_exec, Ancak test etmedim.


Setuid Mesele

Shebang'ın (#!) Tipik olarak uygulanma biçiminin doğasında var olan bir yarış koşulu vardır:

  1. Çekirdek yürütülebilir dosyayı açar ve #! İle başladığını bulur.
  2. Çekirdek çalıştırılabilir dosyayı kapatır ve bunun yerine yorumlayıcıyı açar.
  3. Çekirdek, komut dosyasının yolunu argüman listesine ekler (argv[1] Gibi) ve yorumlayıcıyı yürütür.

Bu uygulama ile setuid komut dosyalarına izin verilirse, bir saldırgan varolan bir setuid komut dosyasına sembolik bir bağlantı oluşturarak, onu yürüterek ve çekirdek adım 1'i gerçekleştirdikten sonra ve yorumlayıcı ulaşmadan önce bağlantıyı değiştirerek düzenleme yaparak rasgele bir komut dosyası çağırabilir. ilk argümanını açıyor. Bu nedenle, çoğu unice bir Shebang algıladıklarında setuid bit yoksayılır.

Bu uygulamayı güvence altına almanın bir yolu, yorumlayıcı açılana kadar çekirdeğin komut dosyasını kilitlemesidir (bunun yalnızca dosyanın bağlantısını kaldırmayı veya üzerine yazmayı değil, aynı zamanda yoldaki herhangi bir dizini yeniden adlandırmayı da engellemesi gerektiğini unutmayın). Ancak unix sistemleri zorunlu kilitlerden uzak durma eğilimindedir ve sembolik bağlantılar doğru bir kilit özelliğini özellikle zor ve invaziv hale getirir. Kimsenin bunu böyle yaptığını sanmıyorum.

Birkaç unix sistemi (çoğunlukla OpenBSD, NetBSD ve Mac OS X, bunların tümü için bir çekirdek ayarının etkinleştirilmesi gerekir), ek bir özellik kullanarak uygulamak secure setuid Shebang yol /dev/fd/N, Dosya tanımlayıcısında zaten açılmış olan dosyayı ifade eder [~ # ~] n [~ # ~] (böylece /dev/fd/N Açmak kabaca dup(N)). Birçok unix sisteminde (Linux dahil) /dev/fd Vardır ancak setuid komut dosyaları yoktur.

  1. Çekirdek yürütülebilir dosyayı açar ve #! İle başladığını bulur. Diyelim ki yürütülebilir dosya için dosya tanımlayıcı 3.
  2. Çekirdek yorumlayıcıyı açar.
  3. Çekirdek /dev/fd/3 Argüman listesini ekler (argv[1] Gibi) ve yorumlayıcıyı yürütür.

Sven Mascheck'in Shebang sayfası , setuid desteği dahil olmak üzere, birlikler arasında Shebang hakkında birçok bilgiye sahiptir.


Setuid tercümanlar

İşletim sisteminizin setuid Shebang'ı desteklemesi veya yerel bir ikili sarıcı (Sudo gibi) kullandığınız için programınızı kök olarak çalıştırmayı başardığınızı varsayalım. Bir güvenlik açığı açtınız mı? Belki . Buradaki yorumlanmış ve derlenmiş programlarla ilgili not. Sorun, çalışma zamanı sistemi ayrıcalıklarla yürütüldüğünde güvenli davranıp davranmadığıdır.

  • Dinamik olarak bağlı herhangi bir yerel ikili yürütülebilir program, programın gerektirdiği dinamik kitaplıkları yükleyen dinamik yükleyici (örn. /lib/ld.so) Tarafından yorumlanır. Birçok unice'de, dinamik kitaplıkların arama yolunu ortam aracılığıyla yapılandırabilirsiniz (LD_LIBRARY_PATH Ortam değişkeni için ortak bir addır) ve hatta çalıştırılan tüm ikili dosyalara ek kitaplıklar yükleyebilirsiniz (LD_PRELOAD) . Programın davetlisi, libc.so İçine (diğer taktiklerin yanı sıra) özel hazırlanmış bir $LD_LIBRARY_PATH Yerleştirerek o program bağlamında rastgele kod yürütebilir. Tüm aklı başında sistemler, setuid yürütülebilir dosyalarındaki LD_* Değişkenlerini yok sayar.

  • Sh, csh ve türevleri gibi kabukları ortam değişkenleri otomatik olarak Kabuk parametreleri olur. PATH, IFS ve daha fazlası gibi parametreler aracılığıyla, komut dosyasının davetçisi Shell komut dosyalarının bağlamında rasgele kod yürütmek için birçok fırsata sahiptir. Bazı kabuklar, komut dosyasının ayrıcalıklarla çağrıldığını algılarsa bu değişkenleri aklı başında varsayılanlara ayarlar, ancak güvenebileceğim belirli bir uygulama olduğunu bilmiyorum.

  • Çoğu çalışma ortamı (yerel, bayt kodu veya yorumlanmış olsun) benzer özelliklere sahiptir. Yerli kodu çalıştıranlar genellikle dinamik bağlantıdan (daha fazla önlem alır) daha süslü bir şey yapmasa da, setuid yürütülebilir dosyalarda çok az özel önlem alın.

  • Perl dikkate değer bir istisnadır. It setuid komut dosyalarını güvenli bir şekilde açıkça destekler. Aslında, işletim sisteminiz komut dosyalarındaki setuid bitini göz ardı etse bile betiğiniz setuid çalıştırabilir. Bunun nedeni, Perl'in gerekli kontrolleri gerçekleştiren ve istenen ayrıcalıklarla istenen kodlarda yorumlayıcıyı yeniden başlatan bir setuid kök yardımcısıyla birlikte gönderilmesidir. Bu perlsec kılavuzunda açıklanmıştır. Eskiden setuid Perl betikleri #!/usr/bin/suidperl -wT Yerine #!/usr/bin/Perl -wT Gerekliydi, ancak çoğu modern sistemde #!/usr/bin/Perl -wT Yeterlidir.

Yerel bir ikili sarıcısı kullanmanın bu sorunları önlemek için kendi başına hiçbir şey yapmadığını unutmayın . Aslında, durumu daha kötü yapabilir, çünkü çalışma zamanı ortamınızın ayrıcalıklarla çağrıldığını algılamasını ve çalışma zamanı yapılandırmasını atlamasını engelleyebilir.

Yerel bir ikili sarmalayıcı, sarmalayıcı çevreyi temizliyorsa bir Kabuk komut dosyasını güvenli hale getirebilir. Komut dosyası çok fazla varsayımda bulunmamaya dikkat etmelidir (ör. Geçerli dizin hakkında), ancak bu devam eder. Çevreyi sterilize etmek için kurulmuş olması koşuluyla Sudo'yu kullanabilirsiniz. Kara listeye alma değişkenleri hataya açıktır, bu nedenle her zaman beyaz liste. Sudo ile, env_reset Seçeneğinin açık olduğundan, setenv öğesinin kapalı olduğundan ve env_file Ve env_keep Öğelerinin yalnızca zararsız değişkenler içerdiğinden emin olun.


TL, DR:

  • Setuid Shebang güvensizdir ancak genellikle göz ardı edilir.
  • Ayrıcalıklarla (Sudo veya setuid aracılığıyla) bir program çalıştırırsanız, yerel kod veya Perl yazın veya programı çevreyi sterilize eden bir sarıcıyla başlatın (env_reset Seçeneğiyle Sudo gibi).

¹ Bu tartışma, “setuid” yerine “setgid” yerine geçerseniz eşit olarak geçerlidir; her ikisi de komut dosyalarındaki Linux çekirdeği tarafından yoksayılır

Bu sorunu çözmenin bir yolu, setuid bitini kullanabilen bir programdan Shell komut dosyasını çağırmaktır.
Sudo gibi bir şey. Örneğin, bunu bir C programında nasıl başaracağınız aşağıda açıklanmıştır:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    setuid( 0 );   // you can set it at run time also
    system( "/home/pubuntu/setuid-test2.sh" );
    return 0;
 }

Setuid-test2.c olarak kaydedin.
Derleme
Şimdi bu program ikili setini yap:

su - nobody   
[enter password]  
chown nobody:nobody a.out  
chmod 4755 a.out  

Şimdi, onu çalıştırabilmelisiniz ve betiğinizin kimsenin izni olmadan yürütüldüğünü göreceksiniz.
Ama burada ayrıca kod yolunu sabit kodlamanız veya yukarıdaki exe'ye komut satırı arg olarak iletmeniz gerekiyor.

57
Hemant

Ben bu teknede olan birkaç script önek:

#!/bin/sh
[ "root" != "$USER" ] && exec Sudo $0 "[email protected]"

Bunun setuid kullanmadığını, ancak geçerli dosyayı Sudo ile yürüttüğünü unutmayın.

24
rcrowley

Sudo some_script şunları yapabilirsiniz:

  #!/ust/bin/env sh

  Sudo /usr/local/scripts/your_script

SETUID programlarının kök ayrıcalıklarıyla çalıştıklarından ve kullanıcılar üzerinde büyük bir kontrole sahip oldukları için çok dikkatli bir şekilde tasarlanması gerekir. Her şeyi akılcı kontrol etmeleri gerekiyor. Komut dosyaları ile yapamazsınız çünkü:

  • Kabuklar, kullanıcılarla yoğun etkileşime giren büyük yazılım parçalarıdır. Her şeyin akıl sağlığını kontrol etmek neredeyse imkansızdır - özellikle kodun çoğu bu modda çalışmak için tasarlanmadığından.
  • Komut dosyaları çoğunlukla çabuk bir çözümdür ve genellikle setuid'e izin verecek kadar özenle hazırlanmazlar. Potansiyel olarak tehlikeli birçok özelliğe sahiptirler.
  • Diğer programlara büyük ölçüde bağımlıdırlar. Kabuğun kontrol edilmesi yeterli değildir. sed, awk vb. de kontrol edilmesi gerekiyor

Lütfen Sudo bazı sağlık kontrolü sağlıyor ancak yeterli değil - kendi kodunuzdaki her satırı kontrol edin.

Son bir not olarak: yetenekleri kullanmayı düşünün. Kullanıcı olarak çalışan bir işleme normal olarak kök ayrıcalıkları gerektiren özel ayrıcalıklar vermenize izin verir. Ancak, ping ağ üzerinde değişiklik yapsa da, dosyalara erişmesi gerekmez. Ancak kalıtsal olup olmadıklarından emin değilim.

12
Maciej Piechotka

süper [-r reqpath] komutu [args]

Süper, belirtilen kullanıcıların komut dosyalarını (veya diğer komutları) kök gibi çalıştırmasına izin verir; veya komutu çalıştırmadan önce uid, gid ve/veya ek grupları her komut için ayrı ayrı ayarlayabilir. Komut dosyalarını setuid kökü yapmaya güvenli bir alternatif olması amaçlanmıştır. Süper, sıradan kullanıcıların başkaları tarafından yürütülmesi için komutlar sağlamasına da izin verir; bunlar komutu sunan kullanıcının uid, gid ve gruplarıyla yürütülür.

Super, kullanıcının istenen komutu yürütmesine izin verilip verilmediğini görmek için bir `` super.tab '' dosyasına başvurur. İzin verilirse, süper pgm [args] komutunu yürütür; burada pgm bu komutla ilişkilendirilmiş programdır. (Kökün varsayılan olarak yürütülmesine izin verilir, ancak bir kural root'u dışlarsa yine de reddedilebilir. Sıradan kullanıcıların varsayılan olarak yürütülmesine izin verilmez.)

Komut, süper programa sembolik bir bağlantıysa (veya sabit bağlantıysa),% komut args yazmak,% super komut args yazmakla eşdeğerdir (Komut süper olmamalı veya süper, bir program aracılığıyla çağrıldığını algılamaz bağlantı.)

http://www.ucolick.org/~will/RUE/super/README

http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html

5
Nizam Mohamed

Sudo + komut dosyasının adı için bir takma ad oluşturabilirsiniz. Tabii ki, bu daha da fazla iştir, çünkü o zaman bir takma ad ayarlamanız gerekir, ancak sizi Sudo yazmak zorunda kalmaz.

Ancak korkunç güvenlik risklerini önemsemiyorsanız, Shell betiğinin yorumlayıcısı olarak bir setuid Shell kullanın. Bunun sizin için işe yarayıp yaramayacağını bilmiyorum, ama sanırım.

Gerçi bunu yapmamayı tavsiye ettiğimi belirteyim. Ben sadece eğitim amaçlı olarak bahsediyorum ;-)

4
wzzrd

Herhangi bir nedenle Sudo kullanılamıyorsa, C'ye ince bir sarmalayıcı komut dosyası yazabilirsiniz:

#include <unistd.h>
int main() {
    setuid(0);
    execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}

Ve derledikten sonra chmod 4511 wrapper_script İle setuid olarak ayarlayın.

Bu, gönderilen başka bir yanıta benzer, ancak komut dosyasını temiz bir ortamla çalıştırır ve system() tarafından çağrılan Kabuk yerine açıkça /bin/bash Kullanır ve bu nedenle bazı güvenlik açıklarını kapatır.

Bunun çevreyi tamamen attığını unutmayın. Bazı çevresel değişkenleri güvenlik açıklarını açmadan kullanmak istiyorsanız, gerçekten Sudo kullanmanız yeterlidir.

Açıkçası, senaryonun kendisinin sadece kök tarafından yazılabilir olduğundan emin olmak istiyorsun.

2
Chris