[Turkish] Global Constructor and Destructor Crashes in ELF File System

EDB-ID:

14842

CVE:

N/A

Author:

murderkey

Type:

papers

Platform:

Linux

Published:

2010-08-30

-------- ELF32 UNIX DOSYA SISTEMLERINDE GLOBAL_CONSTRUCTOR ve GLOBAL_DESTRUCTOR PATLAMALARI--------


Author : murderkey 
Contact: murderkey[_*at*_]hellcode.net
Visit  : http://www.hellcode.net/mkey
Date   : 12/20/2005

$$$$$$$$$$$$$$$$$$$$     $$$$$$$$$$$$$$$$$$$$$$$  $$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$

Bu ufak dokumanda elf32 dosya sistem yapisinda bulunan global_constructor ve global_destructor lar
nasil patlatilir onu gostermeye calisacagim. Aslinda bu yaziyi ozel olarak hazirlamadim, __inline__
assembly kodlarken constructorlara fonksiyon atamasi yapmam gerekti ve burda kullandigim datalarin
birinde overflow (hafiza tasmasi) meydana geldigi icin, ilgilenen assembly programcilarina bir fikir
olsun diye yaziyorum.

NOT: Bu tur bi hafiza tasmasiyla daha once karsilasmadim, zaten real time programlarda bu tur aciklarin
bulunma olasiligi bir hayli dusuktur, cunku hic bir programci constructor atamasi veya destructor atamasi
yapmaya ihtiyac duymaz, bunlara ihtiyac duyan kisiler bizim gibi C programlama dilinin yetmedigi yerlerde
__inline__ assembly kullanan kisilerdir.

Evet asagidaki vulnerable program uzerinde calisiyoruz.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static void murderkey_morfin() __attribute__ ((constructor));
static void murderkey_extasy() __attribute__ ((destructor));


int main(void) {
  
  fprintf(stderr," program main fonksiyonu calistirabilecekmi ?\n");
  return(EXIT_SUCCESS);
}

static void murderkey_morfin() {
 char overdoze[0x16];
 printf("Program matrixe girmeden cakilacak -> SIGSEGV\n");
 strcpy(&overdoze[0],"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
 return;
}

static void murderkey_extasy() {
 fprintf(stderr,"Program patlamazsa bu yaziyi gormeniz lazim\n");
 return;
}




Evet gordugunuz gibi, program elf32 constructor kisminda murderkey_morfin() fonksiyonunu
barindiriyor ve bu fonksiyon strcpy ile 20 bytelik bir hafizayi overflow ediyor.

Burda onemli olan constructor ve destructorlarin main() fonksiyonundan once hafizaya yuklenmesi
ve calistirilmasidir.

Programimizi derleyip calistiralim bakalim ne olacak.

h4x0r elf32 # gcc murderkey-overdoze.c -o murderkey-overdoze -W -Wall -ggdb3

h4x0r elf32 # ./murderkey-overdoze 
Program matrixe girmeden cakilacak -> SIGSEGV
Segmentation fault
h4x0r elf32 # 

Evet bizimde bekledigimiz gibi main() e girmeden once constructor larda programimiz patladi. SIGSEGV.
Simdi bizim burda dikkat edecegimiz yer programin hafizayi nasil kullandigi ve bu aciktan istifade ederek
exploit etmek. Programi Gdb ile attach edip hemen inceleyelim.

h4x0r elf32 # gdb -q ./murderkey-overdoze
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) 
(gdb) maintenance info sections
Exec file:
    `/root/elf32/murderkey-overdoze', file type elf32-i386.
    0x08048134->0x08048147 at 0x00000134: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x08048148->0x08048168 at 0x00000148: .note.ABI-tag ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x08048168->0x0804819c at 0x00000168: .hash ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x0804819c->0x0804821c at 0x0000019c: .dynsym ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x0804821c->0x08048277 at 0x0000021c: .dynstr ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x08048278->0x08048288 at 0x00000278: .gnu.version ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x08048288->0x080482a8 at 0x00000288: .gnu.version_r ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x080482a8->0x080482b8 at 0x000002a8: .rel.dyn ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x080482b8->0x080482d8 at 0x000002b8: .rel.plt ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x080482d8->0x080482ef at 0x000002d8: .init ALLOC LOAD READONLY CODE HAS_CONTENTS
    0x080482f0->0x08048340 at 0x000002f0: .plt ALLOC LOAD READONLY CODE HAS_CONTENTS
    0x08048340->0x08048548 at 0x00000340: .text ALLOC LOAD READONLY CODE HAS_CONTENTS
    0x08048548->0x08048563 at 0x00000548: .fini ALLOC LOAD READONLY CODE HAS_CONTENTS
    0x08048580->0x0804868d at 0x00000580: .rodata ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x08048690->0x08048694 at 0x00000690: .eh_frame ALLOC LOAD READONLY DATA HAS_CONTENTS
    0x08049694->0x080496a0 at 0x00000694: .ctors ALLOC LOAD DATA HAS_CONTENTS     <----------- BURASI ILK GIRIS YERI
    0x080496a0->0x080496ac at 0x000006a0: .dtors ALLOC LOAD DATA HAS_CONTENTS     <----------- BURASI CIKIS YERI
    0x080496ac->0x080496b0 at 0x000006ac: .jcr ALLOC LOAD DATA HAS_CONTENTS
    0x080496b0->0x08049778 at 0x000006b0: .dynamic ALLOC LOAD DATA HAS_CONTENTS
    0x08049778->0x0804977c at 0x00000778: .got ALLOC LOAD DATA HAS_CONTENTS
    0x0804977c->0x08049798 at 0x0000077c: .got.plt ALLOC LOAD DATA HAS_CONTENTS
    0x08049798->0x080497a4 at 0x00000798: .data ALLOC LOAD DATA HAS_CONTENTS
    0x080497a4->0x080497ac at 0x000007a4: .bss ALLOC
    0x00000000->0x000001e3 at 0x000007a4: .comment READONLY HAS_CONTENTS
    0x00000000->0x00000078 at 0x00000988: .debug_aranges READONLY HAS_CONTENTS
    0x00000000->0x0000001b at 0x00000a00: .debug_pubnames READONLY HAS_CONTENTS
    0x00000000->0x00001bec at 0x00000a1b: .debug_info READONLY HAS_CONTENTS
    0x00000000->0x000001d8 at 0x00002607: .debug_abbrev READONLY HAS_CONTENTS
    0x00000000->0x0000034e at 0x000027df: .debug_line READONLY HAS_CONTENTS
    0x00000000->0x00000068 at 0x00002b30: .debug_frame READONLY HAS_CONTENTS
    0x00000000->0x00000025 at 0x00002b98: .debug_str READONLY HAS_CONTENTS
    0x00000000->0x000037b3 at 0x00002bbd: .debug_macinfo READONLY HAS_CONTENTS



Evet elf32 binarysinde .ctors yani global_constructor larimiz 0x08049694->0x080496a0  adresleri 
arasinda yer almakta. bizim fonksiyonumuz da burda yer almasi lazim. yani fonksiyondan kasitim
murderkey_morfin() fonksiyonu.

(gdb) info address murderkey_morfin 
Symbol "murderkey_morfin" is a function at address 0x804841d.
(gdb) 

Evet murderkey_morfin() fonksiyon adresimiz hafizamizda .text segmentinde 0x804841d adresinde yer almakta.
bakalim .ctors sectionunda bu adresimiz varmi

(gdb) x/10x 0x08049694 
0x8049694 <__CTOR_LIST__>:      0xffffffff      0x0804841d      0x00000000      0xffffffff
0x80496a4 <__DTOR_LIST__+4>:    0x08048449      0x00000000      0x00000000      0x00000001
0x80496b4 <_DYNAMIC+4>: 0x00000001      0x0000000c
(gdb) 

Evet 0x0804841d __CTOR_LIST icinde cok guzel. bu demek oluyorki program main() e girmeden bu fonksiyonumuz 
calisacak.

Programi gdb den calistiriyoruz.

(gdb) run
Starting program: /root/elf32/murderkey-overdoze 
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
Program matrixe girmeden cakilacak -> SIGSEGV

Program received signal SIGSEGV, Segmentation fault.
0x08048546 in __do_global_ctors_aux ()
(gdb) 

0x08048546 in __do_global_ctors_aux ()  <0-------- Evet tahmin ettiginiz gibi global_constructor de program patladi.

Simdi hafizaya bakalim bizim kopyaladigimiz AAAAAA lar ne durumda, program exploit edilebilirmi ?

(gdb) info registers 
eax            0xb7fdd538       -1208101576
ecx            0xb7fb71af       -1208258129
edx            0x804864c        134514252
ebx            0x804977c        134518652
esp            0xbffff808       0xbffff808
ebp            0x414141 0x414141
esi            0x0      0
edi            0xbffff894       -1073743724
eip            0x8048546        0x8048546
eflags         0x10246  66118
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
(gdb) 

Evet tahmin ettigim gibi ebp overwrite olmus durumda . 0x414141 yani bizim AAA larimiz ile. burda aklimiza hemen 
off-by-one methodu ile exploit etmek geliyor ama bu taktik burda yemez, neden diye sorarsaniz program daha main()
fonksiyonuna girmedi,yani hic bir frame icinde deiliz, isterseniz bunu gorebiliriz.

(gdb) frame
#0  0x08048546 in __do_global_ctors_aux ()
(gdb) 

evet gordugunuz gibi.

(gdb) info frame 
Cannot access memory at address 0x414145
(gdb) 

burda yapilacak hic birsey yok. fakat strcpy() deki AAA lari biraz arttirirsaniz EIP overwrite olacaginiz gorursunuz.
ben bilerek onu yapmadim eger oyle olsaydi return into libc teknigini kullanabilirdik.

Simdi burda onemli olan sey global constructor ve destructor fonksiyonlarinin arguman alamamasi. zaten orda static void
olarak tanimlanmis durumda.

Burda yapmamiz gereken sey yine destructor ve constructor icine baska bi fonksiyon inject edip bunu calistirabilmek. 4 byte
ile yapilabilecek birsey bu.

cheers