Linux Kernel CVE-2017-11176 Güvenlik Açığı Analizi ve Yeniden Üretimi

1. Güvenlik açığı geçmişi

Linux çekirdeğindeki POSIX mesaj kuyruğunun uygulanmasında bir UAF güvenlik açığı CVE-2017-11176 vardır. Saldırganlar bu güvenlik açığını hizmet reddine neden olmak veya rastgele kod yürütmek için kullanabilir. Bu makale güvenlik açığını, güvenlik açığının nedeni, yama analizi ve yineleme gibi birden çok perspektiften ayrıntılı olarak analiz edecektir.

2. Güvenlik açığı analizi

Posix mesaj kuyruğu asenkron olay bildirimine izin verir.Bir mesaj boş bir kuyruğa yerleştirildiğinde, Posix mesaj kuyruğu bir sinyalin üretilmesine veya bir iş parçacığının başlatılmasına izin verir. Bu eşzamansız olay bildirimi, mq_notify işlevi çağırılarak uygulanır ve mq_notify, belirtilen kuyruk için eşzamansız bir bildirim oluşturur veya siler. Mq_notify işlevi yeniden deneme sürecine girerken çorap işaretçisini NULL olarak ayarlamadığından, UAF zafiyetine neden olabilir.

Yama kodundan, çorabı NULL olarak ayarlayabilirsiniz.

Ardından, güvenlik açığının nedenine bakalım, işte örnek olarak 4.1.0 sürümünün kaynak kodu.

Mq_notify işlevinde, u_notification kullanıcı katmanından geçirilir. Satır 1193, u_notification'ın boş olup olmadığını belirler. Boş değilse, u_notification'daki veriler copy_from_user aracılığıyla bildirime kopyalanır, burada veriler kullanıcı katmanından çekirdek katmanına kopyalanır. Kopyalama başarısız olursa, doğrudan çıkın.

Daha sonra nc ve sock sırasıyla boş bırakılır. 1203. satırda, u_notification boş değilse, ilk olarak, sırayla, notification.sigev_notify'ın SIGEV_NONE veya SIGEV_SIGNAL veya SIGEV_THREAD olması gerektiğine karar verilir. Notification.sigev_notify SIGEV_SIGNAL ise, sinyalin yasal olup olmadığına karar verin.

Satır 1212, notification.sigev_notify SIGEV_THREAD ise, anahtar kodu bloğunu girin. Satır 1216'da, verileri almak için ayırma_skb'si aracılığıyla bir notify_skb oluşturulur. Satır 1221, notification.sigev_value.sival_ptr ile gösterilen veriyi copy_from_user aracılığıyla nc- ye kopyalayın > veri. Burada başarılı olmalıdır, aksi takdirde direk olarak çıkacaktır; satır 1229, mesaj veri başlığını ayarlamak için skb_put'u çağırın. 1231'den 1248'e kadar olan hat, yeniden deneme döngüsü gövdesidir. Satır 1232, dosya tanımlayıcısını almak için fdget işlevini çağırın. Satır 1237, dosya tanıtıcısı aracılığıyla netlink_sock elde etmek için netlink_getsockbyfilp işlevini çağırın, özellikle netlink_getsockbyfilp işlevine bakın.

Filp aracılığıyla ilgili inode düğümünü bulmak için file_inode'u çağırın ve ardından SOCK_I işlevi aracılığıyla inode düğümünü işleyin.

Burada, soket üyesi, container_of makrosu aracılığıyla socket_alloc yapısında bulunur. Burada açıklamak gerekirse, SOCKET_I'nin dönüş değeri bir soket yapısıdır. Aslında çorap yapısındaki ilk üye sock_common da mini soket olan soket tipidir.

Sock_common yapısına bir göz atalım.

1609. satır, çorabı aldıktan sonra, çorabı yargıla ... > Sk_family eşittir AF_NETLINK. 1613 numaralı hattı, ardından referans sayısını artırmak için sock_hold'u çağırın. Sock_hold işlevi aşağıdaki gibidir:

Burada atomic_inc, sk_refcnt'e 1 ekler. Netlink_getsockbyfilp işlevi sock döndürür ve sock'un referans sayısı 1'dir. Sonra, 1246 satırında netlink_attachskb çağrılır. Bu, skb'yi netlink soketine bağlayan bir anahtar işlevdir. Spesifik anahtar kodu aşağıdaki gibidir:

Satır 1683, referans sayısını bir kez azaltmak için sock_put'u çağırın ve son olarak 1 döndürür, işlev geri döner, doğrudan yeniden deneme etiketine gidin.

Burada satır 1237 ve satır 1246, bu iki çağrı referans sayımıyla dengelenir. 1247 satırındaki if ifadesi sock'u boş bırakmaz, 1233 satırına bakın. F.file boşsa, doğrudan out etiketine gidin. Çıkış etiketi kodu aşağıdaki gibidir:

Satır 1306, çorabın boş olup olmadığına karar verin, boş değilse netlink_detachskb işlevini çağırın.

Skb'yi serbest bırakın ve serbest bırakmak için sk referans sayısını azaltın. Sonra bir sorun var: netlink_attachskb'nin 1 dönmesini sağlamak için A evresini yaratırsak ve yeniden deneme mantığını tekrar edersek, bu sefer sock'un referans sayısı dengelenir, bir artı bir eksi, ancak çorap boş değildir. Aynı zamanda, netlink soketine karşılık gelen dosya tanımlayıcısını kapatmak için bir B dizisi oluşturun. B iş parçacığı, netlink soketinin dosya tanımlayıcısını kapattığı için, yeniden deneme mantığındaki A evresi, satır 1232, fdget çağrılırken başarısız olur ve ardından onu serbest bırakmak için doğrudan çıkış etiketine gider ve ikinci kez serbest bırakarak bir güvenlik açığına neden olur. Bu boşluk, koşullu rekabet türünde ikincil bir serbest bırakma boşlukudur. Yalnızca bir ileti dizisinde tetiklenemez.

Bu güvenlik açığının ilkesi nispeten basittir, ancak bu güvenlik açığının nasıl tetikleneceği hala daha karmaşıktır. Öncelikle netlink_attachskb nasıl 1 döndürür ki yeniden deneme mantığına sorunsuz bir şekilde girilir. Netlink_attachskb uygulamasına tekrar bakın.

Satır 1657, nlk_sk işlevi aracılığıyla sk aracılığıyla netlink_sock alın. Buradaki nlk_sk aşağıdaki gibidir.

Makro container_of çağırarak netlink_sock alın. Netlink_sock yapısı aşağıdaki gibidir:

Netlink_sock yapısının ilk üyesi sock türüdür ve sock yapısının ilk üyesi sokettir. Satır 1660, yargı girilmesi gerekiyorsa ilki.

! netlink_skb_is_mmaped (skb) true döndürmelidir, anahtar sk- > sk_rmem_alloc > sk- > sk_rcvbuf || test_bit (NETLINK_CONGESTED, nlk- > durum) Sonuç doğru olmalıdır.

Burada sk- > Sk_rmem_alloc'un boyutu kontrolün baypas edilmesi için daha uygundur.Kod aşağıdaki gibidir.

Eğer yargılama başarısız olursa, aşağıda gösterildiği gibi netlink_skb_set_owner_r işlevini çağırın.

Satır 878, atomik toplama işlemini gerçekleştiren atomic_add makrosunu çağırın. Bu kod satırının anlamı şudur: sk- > Sk_rmem_alloc temelinde skb- ekleyin > gerçek boyut. Sk- eşdeğeri > sk_rmem_alloc + = skb- > gerçek boyut. Bu işlevdeki bu kod satırı doğrudan sk- > Sk_rmem_alloc'un boyutu, sk- değerini artırmak için netlink_skb_set_owner_r işlevini birden çok kez çağırabilir misiniz? > Rmem_alloc'un değeri? Teorik olarak tamamen mümkün, bakalım bu işleve kullanıcı katmanından nasıl ulaşacağız.

Netlink_skb_set_owner_r'nin çağrı zincirini anlama aracını kullanarak hızlı bir şekilde bulabilirsiniz:

netlink_sendmsg- > netlink_unicast- > netlink_attachskb- > netlink_skb_set_owner_r

İşlev çağrısı yolu sorunsuz bir şekilde nasıl geçirilir? Burada netlink_sendmsg'den netlink_skb_set_owner_r'ye nasıl ulaşacağımızı analiz etmemiz gerekiyor.

Netlink_sendmsg işlevi aşağıdaki gibi uygulanır.

Satır 2285, ilk yargıç mesajı- > msg_flag MSG_OOB olamaz, aşağıya bakmaya devam edin.

2292 Satır, yargıç msg- > Msg_namelen uzunluğu burada boş bırakılmamalı, elbette boş kalmayacaktır. If girdikten sonra, yargıç adr- > Nl_family eşittir AF_NETLINK. Satır 2299, dst_group veya dst_portid'in boş olmadığına karar verin, dst_group multicast modunu temsil eder ve dst_portid addr- > nl_pid, dolayısıyla dst_portid'in boş olmadığından emin olmak daha kolaydır. Sonraki:

Satır 2320, yargılanan mesaj- > msg_iter.iov- > iov_base boş olamaz. Ve len sk- > sk_sndbuf-32.

Aslında, tüm işlevde kullanıcı katmanı tarafından yalnızca çok fazla kontrol edilebilir. Doğrudan netlink_unicast çağrısına bakın.

Netlink_unicast işlevi aşağıdaki şekilde uygulanır:

Tüm işlevde, kullanıcı çok fazla kontrol edemez. Satır 1783, timeo ayarlandı, burada bloksuzluğun msg- > msg_flagsMSG_DONTWAIT, böylece iş parçacığı engellenmez. Satır 1790, sk'nin sk'nin çekirdek sürümü olup olmadığına karar verin ve kullanıcı katmanında bir soket oluştururken NETLINK_USERSOCK kullanılmalıdır. Satır 1793, sk_filter olup olmadığına karar verir, burada if ifadesinin girilmemesi ve filtre ayarlanmaması garanti edilir. Satır 1800, netlink_attachskb'yi doğrudan çağırın ve netlink_skb_set_owner_r işlevine başarıyla ulaşın. Bu, netlink_sendmsg çağrısı yaparak sk- 'nin artması olarak kabul edilir > Sk_rmem_alloc süreci. Aslında, sadece sk- > sk_rmem_alloc, sk- > sk_rcvbuf.

Peki sk- > sk_rcvbuf? Setsockopt işlevinde, sock_setsockopt işlevindeki sk- öğesini bulun > Sk_rcvbuf'un çalışması.

Satır 773, sk- > sk_rcvbuf, val * 2 ile SOCK_MIN_RCVBUF arasındaki maksimum değeri alır. 755 satırında val, val ile sysctl_rmem_max arasındaki minimum değeri alır. Satır 749, bu durum SO_RCVBUF. Bakmaya devam et.

Satır 693, optlen değerinin sizeof (int) değerinden küçük olmadığından emin olun. Satır 696, optval'ı val'e atayın, burada optval kullanıcı tarafından kontrol edilebilir. Satır 703, anahtar tercih adını dağıtır, bu nedenle seçim adının SO_RCVBUF olduğundan emin olun. Bu şekilde, modifikasyon skinin sorunsuz bir şekilde ulaşmasını sağlayabilirsiniz. > Rcvbuf kodu.

Bu noktada, netlink_attachskb fonksiyonundaki ilk kontrolü iki şekilde atlıyoruz.

1) sk- through netlink_sendmsg'yi artırın > Sk_rmem_alloc'un değeri.

2) sock_setsockopt ile sk- mümkün olduğunca azaltın > Rcvbuf'un değeri.

İf ifadesini girdikten sonra, aşağıdaki koda bakın:

Bu kod, mevcut iş parçacığının bekleme durumuna girmesini ve doğrudan engellemesini sağlayacaktır. Bekleme durumuna girmek istemiyorsanız, sadece sock_flag'i SOCK_DEAD olarak ayarlayın. Ancak sock_flag, SOCK_DEAD olarak ayarlanmışsa, bunu daha sonra yapmaya gerek yoktur, bu nedenle burada bekleme durumuna girmek gerekir. Akıllıca bir yol, iş parçacığını uyanmaya zorlamak için doğrudan wake_up_interruptible'ı çağırmaktır. Wake_up_interruptible nasıl çağırılır? İşlev çağrı zinciri çok kısadır: netlink_setsockopt- > wake_up_interruptible.

Netlink_setsockopt işlevinde:

Satır 2182, iş parçacığını uyandırmak için wake_up_interruptible'ı çağırın. Satır 2178, vaka NETLINK_NO_ENOBUFS.

Satır 2131, seviyenin SOL_NETLINK olması gerektiğini belirleyin, satır 2134, seçim adının NETLINK_RX_RING ve NETLINK_TX_RING olamayacağını belirleyin ve optlen'in sizeof (int) değerinden büyük veya ona eşit olduğundan emin olun. Satır 2139, anahtar tercih adını dağıtır, burada seçim adının NETLINK_NO_ENOBUFS olduğundan emin olmalısınız. Bu noktada, temelde netlink_attachskb'nin 1 döndürmesi garanti edilir.

Yeniden deneme döngüsüne girdikten sonra çorabın şu anda boş olmadığından emin olun. Ardından, yeniden deneme döngüsünde bir hata yapın ve doğrudan dışarı atlayın, kod aşağıdaki gibidir:

Satır 1232, fdget aracılığıyla notification.sigev_signo'nun fd'sini alın. Notification.sigev_signo, kullanıcı modundan geçirilir, bu nedenle soketi doğrudan kullanıcı katmanında kapatmak tamamen mümkündür. Kullanıcı katmanındaki soketi kapattıktan sonra, satır 1233, if mantığını girin ve ardından çıkış etiketine atlayın.

Şu anda çorap boş değil, doğru olarak değerlendirilirse, netlink_destachskb girin ve ardından ücretsiz çökmeler.

Üç, boşluklar çoğalır

UAF tipi güvenlik açıkları için genel yöntem, pozisyonları işgal etmek için yığın spreyi kullanmaktır. Bu güvenlik açığında birçok kez yayımlanan nesne, netlink_sock nesnesidir. Netlink_sock nesne boyutu, 1008 bayt olan 0x3f0 bayttır.

Çekirdek nesne bellek ayırma kurallarına göre, netlink_sock nesnesi kmalloc-1024 önbelleğinden tahsis edilmelidir.

Döşeme dağıtıcısı, nesneleri atarken son giren ilk çıkar kuralını izler.

Aşağıda, levha ayırıcı nesneleri serbest bırakma işlemidir.

Serbest bırakılacak nesne objesi ac- > Girişin sonu. Aşağıda, levha ayırıcı tarafından nesnelerin atanması işlemidir:

Nesneleri doğrudan ac- > Girişin sonunda bir nesne açılır.

Dolayısıyla, henüz serbest bırakılan bir nesne bağlantılı listenin sonundadır.Eğer nesne şu anda aynı önbellekte tahsis edilirse, az önce serbest bırakılan nesne yeniden tahsis edilecek ve iki işaretçi aynı bellek adresini işaret edecektir. İstenen belleğin tam olarak savunmasız nesnenin bellek konumuna düştüğünden emin olmak için birkaç noktayı kavramanız gerekir:

Yığın püskürtme nesnesi tarafından kullanılan çekirdek önbelleği, savunmasız nesne belleğiyle aynı önbellekte olmalıdır. Yani, boyut aynı kmalloc-X'e düşmelidir;

ac'nin kendisi, her CPU için bir yerel önbellek olan array_chche yapısıdır, bu nedenle yığın püskürtme uygulamasının nesnesi ile savunmasız nesnenin aynı CPU yerel önbelleğinde olmasını sağlamak da gereklidir;

Yığın püskürtme için uygulanan nesne yalnızca kısa bir süre kalırsa, uygulanan nesne işlev geri döndüğünde serbest bırakılır ve koltuğun doğru şekilde oturmaması ile sonuçlanır. Bu nedenle, istenen nesnenin serbest bırakılmayacağından, en azından savunmasız nesne kullanıldığında serbest bırakılmayacağından emin olmak gerekir.Burada, bazı sistem çağrı süreçlerini engellemek için bir yerleşik bellek alanı kullanılmalıdır;

levha önbellek parçalanma problemi, burada işgal edilecek nesnenin boyutu 1008, nesne boyutu nispeten büyük, sayfanın dörtte birini kaplıyor, göreceli olarak düzenli, parçalanma sorunu olmamalı;

Öyleyse yığın spreyinin başarılı olup olmadığına nasıl karar verilir?

Genel olarak, yığın püskürtme nesnesini oluştururken, sihirli değerin savunmasız nesneye karşılık gelen bazı özel üye alanlarının bellek ofsetinde ayarlanması ve ardından yargı için savunmasız nesnedeki ilgili verileri elde etmek için sistem çağrısının kullanılması gerekir. . Netlink_sock yapısının birkaç anahtar üyesi aşağıdaki gibidir.

Verileri almak için getsockname sistem çağrısını kullanın, getsockname netlink_getname işlevini çağıracaktır. Netlink_getname işlevine özellikle bakın:

1576 kod satırı, netlink_sock nesnesindeki portid'i nladdr'ye kopyalayın > nl_pid. Kodun 1577 satırı, nlk- ise > grup 0, set nladdr- > nl_groups, NULL olarak atanır, nlk- > Grup işaretçisi, yığın püskürtme nesnesini oluştururken gruplar alanını doğrudan sıfırla doldurabilir. Ve nladdr, adres'den dönüştürülür ve adres, kullanıcı katmanından geçirilen arabellektir.

Yığın püskürtmenin başarısı aşağıdaki gibidir:

Olağan durum, duruma bağlı olarak, yapıdaki işlev işaretçisini veya işlev işaretçisini içeren yapı üyesini örtmektir. Burada bekleme bekleme kuyruğunu geçersiz kılmayı seçin. Netlink_sock yapısı aşağıdaki gibidir:

Wait_queue_haed_t yapısı aşağıdaki gibidir:

Task_list üyesi, iki yönlü dairesel bağlantılı bir liste başlığıdır ve görev_listesine bağlanan her üye, işlenmesi gereken bekleyen bir rutin öğedir. Bu üye nasıl kullanılır? Aşağıdaki koda bakın.

Bu, netlink_setsockopt işlevindeki kod parçacığıdır. İş parçacığını yeniden başlatma analizi daha önce analiz edilmiştir. Burada, netlink_sock nesnesindeki bekleme rutini ve nlk- parametresi çağrılacaktır. > Bekle. Ayrıntılı analize devam edin:

__Wake_up_common işlevini çağırın:

Kod 70, makro list_for_entry_safe geçişler q- > Görev_listesindeki üyeler, curr'a dönün. Kodun 68. satırı, curr, q- gösteren wait_queue_t işaretçisidir. > Task_list bağlantılı liste wait_queue_t türünde öğeler içerir. Wait_queue_t'nin yapısı aşağıdaki gibidir:

Wait_queue_t yapısında bir işlev gösterici func vardır. __Wake_up_common işlevinin 73. satırındaki koda bakın, doğrudan curr'u çalıştırın > Func işlevi __wait_queue işlevinin func parametresini oluşturarak RIP'yi kontrol edebilir. List_for_each_entry_safe makrosuna tekrar bakıldığında:

pos, __wait_queue öğesidir, 62 satırlık kod, pos- > üye.next referansı anlamak için, burada konum- > Üye __wait_queue'daki görev_ listesidir. __Wait_queue'daki görev_listesi aynı zamanda bir list_head'e işaret etmesi gereken bağlantılı bir liste başıdır, bu nedenle makronun başka bir yere başvurmasını kolaylaştırmak için sahte bir list_head oluşturulmalıdır. Test aşağıdaki gibidir:

Bir sonraki adım, ayrıcalık yükseltme kodunu yürütmek için SMEP'i ROP zinciri üzerinden atlamaktır. Haklar başarıyla yükseltildikten sonra şu şekilde görünür:

* Yazar: ADLab, lütfen FreeBuf.COM'dan belirtin.

Sıfır çalıştırma "doğrudan operasyon + şehir ortağı" satış hizmeti modeli ortaya çıktı ve ilk deneyim merkezi Kasım'da Hangzhou'da açıldı - Küresel Gelecek Mobilite Konferansı 2018
önceki
Sualtında çekilen seyir defteri çok güzel olabilir mi? ! Gosha'nın yaratıcılığı bu sefer küçük değil!
Sonraki
özel! 2013-2017 Lisansüstü Giriş Sınavı Ulusal Trend Haritası (Yüksek Lisans | Özel Yüksek Lisans)
Harekete geçirmeye ve tüketime saldırmaya güvenerek, fırlatıcıyı Tian Yuji'ye karşı patlat
"Son Gün Doğumu" yeni bilim kurgu sularını test etmek için bugün yayında, yerel üretim dünya sahnesinde
Alipay APP, kullanıcı resimlerini sessizce toplamakla ilgili sorgulandı ve resmi personel yanıt veriyor gibi
Üç renge uyan akılda kalıcı görseller, Nike Air More Uptempo'nun göz alıcı yeni çalışması yakında satışta!
Yanzhao.com'un ayarlama sistemi yine bozuldu! Bu ayarlama tekniklerini kullanmalısınız
Bahar Şenliği sırasında kapanmayan Nubia X, sınırlı bir süre için 300 yuan düşecek!
SAIC Maxus G10, 229.800 için dizel üst düzey modeller ekliyor
Yaramaz Film Günü Patlaması | "Kaptan Marvel" Kuzey Amerika ön satışları Marvel'ın ilk üçe, sadece "Reunion 3" ve "Black Panther" den sonra ikinci
Chuangxin Qizhi'den CTO Zhang Faen ile röportaj: Bir sonraki dev AI + B2B alanında doğacak
En yüksek tasarım seviyesini temsil eden Vault by VANS, yine ortak markalı! En sevdiğiniz Sk8-Hi'ye sahip olun
Yang Chaojiao, pirinç pişiricili pilav pişirici Mi Family Bucket'ın harika olduğunu görünce şaşırır!
To Top