Hoşgeldin Misafir

Adim Adim Linux Kernel Exploitation - Linux Kernel Olusturma

CWGaZaNFeR

15 Ağu 2023
407 Mesaj

Aktiflik

Seviye

Deneyim

TIM / GÖREV:
Es-selamun aleykum ve rahmetullah Allahin rahmeti ve bereketi sizlerin uzerine olsun degerli Turkhacks uyeleri.

Oncelikle bu konuyu bir seri halinde yazacagimi bildirmek isterim. Bu seride, daha onceden yayinlanmis ve CVE kodu CVE-2017-11176 olan zafiyet takip edilerek bir
Linux kernel exploit gelistirmek icin adim adim izlenecek yol anlatilacaktir. Yani bu yazida yapilan is, zaten yayinlanmis bir zafiyetin uygulamasini yapmaktir.

Bu seriye, oncelikle yazilim hatasini (bug) anlamak ve onu kernel alanindan tetiklemek icin yama analiziyle baslanacak, ardindan kademeli olarak bir PoC kodu olusturulacaktir. PoC kodu daha sonra son kisimda ise, arbitrary code execution (keyfi kod calistirmak) icin kullanilan bir arbitrary system call’a (keyfi sistem cagrisina) donüstürülecektir.

Hedef kitle, Linux kernel’inin calisma yapisini yeni ogrenmeye baslayanlar oldugu icin, bu calisma Linux kernel’inin calisma yapisini ve istismarini zaten bilenler icin cok ilginc olmayabilir. cogu kernel exploiting makalesi, okuyucunun kernek koduna zaten asina oldugu on kabulü ile yazildigindan, bu makaleleri anlamada eksiklikler ortaya cikabilmektedir. Bu makalede, kernel veri yapisini ve onemli kod yollarini on planda tutarak diger makalelerde ortaya cikan bu boslugu doldurmaya calisacagiz. Yazinin sonunda, istismarin her bir satiri ve bunlarin kernel üzerindeki etkisi okuyucu tarafindan anlasilmis olmasi amaclanmaktadir.

Her seyi tek bir makalede ele almak imkansiz olsa da, istismari gelistirmek icin gereken her kernel yolunu (kernel path) aciklamaya calisacagiz. Bunu uygulamali bir ornekle desteklenen rehberli bir Linux kernel turu olarak düsünebilirsiniz. Exploit kodu yazma, aslinda Linux kernel’ini anlamanin iyi bir yoludur. Ek olarak, bazi hata ayiklama teknikleri, araclar, yayginca yapilan hatalar ve bunlarin nasil düzeltilecegini gostermeye calisacagim.

640px-Kernel_Layout.svg.png


Burada gelistirilen exploit kodu, “mq_notify: double sock_put()” olarak da bilinen CVE-2017-11176 CVE koduna sahip zafiyetin exploit kodudur.
Not: cogu Linux isletim sistemi dagitimi, 2017’nin ortalarinda bu zafiyeti gidermek üzere yama da cikaramamistir. Ancak su an elbette bu zafiyet dagitimlarda giderilmistir.

Burada gosterilen kernel kodu belirli bir sürümün sahip oldugu kodlara sahiptir (v2.6.32.x) ve bununla birlikte ilgili bug, 4.11.9 sürümüne kadar olan kernel’lari da etkiler. Bu versiyonun cok eski oldugu düsünülebilir, ancak hala bircok yerde kullaniliyor ve bu versiyonda kullanilan bazi kernel yollarini anlamak daha kolay olacaktir. Ayni zamanda bu yazida kullanilandan daha yeni bir kernel’da esdeger kernel yollari bulmak oldukca mümkündür.

Burada olusturulan exploit kodu bir hedef ozelindedir. Bu nedenle, onu baska bir hedefte calistirmak icin bazi degisiklikler gereklidir (structure offsets/layout, araclar, fonksiyon adresleri vb). Exploit kodunun son halini burada bulabilirsiniz ancak exploit kodunu oldugu gibi sisteminizde calistirmayin, cünkü bu exploit kodu sisteminizi cokertecektir!

Güvenlik zafiyeti bulunan bir kernel’in kaynak kodunu indirmeniz ve bu kernel calisirken kodu takip etmeye calismaniz (hatta daha iyisi, exploit kodunu bu sistemde calistirmaniz) onerilmektedir.

Uyari: Lütfen bu yazi dizisinin boyutu sizi korkutmasin, yazinin büyük bir bolümü kodlardan olusmaktadir. Ancak sunu da unutmayin ki, gercekten kernel exploiting’ine girmek istiyorsaniz, buyuk miktarlarda kod ve doküman okumaya hazir olmalisiniz.

Bu makale, Linux kernel konusunun yalnizca kücük bir alt kümesini kapsamaktadir. Asagida belirtilmis harika kitaplari okumanizi tavsiye ederim:


  • Understanding the Linux Kernel (D. P. Bovet, M. Cesati)
  • Understanding Linux Network Internals (C. Benvenuti)
  • A guide to Kernel Exploitation: Attacking the Core (E. Perla, M. Oldani)
  • Linux Device Drivers (J. Corbet, A. Rubini, G. Kroah-Hartman)

LAB KURULUMU


Burada gosterilen kernel kodu belirli bir sürümün sahip oldugu kodlara sahiptir (v2.6.32.x). Ancak, exploit kodunu “Debian 8.6.0 (amd64) ISO” hedefi üzerinde uygulayabilirsiniz. Kodda exploit islemimizi engellemeyecek kücüklükte degisiklikler bulunabilir, ancak bu bir problem olusturmamaktadir.

Yukaridaki imaj, 3.16.36 kernel sürümüne sahiptir. Bu imaj dosyasinda ilgili bug’in oldugu ve bu bug’in belirtilen kernel’in cokmesine neden olabildigi test edilmis ve onaylanmistir. Koddaki degisikliklerin cogu, kernel exploitation’in son asamalarinda yapilacaktir.

Yazilim hatasi cesitli konfigürasyonlarda/mimaride kullanilabilir olsa da, ileri asamalarda herhangi bir sorun cikmadan kullanmak icin mevcut gereksinimler sunlardir:


  • Kernel sürümü 4.11.9’dan düsük olmalidir (4.x’ten kücük sürümleri oneririz)
  • “amd64” (x86-64) mimarisinde calismak zorundadir
  • Debugging (hata ayiklamasi) yapabilmek icin root erisiminiz olmalidir
  • Kernel, SLAB allocator kullanmalidir
  • SMEP ayari etkinlestirilmis olmalidir
  • kASLR ve SMAP devre disi birakilmis olmalidir
  • Bellegin (Memory/RAM) 512MB ve üzeri olmasi gerekmektedir
  • Herhangi bir sayida CPU. Tek CPU yeterli olacaktir. Bunun sebebini ilerleyen bolümlerde anlayacaksiniz.

UYARI: onerilen imaj dosyasindaki kernel farkliligindan dolayi CPU sayisinin 1 olarak ayarlanmasi tavsiye edilir. Aksi takdirde, reallocation’in ek adimlara ihtiyaci olabilir.

onerilen imaj dosyasindaki varsayilan yapilandirma ayarlari, yukaridaki tüm gereksinimleri karsilamaktadir. Exploit kodunu baska bir hedefe yonelik gelistirmek istiyorsaniz, serinin ileri ki bolümlerine iyi bir sekilde odaklanmaniz tavsiye edilmektedir.

SLAB/SMEP/SMAP’in ne oldugunu bilmiyorsaniz endiselenmeyin, bu kavramlar ileri kisimlarda ele alinacaktir.

UYARI: Debugging’i kolaylastirmak icin hedef Linux kernel’ini bir sanallastirma platformuyla calistirmalisiniz. Ancak, SMEP’i desteklememesi sebebiyle VirtualBox yaziliminin kullanilmasi onerilmemektedir. ornegin; VMWare yaziliminin ücretsiz sürümünü veya SMEP’i destekleyen herhangi bir sanallastirma aracini kullanabilirsiniz.


Sistem yüklendikten sonra (LiveCD üzerinde gelistirme yapilmamalidir), sistem yapilandirmasinin beklendigi gibi olup olmadigini kontrol etmemiz gerekmektedir.

SLAB/SMEP/SMAP/KASLR Durum Kontrolu


SMEP özelliginin aktif olup olmadigini anlamak icin aşagiıdaki komutu calistiriniz. Komutun ciktisinda "smep” yer almalidir:

Kod:
$ grep "smep" /proc/cpuinfo
flags   : [...] smep bmi2 invpcid
                ^--- buradaki

Eger çiktida “smep” yer almiyorsa, cat /proc/cmdline komutunun çiktisinda “nosmep” olmamasi gerekmektedir. Eger varsa, /etc/default/grub dosyasini düzenlemeniz ve aşagidaki satirlari degiştirmeniz gerekmektedir:

Kod:
# /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet"              // "nosmep" içermemelidir
GRUB_CMDLINE_LINUX="initrd=/install/initrd.gz"  // "nosmep" içermemelidir

Ardindan update-grub komutunu calistirdiktan sonra sisteminizi yeniden baslatin. Daha sonra bu ozellik halen devre disi ise (cat /proc/cpuinfo komutu ile kontrol edebilirsiniz), baska bir sanallastirma araci kullanmaniz gerekmektedir.

SMAP ozelligi icin ise tam tersini yapmaniz gerekecek. oncelikle grep /proc/cpuinfo komutu ile ciktida “nosmap” olup olmadigi kontrol edilmelidir. Eger ciktida “smap” yok ise, her sey yolunda demektir. Aksi takdirde, grub yapilandirma dosyaniza “nosmap” eklemeniz gerekmektedir. Ardindan update-grub komutunu calistirip sisteminizi yeniden baslatmaniz gerekmektedir.

Burada gelistirilen exploit kodu, sabit kodlanmis adresleri kullanmaktadir. Bu sebeple, kASLR ozelligi devre disi birakilmalidir. kASLR ozelligi, ASLR (Address Space Layout Randomization) ozelliginin kernel icin yapilmis seklidir. kASLR ozelligini devre disi birakmak icin grub komut satirina “nokaslr” secenegini ekleyebilirsiniz (nosmap ozelliginde yapildigi gibi). Islemler sonucunda grub komut satiri asagidaki gibi olmalidir:

Son olarak, cekirdegimizin SLAB allocator kullandigindan emin olmamiz gerekmektedir. Asagidaki komut ile kernel’in SLAB allocator kullandigini dogrulayabilirsiniz:


Kod:
$ grep "CONFIG_SL.B=" /boot/config-$(uname -r)
CONFIG_SLAB=y

Ciktinin CONFIG_SLAB=y olmasi gerekmektedir. Debian varsayilan olarak SLAB kullanirken Ubuntu varsayilan olarak SLUB kullanir. Eger hedef kernel SLAB kullanmiyorsa, kernel’i yeniden derlemeniz gerekir. Yeniden derleyebilmek iCin ise isletim sistemi dagitiminin dokumantasyonuna bakabilirsiniz.

Yeniden belirtmekte fayda var, yukarida paylastigim ISO dosyasi tum bu gereksinimleri karsiladigi icin onu kullanmanizi oneririm.


SystemTap’i Yukleme


Daha oncede belirtildigi gibi, kullanilmasi tavsiye edilen ISO dosyasi bug barindiran zafiyetli bir kernel’i calistirir (3.16.36 (uname -v) sürümüne sahiptir ve 3.16.47 versiyonunda yama yapilarak zafiyet giderilmistir).

UYARI: Kernel’i güncelleyebilecegi icin otomatik SystemTap kurulum prosedürünü uygulamamalisiniz!

Bu nedenle, zafiyetli sürümümüz icin gerekli olan .deb paketlerini indirmemiz ve bu paketleri manuel olarak sistemimize yüklememiz gerekecek. İhtiyacimiz olacak paketlerin listesi asagidadir:


  • linux-image-3.16.0-4-amd64_3.16.36-1+deb8u1_amd64.deb
  • linux-image-3.16.0-4-amd64-dbg_3.16.36-1+deb8u1_amd64.deb
  • linux-headers-3.16.0-4-amd64_3.16.36-1+deb8u1_amd64.deb

Gerekli paketleri bu linkten indirebilirsiniz, dilerseniz asagidaki komutlari calistirarak indirmeniz mumkun:

Kod:
# wget https://snapshot.debian.org/archive/debian-security/20160904T172241Z/pool/updates/main/l/linux/linux-image-3.16.0-4-amd64_3.16.36-1%2Bdeb8u1_amd64.deb
# wget https://snapshot.debian.org/archive/debian-security/20160904T172241Z/pool/updates/main/l/linux/linux-image-3.16.0-4-amd64-dbg_3.16.36-1%2Bdeb8u1_amd64.deb
# wget https://snapshot.debian.org/archive/debian-security/20160904T172241Z/pool/updates/main/l/linux/linux-headers-3.16.0-4-amd64_3.16.36-1%2Bdeb8u1_amd64.deb

Paketleri indirdikten sonra asagidaki komutlar ile yukleyebilirsiniz:

Kod:
# dpkg -i linux-image-3.16.0-4-amd64_3.16.36-1+deb8u1_amd64.deb
# dpkg -i linux-image-3.16.0-4-amd64-dbg_3.16.36-1+deb8u1_amd64.deb
# dpkg -i linux-headers-3.16.0-4-amd64_3.16.36-1+deb8u1_amd64.deb

Yuklemeleri tamamladiktan sonra sisteminizi yeniden baslatip asagidaki komut ile systemtap’i sisteminize kurunuz:

Kod:
# apt install systemtap

Son olarak her seyin dogru yuklendiginden emin olmak icin asagidaki komutu calistiriniz:

Kod:
# stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'
stap: Symbol `SSL_ImplementedCiphers' has different size in shared object, consider re-linking
Pass 1: parsed user script and 106 library script(s) using 87832virt/32844res/5328shr/28100data kb, in 100usr/10sys/118real ms.
Pass 2: analyzed script: 1 probe(s), 1 function(s), 3 embed(s), 0 global(s) using 202656virt/149172res/6864shr/142924data kb, in 1180usr/730sys/3789real ms.
Pass 3: translated to C into "/tmp/stapWdpIWC/stap_1390f4a5f16155a0227289d1fa3d97a4_1464_src.c" using 202656virt/149364res/7056shr/142924data kb, in 0usr/20sys/23real ms.
Pass 4: compiled C into "stap_1390f4a5f16155a0227289d1fa3d97a4_1464.ko" in 6310usr/890sys/13392real ms.
Pass 5: starting run.
read performed                                      // <--------------
Pass 5: run completed in 10usr/20sys/309real ms.

Son Kontroller


systemtap paketine ek olarak, exploit kodunu derlemek ve calistirmak icin hedef kernel kullaniacaktir, bu nedenle asagidaki komutu calistirmalisiniz:

Kod:
# apt install binutils gcc

Simdi ise exploit kodunu indirin.

Kod:
$ wget https://raw.githubusercontent.com/lexfo/cve-2017-11176/master/cve-2017-11176.c

Onerilen ISO ve makale hedefleri arasindaki kaynak kod farkliliklari nedeniyle, exploit kodunda yer alan “used-after-freed” nesnesi “kmalloc-1024” yerine “kmalloc-2048” onbellek degerine tanimlanmistir. Yani exploit kodunun calisabilmesi icin exploit kodunda asagidaki degisikligin yapilmasi gerekmektedir:

Kod:
#define KMALLOC_TARGET 2048 // 1024 yerine 2048 yazdık

Bu degisikligin sebebini ileri kisimlari okudugunuzda daha iyi anlayacaksiniz. simdi yapmamiz gereken, asagida gosterildigi gibi kodu derleyip calistirmak:


Kod:
$ gcc -fpic -O0 -std=c99 -Wall -pthread cve-2017-11176.c -o exploit
$ ./exploit
[ ] -={ CVE-2017-11176 Exploit }=-
[+] successfully migrated to CPU#0
[+] userland structures allocated:
[+] g_uland_wq_elt = 0x120001000
[+] g_fake_stack   = 0x20001000
[+] ROP-chain ready
[ ] optmem_max = 20480
[+] can use the 'ancillary data buffer' reallocation gadget!
[+] g_uland_wq_elt.func = 0xffffffff8107b6b8
[+] reallocation data initialized!
[ ] initializing reallocation threads, please wait...
[+] 200 reallocation threads ready!
[+] reallocation ready!
[+] 300 candidates created
[+] parsing '/proc/net/netlink' complete
[+] adjacent candidates found!
[+] netlink candidates ready:
[+] target.pid = -4590
[+] guard.pid  = -4614
[ ] preparing blocking netlink socket
[+] receive buffer reduced
[ ] flooding socket
[+] flood completed
[+] blocking socket ready
[+] netlink fd duplicated (unblock_fd=403, sock_fd2=404)
[ ] creating unblock thread...
[+] unblocking thread has been created!
[ ] get ready to block
[ ][unblock] closing 576 fd
[ ][unblock] unblocking now
[+] mq_notify succeed
[ ] creating unblock thread...
[+] unblocking thread has been created!
[ ] get ready to block
[ ][unblock] closing 404 fd
[ ][unblock] unblocking now
[ 55.395645] Freeing alive netlink socket ffff88001aca5800
[+] mq_notify succeed
[+] guard socket closed
[ 60.399964] general protection fault: 0000 [#1] SMP
... cut (other crash dump info) ...

<<< HIT CTRL-C >>>

Bu, hedef icin olusturulmadigindan exploit kodu basarisiz oldu ve bize root shell’i vermedi. Ileride goreceginiz uzere, exploit kodu degisiklik gerektiriyor. Ancak, bu exploit kodu ilgili bug’in barindigini bizlere dogrulamaktadir.

UYARI: Hedefimiz ile onerilen ISO arasindaki diger kod farkliliklari nedeniyle, bazi kernel cokmeleri almayacaksiniz. Bunun nedeni, kernel’in belirli bir bug’da (yukaridaki gibi) otomatik olarak cokmek yerine exploit kodunu kapatmasi veya oldurmesidir. Ancak kernel exploit kodunun calistigi anda kararsiz bir durumda ve her an cokebilir konumdadir. Exploit kodunu okudugunuz taktirde kodlarin arasindaki farklari anlayabilirsiniz.


Kernel Kaynak Kodunu Edinmek


Sistem, kurulumundan sonra kullanima hazir hale getirildikten sonraki adim, kernel kaynak kodunu edinmektir. Eski bir kernel kullandigimizdan dolayi onu asagidaki komutlari kullanarak manuel olarak indirmemiz gerekecek:

Kod:
# wget https://snapshot.debian.org/archive/debian-security/20160904T172241Z/pool/updates/main/l/linux/linux-source-3.16_3.16.36-1%2Bdeb8u1_all.deb

Yuklemek icin ise:

Kod:
# dpkg -i linux-source-3.16_3.16.36-1+deb8u1_all.deb

Kernel kaynak kodu su konumda bulunmali: “/usr/src/linux-source-3.16.tar.xz”

Hedef kernel cok fazla cokeceginden, kernel kodunu analiz etmek ve exploit kodunu gelistirmek icin ana sisteminizi kullanmaniz gerekecektir. Yani bu kaynak kodunu ana sisteminize de indirmenizde fayda var. Hedef zafiyetli makine yalnizca exploit kodunu derlemek/calistirmak ve SystemTap islemi icin, SSH araciligiyla kullanilmalidir.

Buradan sonraki adimlarda dilediginiz kod tarama uygulamasini kullanabilirsiniz. Ancak sembollere verimli bir sekilde capraz referans (cross-reference) verebilmeniz gerektigini unutmamaniz gerekmektedir. Linux, milyonlarca satir koddan olusan bir kernel oldugu icin, iyi bir kod tarama uygulamasi olmadan bu kodlarin icinde kaybolmaniz cok olasidir.

cscope uygulamasinin bir cok cekirdek gelistirici tarafindan kullanildigi gorulmektedir. capraz referans verme islemini su sekilde ya da asagidaki kod ile yapabilirsiniz:

Kod:
cscope -kqRubv

Kernel “freestanding” konumda calisirken system library basliklarini haric tutan “-k” parametresine dikkat etmekte fayda var. cscope veritabani olusturma islemi birkac dakika surcektir. Ardindan cscope eklentisi olan bir metin duzenleyicisi secmenizde fayda var. (ornegin; vim, emacs)

Artik ilk kernel exploit kodunuzu gelistirmeye hazirsiniz!


Misyon dahilinde kullaniniz, selam ve dua ile.