x64 mimarisi için return address sahteciliği

x64 mimarisi için return address sahteciliği

Herkese merhaba ✌️
Bloğumun ilk yazısında bahsetmiştim, niche konular için ingilizce yazacağıma söz vermiştim çünkü bu tarz konular yerel kitleden çok fazla kişiye hitap etmeyebilir ve bu yüzden bu tarz derinlemesine yazılım içeren, anlaması zor ve karışık konuları globale hitap edebilmesi ve daha çok kişiye ulaşabilmesi için ingilizce yazmam gerekiyor fakat bu konuda yerel kaynakların çok yetersiz olduğunu fark ettim ve bu yüzden yazıyı türkçe yazmaya karar verdim. Benim açımdan etkileşimi düşük bir yazı olacak ama en azından türkçe kaynak olmuş olur. Birilerinin işine yaraması beni mutlu edecektir. Bu konuyu araştırdığınızda aslında nasıl yapılabileceğine ait bir çok kaynak var fakat karışık bir konu ve bolca yazılım içerdiğinden bu konuyu biraz daha detaylı anlatarak bu spoofing işleminin nasıl yapıldığını anlatmaya çalışacağım. Bir çok terimin türkçe karşılığı olmayabilir bu yüzden ingilizce karışık yazabilirim maalesef bunun için yapabileceğim bir şey yok, türkçe karşılıkları ya çok saçma oluyor yada hiç bir karşılığı bile olmayabiliyor. Bunun için şimdiden üzgünüm zaten bu konuyu okuyan ve ilgi duyan birinin biraz da olsa ingilizce biliyor olduğunu varsaymak zorundayım. Yazılım güvenliği ve mimarisi konusunda son zamanlarda çok ilgiliyim bu yüzden bu konuyu ele almak istedim.
Gelelim konumuza, x86 mimarisi için bu süreç farklı işler fakat x64 bana göre daha zor ve karışık olduğundan bunu anlatmayı uygun buldum. Konuda bunun nasıl yapıldığını anlatacağım ve nasıl yapıldığını anladığınızda çözüm bulmak çok zor olmasa gerek o yüzden çözümünü size bırakıyorum. Bu yazı saldırıyı yapmaktan ziyade nasıl çalıştığını anlamak için temel bilgileri sunar bu yüzden eğitim amaçlıdır. Bu saldırıyı yapabilmek için yine de ciddi bir tersine mühendislik bilgisi gerektirir. Bu yüzden her şeyi bu yazıda vermiyorum en azından kötü niyetli insanların türemesini istemiyorum.

Return address sahteciliği nedir ? Ne işe yarar ?

Öncelikle "x64" terimi, 64 bit işlemcileri ve mimarileri ifade eder. Bu mimaride, her işlemci register'ı, bellek adresi, ve veri yapıları 64 bit genişliğindedir. Programda ki dönüş adreslerinin (return address) sahte olarak değiştirilmesi anlamına gelir. 64 bit sistemlerde, dönüş adresi genellikle bir register veya yığındaki bir bellek adresinde saklanır. Saldırgan, dönüş adresini manipüle ederek programın, tasarlanan adrese değil, kendisinin istediği bir adrese dönmesini sağlayabilir. Bu tür bir saldırı, özellikle ciddi bir güvenlik açığı oluşturur.

Neden önemlidir ?

Basit bir cümle ile açıklamak gerekirse yayınladığınız yazılımınızın art niyetli kişiler tarafından hacklenmesine yol açar. Bu tür saldırılar yapılması karışık ve zor saldırılardır fakat piyasada çok fazla programda bu tarz güvenlik açığı mevcut olup bunun sebeplerinden en büyüğü yazılımcı yetiştireceğiz diyerek çok fazla yazılımcı yetiştirmeye çalışan bir politika benimsenmesidir, bunun sonucunda kalitesiz yazılımcılardan kalitesiz yazılımlar ortaya çıkmaya başlar. 6 aylık kurs alıp ben yazılımcıyım diye şirketlerde çalışan ve yazılım geliştiriyorum diye ortada dolaşan insanları gördükçe olayın ne kadar ciddi olduğunu anlayabilirsiniz 😅 Bu tarz saldırıları önlemek için profesyonel düzeyde yardım yada danışmanlık almanız gerekir hele ki türkiye de bir yazılım projesinin sahibiyseniz... Yine de bu tarz complex saldırılar için net bir çözüm yöntemi yoktur, sadece işi zorlaştırabilirsiniz. Bu tür ciddi tersine mühendislik bilgisi gerektiren saldırılar için kafayı size takmış ve işinde uzman biri için herhangi bir kalıcı çözüm yada önlem yoktur.

Bunu geliştirmek için biraz C++ ve Assemblyden yararlanmamız gerekecek. C++ yı sadece örneği çalıştırmak ve görselde işleyişi gösterebilmek için kullanacam burada asıl işi yapan Assembly kodumuz olacaktır. Tamamlanmış ve örnek içeren halini github üzerinden paylaşacam, linkini konu altında bulabilirsiniz.
Assembly kodumuz

x64spoof_stub.asm

Bu kodun yaptığı şey temelde yığındaki kabuk kodu için geçici bir depolama alanı oluşturmak, gadget adresini ve çağrılan işlev adresini orada depolamak ve kabuk kodu için fazladan 8 bayt ayırmaktır. Bundan sonrası için bu deponun adresi kabuk koduna aktarılır, daha sonra registers okur ve kabuk kodunun dönüş adresini, orijinal dönüş adresini ve nonvolatile register orijinal içeriğini burada saklar. Bundan sonrası için depolamanın adresinin korunmasını sağlamak için bunu register içine koyar ve çağrılan işleve atlar. Fonksiyon çalışır, ardından kullandığımız gadget'a geri döner böylelikle kabuk kodumuzun geri kalanını çalıştırmaya devam eder. Kalan kabuk kodu rcx'i geri yükler, yığını hizalar ve geri döner burada dönüş adresinin değişen adresi nedeniyle bir jmp tarafından uygulanır.
Sırayla genel olarak bu şekilde süreç işler yinede kodun çalışma mantığını kavrayabilmeniz için asm bilmeniz gerekir umarım açıklayıcı ve anlaşılabilir olmuştur.
C++ projemizi de oluşturalım. ASM kodunun düzgün işlenebilmesi için c++ kodunu buna uygun olarak derledik. Burada main.cpp üzerinde zaten mevcut örneği bıraktım. Projenin github linkini de konu altına bıraktım.

x64ret_addr_spoof.hpp

Sınırlamalar: yalnızca x64'te çalışır, yalnızca bir nonvolatile register için çalışır (modülün jmp_rdx ile aynı kabuğu kullanan bir bölümünü bulmaya zorlanır), herhangi bir adreste çalışamaz, signature yoluyla kolayca tespit edilebilir.

main.cpp

rtr-address
Bu konu sadece eğitim amaçlı olduğu için temel düzeyde nasıl çalıştığını anlatmaya çalıştım. Leak olmuş olan kısmından fazlasını zaten vermedim ayrıca nasıl önlem alabileceğinize dairde ufak bir ipucu vermiş oldum. Zaten bu konuda ki haline çok kolay önlem alınabilir yine de bir nevi çözümü de vermiş oldum 😄