|  | 
        
            | 
                    
                        | .NET ve Uygulama Güvenliği - 2 |  |  
                        | 
	
    
		
            | Gönderiliyor lütfen bekleyin... | 
 |  | 
        
            | Daha önceki makalemizde (.NET ve Uygulama Güvenliği 1) 
        dağıtım aşamasından sonra uygulamamız üzerinde istemediğimiz şekilde değilik yapılmaya müsait olabildiğini inceledik.
        Bu makalemizde iste bu tür sorunlara karşı neler yapılabileceğini Microsoftun araçları ile ya da 3. parti araçlar ile 
        ne gibi önlemler alabileceğimizi inceleyeceğiz. Kısaca önceki senaryolardan bahsedecek olursak, uygulamanın dağıtımından sonraki 
        safhada, uygulamamız ya da uygulamanın kullandığı Dlller Reflector ile açılıp 
        kodlar görüntülendikten sonra (Type bilgileri ve isimleri çözüldükten sonra) 
        benzer bilgiler ve isimlerden yola çıkılarak orjinallerinden farklı Dll'ler 
        oluşturulup, orjinalleri ile değiştirilerek farklı ya da zararlı kodların 
        çalıştırılabilmesi sağlanmaktadır. Diğer bir senaryomuzda ise, yeniden 
        yazılamayacak kadar karmaşık veya yazılmasına gerek kalmadan sadece belirli bir 
        metodun veya kod bloğunun değişmesi sonucunda uygulama amacından farklı çalışması sağlanarak istenmeyen durumlara 
        neden olabildiğini ve bunun da uygulama ya da uygulamanın kullandığı Dlllere kod gömerek (code injection)nasıl
        gerçekleştirilebileceğini incelemiştik. 
 Dijital Imzalama
 
 Daha önce az çok .NET üzerinde uygulama geliştirenler tekil isim (strong name) 
        kavramı ile karşılaşmışlardır. Geliştirilen assembly'lerin güveliğini sağlamak, 
        tekilliğini belirtmek, versiyonlamak, Com+ kullanmak  veya geliştirilen 
        assembly'nin GAC'a yüklenmesi gerektiğinde assembly'lerimizin tekil isme sahip 
        olmaları gerekmektedir. Tekil isim "BTA.CoreDevelopment.Client.dll" şeklinde 
        assembly adı değil , "assembly adı + versiyon numarası + culture bilgisi ve 
        public key token" bilgilerinin birleşimi sonucunda oluşur. Aslında çok kısa bir özetle tekil isim "bir assembly'nin 
        tekilliğini sağlamak" amacı ile kullanılır. Bu tekilliği sağlamak için de tabiki 
        sadece bize ait olan bazı bilgilerin olması gerekmektedir. Sadece bize özel olan 
        bu bilgileri kullanarak assembly'yi işaretlenerek tekillik sağlanabilmektedir. 
        Bunun için de günümüzde yoğun olarak kullanılan dijital imzalama (digital 
        signature) yöntemini  tekilliği sağlamakta kullanabiliriz. Assembly'lerin 
        tekilliğini nasıl sağlandığını anlayabilmemiz için öncelikle şifreleme tekniğini 
        biraz inceleyelim.
 
 Temel prensip olarak hashing ve public/private anahtarlar kullanılarak yapılan 
        imzalar birlikte kullanılarak belirli bir veri için tekillik oluşturulabilir. 
        Hashing'in mantığında belirli bir veri üzerinden kullanılan algoritmaya göre 
        özel bir değer üretme söz konusudur.
 
  
 Yukardaki şekilden de anlaşılacağı üzere hashing işlemine tabi tutulacak veri korumak istediğimiz assembly
            olduğunu düşünürsek, assembly üzerinden bir hash algoritması(MD5, SHA1 vsvs) ile bir değer elde edebiliriz.
            Eğer assembly içerisinde bir değişiklik olursa üretilecek olan Hash değeri de farklılaşacaktır. Hashing 
            genelde şifreleme ile karıştırılan bir konudur.Hashing bir sıkıştırma ya da şifreleme yöntemi değildir. 
            Sıkıştırma ya da şifrelemede orjinal veriyi tekrar elde etmek mümkün iken Hash değerinden yola çıkarak orjinal
            veri elde edilemez.
            
            Peki bu durumda hash değeri bizim için ne anlam ifade etmektedir ? Aynı 
    hashing algoritması kullanılarak farklı iki assembly den elde edilen hashing 
    değerlerine bakıldığında aynı sonucu elde etmiş isek bu iki assembly aynıdır 
    diyebiliriz ki bu durumda hash değerleri karşılaştırma amacı ile ile kullanılır 
    sonucunu çıkarabiliriz. Gerçekte de derleyici kod derlendikten sonra oluşan 
    assembly'nin içerisine bu elde ettiği hash değerin yazmaktadır.
 
 
  
 Yukardaki resimde de görüldüğü gibi CFF Explorer (bir önceki makalede bu 
    araçtan bahsetmiştik) ile bir assembly incelendiğinde SHA1 algoritmasi 
    kullanılarak oluşturulan hash değerini görmüş oluyoruz. (MD5 algoritmasi 
    kullanılarak da hash değerinin yazıldığını görüyoruz ki şu anda detay yapılacak 
    konu değildir. CLI dökümanları incelendiğinde bu alanın ileriye yönelik kullanım 
    amaçlı konulduğunu bilgisine erişilebilir) Bu açıklamalardan sonra akla gelecek 
    ilk soru " bu alanı harici müdahaleler ile değiştiremez miyim ?" olacaktır. 
    Cevap ise vahim : "evet değiştirilebilir". Bu durumda assembly'nin hash değeri 
    ile üzerinde değişiklik yapılarak elde edilen  sahte assmebly'nin hash 
    değerleri değiştirilebilir ve bu nedenle de tekillik güvenliğini sağlamamış 
    oluruz.
 Bu soruna çözüm olarak elde ettiğimiz bu hash değerini şifreleyerek assembly 
    içerisine yazdığımızda dışardan müdahale etmek istendiğinde şifrelenmiş hash 
    değeri ile karşılaşılacak ve bu hash değerinin gerçek değeri bilinmediğinden 
    ilerleme kaydedilemeyecektir. Bu durumda assembly içerisine şifrelenerek 
    yazılmış hash değerinin orjinal değerine erişmek için gerekli anahtarı da 
    koymamız gerekmektedir. Aksi durumda karşılaştırma yapılmak istenildiğinde gerçek 
    hash değerine ulaşılamayacağı için biz de sorun yaşıyor olacağız. İşte bu 
    aşamalarda  public/private anahtar yöntemini kullanarak assembly içerisine 
    hem şifrelenmiş hash değerini hem de şifreyi çözecek public anahtarı koyarak sorunumuzu 
    halletmiş olacağız.Bu yöntemi kullanmadan önce public/private anahtarlar 
    kullanılarak nasıl şifreleme yapılabildiğini kısaca inceleyelim.
 
 
  Yukardaki resimde de açıkça görüldüğü gibi eğer bir veri public anahtar ile 
    şifrelenmiş ise bunu ancak private anahtar ile, eğer veri private anahtar ile 
    şifrelenir ise bunu anca public anahtar ile çözebiliriz (Konu hakkında detaylı 
    bilgiler için Asimetrik Şifreleme konularına bakınız).
    Yani şifrelenmiş verinin orjinal halini görebilmek için ya private (public 
    anahtar ile şifrelenmiş işe) ya da public ( private anahtar ile şifrelenmiş ise) 
    anahtara sahip olunması gerekmektedir.
 
 Hashleme ve asimetrik şifreleme yöntemleri kullanılarak oluşturulan 
    assembly'lere tekil isim (strong name) verebilmekteyiz. Aşağıdaki resimde basit 
    bir şekilde bu işlemin nasıl yapıldığı gösterilmektedir.
 
 
   Yukardaki şekli kısaca özetlemek gerekirse, derleme sırasında oluşturulan assemblyden öncelikle SHA1 hash algoritmasi ile bir değer üretirlir.
        Bu değer assembly içerisine daha önce açıkladığımız gibi değiştirilme ihtimali göz önüne alınırak doğrudan yazılmaz. 
    Oluşturulan private anahtar ile bu assembly'ye özel hash değeri şifrelenir ve  
    geri çözülebilmesi için public anahtar ile birlikte assembly içerisine 
    kaydedilir.
 
  Çalışma zamanında 
    imzalı assembly'yi yükleyen birim assembly'den bir hash değeri üretir. Daha 
    sonra assembly içerisindeki şifrelenmiş hash değerini public anahtar kullanarak 
    gerçek hash değerini elde eder. Bu iki hash değerini karşılaştırdığında eğer 
    aynı değerleri elde ediyor ise assembly doğrulanmış olur.
 
 Şimdi bir tekil isme sahip assembly oluşturup bu assembly'yi önceki 
    makalemizdeki gibi değiştirmeye çalışalım. Öncelikle yukardaki anlatılanlar 
    doğrultusunda public/private anahtar ikilisine ihtiyaç vardır. Bu amaç için 
    Sn.exe isimli aracı Visual Studio 2008 komut satırından aşağıdaki parametrelerle 
    kullandığımzda bize public/private anahtar ikilisini üretecektir.
 
 sn -k bta.snk (sn.exe -k dosyaismi)
 
 Eğer üretiken bu anahtar ikilisinden sadece public anahtar dosyasını elde etmek 
    istenildiğinde sn.exe aşağıdaki gibi kullanılabilir.
 
 sn -p bta.snk btapublic.snk
 
 Bir assembly'nin public anahtarı  ile ilgili bilgi almak için ise
 
 sn -Tp bta.dll
 
 şeklinde kullanılması yeterli olacaktır. Oluşturulan snk dosyası projeye eklenir 
    ve projenin AssemblyInfo.cs dosyası içerisine aşağıdaki kod satırı eklenerek 
    derleme işlemi sırasında tekil isim oluşturulması sağlanmış olur.
 
 [assembly: AssemblyKeyFile("bta.snk")]
 
 Visual Studio 2008 ile bilirlikte assembly'lerin kolay bir şekilde imzalanmasi 
    için ek özellik getirildi. Projeye sağ tıkladıkdan sonra açılan menüden 
    Properties menüsüne tıkladığımızda açılan ekranda Signing sekmesine 
    tıkladığımızda Signing bölümünü göreceğiz. Eğer daha önceden bir dosya varsa bu 
    kısımdan seçebilir ya da ilk defa oluşturulmak istenirse yine bu kısımdan yeni 
    public/private anahtar dosyamızı oluşturabiliriz.
 
 
  
 Anahtarı oluşturdukdan sonra Solution Explorer penceresiden uygulama dosyaları 
    incelendiğinde *.pfx uzantılı bir dosyanın projeye eklendiğini görebiliriz.Artık 
    bu assembly derlendiğinde şimdiye kadar bahsettiğimiz tekil isme sahip 
    olacaktır. Oluşan assembly IL Disassembler ile açılıp manifest kısmına 
    bakıldığında tekil isme sahip olmayan assembly'lerden farklı olarak artık public 
    anahtarı içerdiğini görebilmekteyiz.
 
 
  
 Şimdi önceki makalemizde geçen senaryoları tekil isim verilmiş bir assembly 
    üzerinde gerçeklemeye çalışalım. Birinci senaryo da geçek assembly'nin Reflector 
    ile açılarak kod yapısının tespit edilmesi ve benzer bir assembly geliştirilerek 
    gerçeği ile değiştirilmesi sonucunda uygulamamızın istenemeyen kodları 
    çalıştırması idi.Önceki makalemizdeki clHavale.dll uygulamasını bu defa 
    yukardaki açıklamalar doğrultusunda *.pfx  dosyasını oluşturup tekil isim 
    vererek derleyelim.
 
 
  Bu adımdan sonra waHavale isimli pencere uygulamamıza bu tekil isim verilmiş 
    dll'i referans ederek derleyelim. Daha sonra sahte dll ile bu tekil isime sahip 
    dll'i değitirelim. Hatırlayacağınız üzere eğer bizim geliştirdiğimiz dll tekil 
    isme sahip değildi ve uygulama bu harici müdahale sonucunda sorunsuz olarak 
    çalışmıştı. Geliştirme aşamasında dll'i tekil isme sahip şekilde 
    hazırladığımızda ise bu müdahale sonucu başarısız olacaktır.
 
 
   
 Görüldüğü gibi tekil isme sahip bir dlli kullanarak derlenen ana uygulamamız çalışma zamanında ilgili 
        tekil isme sahip dll içerisindeki kodları kullanmak istediğinde ilgili dlli yükleme çalışırken tekil isimli 
        dll olup olmadığını kontrol etmekte, eğer bu tekil isimli dlli bulamazsa da çalışma zamanında hata üretmektedir.
         Bu örnekteki tekil isim "clHavale, Version=1.0.0 ,Culture=neutral, 
    PublicKeyToken=b0c1e38505bbbe10" dur. Daha öncede bahsettiğimiz gibi tekil 
    isim için gerekli verilen isim içerisinde yer almıştır. PublicKeyToken 
    assembly içerisine gömülen public anahtarımızdan üretilen hash değerinden 
    ibarettir. Önceki makaledeki bilgilerden yola çıkarak , tekil isimli dll 
    uygulamaya (exe) refere edildiğinde uygulama içerisinde bir yerlerde bu bilgi 
    kaydedilmekte ve çalışma zamanında bu bilgi kontrol edilmektedir. (Bir önceki 
    makalemizde açıkladığımız AssemblyRef kısmı olabilir mi ?) . Makalenin ilerleyen 
    bölümünde bu kısmı detaylandıracağız.
 
 Diğer senaryomuzda ise Reflector ve Reflexil araçları ile bir assembly'nin 
    kodlarının değiştirilmesi işleminden sonra değişikliğin yine aynı assembly 
    üzerine yazılması sonucunda uygulama istenemeyen kodlar ya da kodların silinip 
    kaydedilmesinden sonra çalışması gereken kodların çalışmaması söz konusu 
    idi.Aynı adımları tekil isme sahip clHavale.dll üzerinde yapmaya çalıştığımızda 
    Reflexil bize aşağıdaki seçeneklerden hangisini uygulayacağını sormaktadır.
 
 
  
 Görüldüğü gibi aslında kodları değiştirilmiş assembly doğrudan kaydedilememekte 
    alternatif seçenekler sunmaktadır.
    Bu seçeneklere kısaca değinirsek;
 Register it for verification skipping  tercih edildiğinde Reflexil kodları değişmiş assemblyyi
    oluşturur ve ana uygulamamızın bu assembly'yi çalışma zamanındaki onaylama 
    işlemine tabi tutmadan çalıştırabilmesi için kayıt defterine (registry) 
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification  altında
    clHavale,B0C1E38505BBBE10 isimli (dikkat edeceğiniz gibi assembly adı ve 
    assembly'nin PublicKeyToken bilgisi) bir anahtar oluşturmuştur.
 Artık ana uygulama tekil isme sahip bu dll için çalışma zamanında yukarda 
    bahsedilen hash değerlerinin aynı olması üzerine kurulu kontrol işlemini 
    yapmayacaktır. Ve bu durumda da uygulama yine sorunsuz bir şekilde çalışmaya devam edecektir.
    (Ama kayıt defterine erişim hakkı bulunmayan kullanıcılar için bu seçenek işe 
    yaramayacağından istenilen sonucu elde edememiş oluyoruz. )
 
 Re-sign with key seçeneğinde ise Reflexil private anahtarı isteyerek 
    değişmiş olan bu assembly için tekrar bir tekil isim oluşturma işlemi 
    yapabileceğini söylemektedir. Oysaki geliştirici dışında kimsede private anahtar 
    olmadığı için bu mümkün olmamaktadır. Eğer private anahtar bizde olsa idi 
    Reflexil değişen asssembly için hash değeri üretecek bunu da private anahtar ile 
    şifreledikten sonra assembly içerisine kaydedecek böylelikle ana uygulama 
    rahatlıkla bu assembly'yi runtime da yükleyerek çalıştıracaktır.Yine eğer 
    private anahtar bizde olsa idi dll'i yeniden yazdıkdan sonra kendimiz 
    imzalayabilirdik.Bu nedenle private anahtarın gizliliği oldukça önemlidir.
 
 Remove strong name seçeneği ise oldukça cüretkar imkanlar sunmaktadır. 
    Kısaca assembly'nin imzasını assembly içinden silecek ve açılan pencerede ise bu 
    assembly'ye referansda bulunan ana uygulamayı (tercihe göre) isteyerek ana 
    uygulama içerisindeki tekil isme ait bilgileri yok edecektir. Bu aşamadan sonra 
    ana uygulama bir önceki makalemizde detaylı bahsettiğimiz assembly bilgilerinden 
    yola çıkarak değiştirilmiş assembly'yi çalıştırabilecektir. Aslında bu çok da 
    karmaşık bir işlem değildir. Yani tekil isimli assembly'yi refere eden 
    uyugulamayı CFF Explorer ile açıp metadata bilgilerinden AssemblyRef 
    tablosundaki clHavale.dll 'in bilgilerine baktığımızda PublicKeyOrToken 
    bilgisinin var olduğunu görürüz. İşte bu kısmı düzenleyerek 0 değerini verdikten 
    sonra ana uygulama kaydedildiğinde sahte dll ile gerçek dll yer değiştirir. Bu 
    adımdan sonra da ana uygulama tekil isme sahip olup olmadığına bakmadan ilgili 
    dll'i yükleyebildiğini ve çalıştırdığını göreceğiz.
 
 
  
 Bir başka senaryo da şu olabilir. Ana uygulama tekil isme sahip bir dll 
    beklemektedir. Biz de tekil isme sahip dll'i açıp içerisine kod gömüp ya da 
    sildikten sonra ana uygulama tarfından çalıştırılmasını istediğimizde ilk adım 
    olarak yukardaki gibi ana uygulama içerisinde clHavale.dll ine ait 
    PublicKeyOrToken bilgisini 0 yaparak ana uygulamayı kaydettik. Bu durumda hala 
    gerçek dll'imiz tekil isme sahip olduğu için ana uygulama da tekil isme sahip 
    olmayan bir dll aradığı için gerçek clHavale.dll çalıştırılamayacaktır. Bu 
    durumda gerçek clHavale.dll den imza bilgisini silmemiz gerekmekte ve bunun için 
    de yine CFF Explorer'dan faydalanarak aşağıdaki görüldüğü gibi PublicKey bilgisi 
    0 yapılarak tekil ismin yok edilmesi sağlanabilmektedir. Biraz araştırma 
    yapıldığında tekil ismi silen birkaç uygulama olduğunu görebiliriz.
 
 
  
 Cancel with Delay Signed seçeneği ise şu aşamada detaylandırma ihtiyacı 
    duymadığımız bir konu. Kısaca delay signed geliştirilen dll'in içerisinde sadece 
    public anahtarın bırakılarak private anahtar olmadan da kodu yazmak ve 
    assembly'yi geliştirmek için gerekli imkanların sağlanmasına yaramaktadır. 
    Assembly geliiştirildikten sonra dağıtım aşamasında private anahtar kullanılarak 
    assembly imzalanır ve dağıtıma hazır duruma getirilir. Delay Singing  
    hakkında detaylı bilgi için
    
    http://msdn.microsoft.com/en-us/library/t07a3dye.aspx adresinden 
    faydalanabilirisiniz.
 
 Şu ana kadar bir assembly'nin imzalanması sonucunda eskisi kadar rahat bir 
    şekilde harici müdahale edilemediğini ama hala bazı müdahaleler sonucunda yine 
    istenmeyen durumların gerçekleşebiliceğini görmüş olduk. Aslında şu ana kadar 
    bahsettiğimiz tüm konulardan çıkan tekil isim assembly'nin tekilliğini 
    sağlayabilmekte ama uygulamanın güvenirliğini görüldüğü üzere  
    sağlayamamaktadır.
 
 Makalede kullanılan örneği idirmek için tıklayınız.
 
 Oğuz YAĞMUR
 MVP
 [email protected]
 
 
 
                Makale:.NET ve Uygulama Güvenliği - 2 C#, Visual C# ve .NET Oğuz Yağmur
 | 
        
            |  | 
        
            |  | 
        
            | 
                    
                        
                            
                        
                            Eklenen Son 10 
                            Bu Konuda Geçmiş 10 
                        
                            Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
                         
                            Son Eklenen 10 Makale Yükleniyor
                         
                            Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
                         | 
        
            |  |