|
Welcome,
Guest
|
|
Osman PAMUK, TÜBİTAK BİLGEM
20.11.2011 Kullanıcı erişim bilgileri (Access Token) Windows işletim sistemindeki işlemlerin (process) ve iş parçacıklarının (thread) güvenlik bilgilerinin saklandığı veri yapılarıdır. Bir erişim bilgisi içinde, ilgili olduğu işlem veya iş parçacığının hangi kullanıcı hesabı ve kullanıcı grubu ile bağlantılı olduğu ve hangi ayrıcalıklara sahip olduğu bilgisi bulunur. İşletim sistemi, bir işlem veya iş parçacığının herhangi bir nesneye erişip erişemeyeceğini ve hangi nesnede hangi tür işlemleri yapıp yapamayacağını, erişim bilgisi içindeki o işlem veya iş parçacığının hangi kullanıcı hesabıyla çalıştığı ve bu kullanıcının hangi gruplara üye olduğu bilgisine bakarak karar vermektedir. Mesela herhangi bir dosya veya registry anahtarına ulaşıp okuma veya yazma yapmaya çalıştığınızda sahip olduğunuz erişim bilgisindeki kayıtlar ile nesne üzerindeki bilgiler eşleştirilmekte ve bunun sonucunda istediğiniz yetkiyi alıp alamayacağınıza karar verilmektedir. Bunun yanında erişim bilgisi içindeki ayrıcalıklar listesi ile işletim sistemi, erişim bilgisinde belirtilen kullanıcının işlem veya iş parçacığının hangi özel sistem işlemlerini yapıp yapamacağını da belirler. Bu ayrıcalıkların içinde "Take Ownership" yani herhangi bir nesnenin sahibi olabilme yetkisi ve "Debug programs" yani herhangi bir işlemde hata ayıklama yapabilme yetkisi gibi çok önemli sistem işlemleri bulunmaktadır. [1] Bu yazıda da Windows 7'deki bu kullanıcı erişim bilgilerini tahrif etmek ve sonuçta hak yükseltme veya hesap taklit etme(impersonation) saldırılarına yol açabilecek iki yöntemden bahsedilecektir. Amacımız şu anda pratik uygulamalarında zorluklar olmasına rağmen bu tür potansiyel saldırı alanlarının en yeni işletim sistemlerinde de olduğunu göstermektir. Herşeyden önce şunu belirtmek gerekir ki, bahsedeceğimiz yöntemler işletim sistemi çekirdeğinde değişiklikler içermektedir. Tabiî ki kötü niyetli bir yazılımın da çekirdeğe ulaşabilmesi için önce bir açıklık tespit etmesi ve bunu kullanabilmesi (exploit edebilmesi) gerekmektedir. Daha önce vista ile gelen çekirdek koruma tekniklerinden ve bu korumayı aşmak için kullanılabilecek bir yöntemden bahsedilmişti [2]. Fakat Windows 7'nin en güncel konumunda "memory randomization" özelliği sayesinde bu veya benzeri bir açıklığı halihazırda kullanmak mümkün değildir. Bu yüzden bu yazıda, inceleyeceğimiz yöntemlerden bahsederken, çekirdeğe ulaşmak için güvenli bir yöntem olan kernel debugger attachment (çekirdeğe hata ayıklıyıcı bağlama) yöntemini kullanacağız. Saldırı yöntemlerini incelemeye başlamadan önce erişim bilgilerinin sistemde nasıl tutulduğu ve kulllanıldığına kısa bir göz atalım. Windows 7 64 bit bir işletim sistemindeki erişim bilgilerinin (access token) yapısı aşağıdaki gibidir: 0: kd> dt -v nt!_token struct _TOKEN, 33 elements, 0x310 bytes +0x000 TokenSource : struct _TOKEN_SOURCE, 2 elements, 0x10 bytes +0x010 TokenId : struct _LUID, 2 elements, 0x8 bytes +0x018 AuthenticationId : struct _LUID, 2 elements, 0x8 bytes +0x020 ParentTokenId : struct _LUID, 2 elements, 0x8 bytes +0x028 ExpirationTime : union _LARGE_INTEGER, 4 elements, 0x8 bytes +0x030 TokenLock : Ptr64 to struct _ERESOURCE, 15 elements, 0x68 bytes +0x038 ModifiedId : struct _LUID, 2 elements, 0x8 bytes +0x040 Privileges : struct _SEP_TOKEN_PRIVILEGES, 3 elements, 0x18 bytes ... İşletim sisteminin çekirdeğinde çalıştırılan iş parçacıklarının ve işlemlerin bilgileri "EPROCESS" ve "ETHREAD" yapılarıyla tanımlanan çekirdek nesnelerinde tutulmaktadır. Bu nesneler aynı zamanda işlem veya iş parçacığının sahip olduğu erişim bilgilerinin adres bilgisini de tutmaktadır. "EPROCESS" yapısı ve "Token" pointer: 0: kd> dt -v nt!_eprocess struct _EPROCESS, 135 elements, 0x4d0 bytes +0x000 Pcb : struct _KPROCESS, 37 elements, 0x160 bytes … +0x200 ObjectTable : Ptr64 to struct _HANDLE_TABLE, 15 elements, 0x68 bytes +0x208 Token : struct _EX_FAST_REF, 3 elements, 0x8 bytes +0x210 WorkingSetPage : Uint8B … Yukarıda gösterildiği gibi bir işlem nesnesinin 0x208'inci baytında işlemin erişim bilgisi nesnesinin adresini içeren _EX_FAST_REF yapısı bulunmaktadır. Bu yapıya biraz daha ayrıntılı bir şekilde göz atarsak: 1: kd>dt -b -v nt!_EX_FAST_REF struct _EX_FAST_REF, 3 elements, 0x8 bytes +0x000 Object : Ptr64 to +0x000 RefCnt : BitfieldPos 0, 4 Bits +0x000 Value : Uint8B _EX_FAST_REF yapısı haddizatında sadece 8 baytlık bir işaretleyicidir (pointer). Fakat bu işaretleyicininf son 4 biti bu nesneye yapılan referansların sayısını tutmak için ayrılmıştır. Bu nedenle _EX_FAST_REF yapısından gerçek adresi bulmak için son 4 bit sıfırlanmalıdır. Ayrıcalık Yükseltme Bir kullanıcının sahip olduğu ayırcalıkların neler olduğunu erişim bilgisi nesnesinin baştan 0x40'ıncı baytında ki SEP_TOKEN_PRIVILEGES yapısında bulunmaktadır. 0: kd> dt -s -b _SEP_TOKEN_PRIVILEGES nt!_SEP_TOKEN_PRIVILEGES +0x000 Present : Uint8B +0x008 Enabled : Uint8B +0x010 EnabledByDefault : Uint8B Yukarıda da görüldüğü gibi SEP_TOKEN_PRIVILEGES yapısı 8 baytlık üç alandan oluşmaktadır. İlk alan "Present" kullanıcı işlem veya iş parçacığının sahip olabileceği bütün ayrıcalıkların bilgisini, ikinci alan "Enabled" halihazırda etkinlendirilmiş ayrıcalıkların bilgisini, üçüncü alan "EnabledByDefault" ise kullanıcı işlem veya iş parçacığının ilk oluşturulduğu anda sahip olacağı ayrıcalıkların bilgisini tutmaktadır. Kullanıcı işlem veya iş parçacığı ilk oluşturulduğunda bütün kullanabileceği ayrıcalıklar aktif hale getirilmemektedir. Bu ayrıcalıklar zamanla ihtiyaç duyulduğunda eğer "Present" alanında, ilgili ayrıcalığa sahip olabilir bilgisi mevcutsa aktif hale getirilmektedir. Bu alanlarda her ayrıcalık bir bitle temsil edilmektedir. Sonuç olarak herhangi bir ayrıcalığa sahip olmasını istediğiniz bir işlemin ve iş parçacığının o ayrıcalıkla ilgili erişim bilgisindeki bitlerini 1 olarak değiştirmeniz gerekli hakları vermek için yeterlidir. Mesela normal kullanıcı haklarıyla çalıştırdığımız "cmd.exe" programının sahip olduğu hakları değiştirmek istiyoruz. Bunun için ilk önce "cmd.exe" programımızın erişim bilgisi nesnesindeki SEP_TOKEN_PRIVILEGES yapısına ulaşmamız gerekecektir. Programımızın işlem nesnesinin adresini bulmak için debuggerımızdaki "!process" komutunu kullanabiliriz: 1: kd> !process 0 0 cmd.exe PROCESS fffffa80010c1060 SessionId: 1 Cid: 0b90 Peb: 7fffffdf000 ParentCid: 082c DirBase: 2adb8000 ObjectTable: fffff8a002a87f90 HandleCount: 19. Image: cmd.exe Programımızı çalıştıran işlemin "0xfffffa80010c1060" adresinde olduğunu öğrendik. Bu adreste "EPROCESS" yapısındaki nesnemiz bulunmakta ve işlem ile ilgili bilgiler bu nesnede tutulmaktadır. Bu işlem nesnesindeki erişim bilgisi nesnesinin adresini tutan _EX_FAST_REF yapısına gözatalım: 1: kd>dt -b -v nt!_EX_FAST_REF fffffa80010c1060+0x208 struct _EX_FAST_REF, 3 elements, 0x8 bytes +0x000 Object : 0xfffff8a0`0300f6c5 +0x000 RefCnt : Bitfield 0y0101 +0x000 Value : 0xfffff8a0`0300f6c5 _EX_FAST_REF yapısındaki değer "0xfffff8a0`0300f6c5" olduğuna göre erişim bilgisi nesnesinin adres değeri "0xfffff8a0`0300f6c0" olmalı. Bu adresteki erişim bilgisi nesnesinin ayrıcalık değerlerini inceleyelim: 1: kd>dt -v -b nt!_SEP_TOKEN_PRIVILEGES0xfffff8a0`0300f6c0+0x040 struct _SEP_TOKEN_PRIVILEGES, 3 elements, 0x18 bytes +0x000 Present : 0x6`02880000 +0x008 Enabled : 0x800000 +0x010 EnabledByDefault : 0x800000 Bu ayrıcalıkların karşılıklarını "ProcessExplorer" [3] programıyla daha net bir şekilde görebiliriz: 01.jpg Şekil - 1 Erişim bilgisi tahrif edilmemiş "cmd.exe" işleminin ayrıcalıkları Peki bütün ayrıcalıklara sahip olmak istiyorsak? Yapmamız gereken şey sadece _SEP_TOKEN_PRIVILEGES yapısındaki "Present", "Enabled" ve "EnabledByDefault" alanlarını değiştirmek: eq 0xfffff8a0`0300f6c0+0x040 0xffffffffffffffff eq 0xfffff8a0`0300f6c0+0x048 0xffffffffffffffff eq 0xfffff8a0`0300f6c0+0x050 0xffffffffffffffff Son durum: 0: kd>dt -v -b nt!_SEP_TOKEN_PRIVILEGES0xfffff8a0`0300f6c0+0x040 struct _SEP_TOKEN_PRIVILEGES, 3 elements, 0x18 bytes +0x000 Present : 0xffffffff`ffffffff +0x008 Enabled : 0xffffffff`ffffffff +0x010 EnabledByDefault :0xffffffff`ffffffff 02.jpg Şekil - 2 Erişim bilgisi tahrif edilmiş "cmd.exe" işleminin ayrıcalıkları Süper ayrıcalıklı uygulamanız emirlerinize hazır. Farklı bir Kullanıcının Erişim Bilgisini Çalma Erişim bilgisi nesneleri yanlızca bir işlem nesnesine bağlı olmak zorunda değildir. Bundan dolayı herhangi bir işlem nesnesinin _EX_FAST_REF değerini değiştirerek başka bir erişim bilgisi nesnesine yönlendirebiliriz. Bunun sonucunda normal bir kullanıcının kullanabileceği bir açıklığı kullanabilirseniz, yapmak istediğiniz işleri yapabilme hakkı olan bir kullanıcı hesabı şeçip, bu kullanıcı hesabıyla çalıştırılmış bir işlemin erişim bilgisi nesnesini paylaşabilirsiniz. Mesela her Windows işletim sisteminde olan "System" işleminin hesabını kullanarak yerel yönetici hesabından daha fazla hakka sahip de olabilirsiniz. Herhangi bir açıklığı kullanma ihtimalinin olmadığı bir durumda bu tür kernel nesneleri üzerinde herhangi bir değişiklik yapabilmek için yönetici haklarına sahip olmanız gerekecektir. Bu tür bir durumda bile farklı bir kullanıcı hesabıyla çalışıyormuş gibi sistemi yanıltmak sistem tarafından tutulan kayıtları atlatmanızı sağlayacaktır. Fakat diğer taraftan bu tekniğin kendine has bazı sorunları da bulunmaktadır. Her nesne üzerinde onu kullanan ve referans veren işlemlerin sayısını tutan sayaçlar bulunmaktadır. Bir nesneyi kullanan veya referans veren bir işlem kalmadığı takdirde nesne yöneticisi ilgili nesneyi hafızadan silmektedir. Bundan dolayı eğer bir erişim bilgisi nesnesini başka bir işleme bağlarsak ilgili erişim bilgisi nesnesinin sayaçlarının arttırılması gerekmektedir. Aksi takdirde erişim bilgisi nesnesinin gerçek sahibi olan işlem veya sonradan nesneyi kullanmaya başlayan işlemden herhangi biri kapatıldığında diğer işlemde devre dışı kalacaktır. Bu tür sorunlarla uğraşmamak için, herhangi bir işlemle aynı erişim bilgisi nesnesini kullanmaktansa, taklit edilmek istenen erişim bilgisi nesnesinin "ZwDuplicateToken" fonksiyonuyla yeni bir kopyasını oluşturabiliriz. Bir sonraki aşamada da bu yeni oluşturulan nesnenin adresini istediğimiz bir işlemin _EX_FAST_REF değerine yazabiliriz [4]. Mesela yine normal kullanıcı haklarıyla çalıştırdığımız cmd.exe işlemimizi ele alalım. İlk çalıştırıldığında işlemimiz aşağıda gördüğünüz "User" ve "SID" haklarıyla çalışmaktadır. 03.jpg Şekil - 3 Erişim bilgisi tahrif edilmemiş "cmd.exe" işleminin kullanıcı bilgileri Amacımız PID'si 4 olan "System" işleminin erişim bilgisi nesnesinin bir kopyasını oluşturmak ve bu kopyayı yukarıdaki işlemimize bağlamak. Bunun için ilk önce kernel (çekirdek) hafızasında değişiklik yetkisi olan bir kernel sürücüsü oluşturmalıyız. Halihazırda elimizde bir açıklık ve exploit olmadığını varsayarsak oluşturacağınız kernel sürücüsünü yüklemek için yerel yönetici haklarına sahip olmanız ve işletim sistemine bir çekirdek hata ayıklaycı bağlamanız gerekecektir. Sonuçta kernel sürücünüzü yükleyip çalıştırdığımızda aşağıdaki sonucu elde edeceğiz. 04.jpg Şekil - 4 Erişim bilgisi tahrif edilmiş "cmd.exe" işleminin kullanıcı bilgileri Yukarıda da görüldüğü gibi yeni "User" ımız artık yerel sistem kullanıcısı. Bundan sonra "cmd.exe" işlemimizle yaptığımız her işlem bu kullanıcı haklarıyla çalıştırılacak ve kayıtlarda da sadece "System" kullanıcısının ismi gözükecektir. |
|
|
Please Log in or Create an account to join the conversation. |
