Posted on July 2nd, 2015
computerpatching

30 Haziran tarihinde yayınlanan zafiyetlere bakarken ,  IBM ‘ in yaygın Storage yazılımı ile ilgili zafiyetler dikkatimizi çekti.  Zafiyetle ilgili yayınlanan güvenlik bildirisinden yola çıkarak , bu zafiyeti tersine mühendislik ile bulmayı ve tetiklemeyi hedefledik.  Bu yazıyı hazırlarken  piyasada henüz yayınlanmış bir PoC ve exploit kodu yoktu. Öncelikle zafiyetle ilgi güvenlik bildirisini inceleyelim;

vuln-details

Güvenlik bildirisi bize kısıtlı olmakla beraber iki adet ipucu veriyor. Birinci ipucu; Zafiyet  11460 portunu dinleyen IBM FastBack Server yazılımında bir hafıza taşması hatası .. İkinci ipucu ise zafiyetin FXCLI_OraBr_Exec_Command fonksiyonunda olduğu.

Yazılımın trial versiyonunu bulup , yüklüyoruz  ve ilk etapta 11460 portunu dinleyen processi tespit etmek için TcpView ile bir göz atıyoruz. İnceleyeceğimiz process; FastBackServer.exe

tcpview

 

Bu bir server-side zafiyet olduğuna göre tetiklenmesi illaki paket ile yapılacak. O halde önce bu işlem için bir script hazırlayalım;

ilkpaket

Debuggerımızı processe attach edip,  WSARecv fonksiyonuna bir breakpoint koyuyoruz ve scriptimizi çalıştırarak ilk paketi gönderiyoruz.

bp WS2_32!WSARecv" .printf \"[+] WSArecv(%x, %x, %x)\n\", poi(@esp+0x4), poi(poi(@esp+0x8)+4), poi(poi(@esp+0x8)); .echo"

bp-wsarecv

 

İlk etapta bu breakpoint esnasında anladığımız , WSARecv ile uygulamanın 0x4400 byte’a kadar paket kabul ettiği… O halde scriptimizi bu doğrultuda düzenleyip, 0x4400 bytelık paket gönderelim.

17408lik-data

Artık paketimizi adım adım debuggerda takip edebiliriz. Bunun için WSARecv ‘ in buf parametresine yani paketime bir breakpoint access koyalım;

bp-access-ondata

 

Uygulama bir memcpy fonksiyonunda duruyor.  Paketimizin ilk bytelarına burada bir read işlemi olduğu için breakpoint access çalışıyor ve duruyor.  Memcpy fonksiyonun bitmesini sağlıyoruz. Memcpyden bittikten sonra ,  uygulama   005816EA adresine dönüş yapıyor. Burası  public FX_AGENT_CopyReceiveBuff   fonksiyonu içinde bir alan oluyor.

ida-graphs

Bu fonksiyondan tahminen anladığımız, agent’dan gelen  veriyi hafıza alanına kopyalamaya yarıyor.  Fonksiyonun ilişkisel bağlarına baktığımızda ,  herşey daha da oturuyor. Biz zaten Agent gibi davranıyoruz, server ilk EstablishConnection ile bağlantımızı kabul ediyor, daha sonra Cylic ve GetData fonksiyonları ile bizi en son CopyReceiveBuff a getiriyor.  Tekrardan adım adım paketimizi, debugger ve ida’da takip etmeye devam edelim. loc_581752  isimli bir fonksiyona geliyor, bu fonksiyon paketimizi çeşitli bitwise işleminden geçiriyor. Bu yüzden IDA’da fonksiyonu bitwise_fonk olarak rename ettik.

bitwise

 

 Fonksiyonun en sonunda gönderdiğimiz paketimizin ilk 4byteını,  sıfıra eşit olup olmadığına bakıyor. Paketimizin ilk dört byteını bu şekilde toplamda 3 adet karşılaştırmaya sokuyor.

compare

Paketimiz mevcut haliyle , 41424344h >  100000h olduğundan ,  üçüncü karşılaştırmada  kırmızı okun gösterdiği adrese gidiyor.. Debuggerda takip ettiğimizde FX_AGENT_GetData fonksiyonu içerisindeki 005815d3 adresine geri dönüyoruz ve daha sonra da şu fonksiyonun içine düşüyoruz;

packeterror

Anlaşıldığı üzere paketimiz, uygulamanın istediği yapıya uygun olmadığı için clientın discconnect olduğu, hata loglarının yazıldığı fonksiyonu gittik. Bizim gelmek istediğimiz yer malesef burası değil. O halde 3. karşılaştırmada , paket  <=  100000h eşitliğini sağlayıp , bu sefer nereye gideceğimize bakalım. Bunun için scriptdeki paketimin ilk 4 byteını şu şekilde değiştiriyoruz; 0x30000

3000h

Tekrardan 3. karşılaştırmanın olduğu 0x005817D0 adresine breakpoint koyup ,  uygulamayı debugger içinde çalıştırıp , yeni paketimizi tekrardan gönderelim;

3rdcmp

 Bitwise operasoyonu sonrasında ECX+4438’de bulunan paketimizin ilk 4byteı,  0x300 oluyor. Bu sefer diğer koşula zıplayabiliyoruz. Tekrardan paketimizi debugger ve IDA ile paralel bir şekilde takip etmeye devam ediyoruz. Yine bir memcpy fonksiyonuna giriyoruz, memcpy parametlerine baktığımızda  src parametresinde paketimizin kalan datasının (XXXXX…) bir memory alanına kopyalandığını anlıyoruz.

memcpy

Fonksiyonların içinde kaybolmadan devam ediyoruz amacımız paketimizi takip etmek ve şüpheli gördüğümüz yerde durmak. Bu fonksiyonları da geçtikten sonra tekrardan daha önce 3. karşılaştırmadan sonra geri döndüğümüz FX_AGENT_GetData fonksiyonu içerisindeki 005815d3 adresine geri dönüyoruz.

getdata

 Ancak bu sefer paketimizi takip ettiğimizde  Java Client Disconneceted hatasının verdiği fonksiyona değil,  loc_581614 fonksiyonuna zıplıyoruz.  3. karşılaştırma için paketimizi değiştirmemiz bizi hataya düşmekten kurtardı.  Paketimizi , debuggerda trace ederek takip etmeye devam ettiğimizde , FX_AGENT_GetData fonksiyonunu da tamamlayıp,  FX_Agent_Cyclic fonksiyonu içinde 00581320 adresine geri dönüyoruz. Bir kaç instruction devam ettikten sonra , şöyle bir fonksiyonun içine düşüyoruz ve yine bizim paketimizin ilk 4byteı , karşılaştırılmaya sokuluyor;

58132c

İlk 4byte , sıfıra eşit olmadığı için , loc_581347 fonksiyonuna zıplıyoruz;

call-recvcmnd

Burada eminim , FXCLI_C_ReceiveCommand fonksiyonunu gören bug hunter iştahlanmaya başlar. Bu fonksiyona call edilirken , PUSH ile gönderilen ECX (int) ve EDX (src) argümanlarını da bizim paketlerimiz oluşturuyor. src (edx) argümanında gönderdiğimiz “X” datası , int (ecx) ise paketimizin ilk 4byteının bitwise edildikten sonraki hali 0x300 bulunuyor.   Yani paketimizi bu yeni fonksiyon içerisinde takip edeceğiz.  Artık FXCLI_C_ReceiveCommand isimli yeni fonksiyonun içine düşebiliriz;

recvcommand

FXCLI_C_ReceiveCommand  fonksiyonuna şöyle bir tepeden baktığımızda, kırmızı çarpı ile işaretlediğim en alt sağ fonksiyon içindeki bir call dikkatimizi çekiyor;

FXCLI_OraBR_Exec_Command

 Güvenlik bildirisinde de zafiyetin bu fonksiyon içinde olduğu söyleniyordu. Umarım paketimizi çok fazla değiştirme gereği duymadan bu fonksiyona sıçrayabiliriz diye umarak ,  adım adım takip işlemine debuggerdan devam ediyoruz. Sırasıyla paketimiz loc_56A12E, loc_56A158, loc_56A192,  loc_56A1B9 fonksiyonlarından geçtikten sonra en son FXCLI_OraBR_Exec_Command fonksiyonuna çağrımın olduğu loc_56A1F0 fonksiyonuna ulaşıyor.

IDA’dan FXCLI_OraBR_Exec_Command fonksiyonuna gittiğimizde gerçekten devasal bir fonksiyon ile karşılaşıyoruz. Node sayısı 1000in üzerinde olduğu için IDA Graph ayalarınında maximum node sayısını arttırmanız gerekiyor graph view için;

bigfunc

Bu fonksiyon içerisinde ilerlememizi devam ettiriyoruz. GetConnectedIPport, GetJavaClientInfo  gibi yaklaşık 12-13 fonksiyondan geçiyoruz. Yazının yeterince uzun olmaması için bu kısımları detaylıca irdelemiyoruz. Uzun bir süreçle bu fonksiyonları atlattıktan sonra , yine bir paketimizin belli bir byteının karşılaştırıldığı aşağıdaki fonksiyona düşüyoruz;

xx-ilkcmp

 Buradaki cmp instructionı incelediğimizde yine bizim paketimizdeki belirli bir byte’ı  0x61A8 ile karşılaştırdığını görüyoruz;

xx-ilkcmp2

Burada yapmamız gereken , gönderiğimiz kaçıncı X byetlarını , 61A8h ile karşılaştırıyor bunu tespit etmek. Daha sonrasında o byteları , 61A8h’den küçük bir byte ile değiştirmek. Aksi takdirde uygulama akışı  yine bir istenmeyen (messaga size error hatasına) noktaya gidiyor.  Scriptimi aşağıdaki gibi düzenleyip,  paketimde gerekli yere 0x61A7 yazarak , karşılaştırmadan geçmeyi sağlıyoru<.

passcmp1

Bu şekilde karşılaştırmayı geçtikten sonra, debuggerda ilerlerken ikinci bir comparison ile karşılaşıyoruz. Bu sefer paketimdeki “EFGH” bytelarını yine 0x61A8 ile karşılaştırıyor;

kinci

xx-2ndcmp

Paketimiz bu şekilde 3 adet karşılaştırmadan geçiyor. Her karşılaştırmada gerekli yerleri değiştirerek , atlatıyoruz ve sonrasında bir memcpy fonksiyonuna geliyoruz.

koprudenoncememcpy

Bu memcpy fonksiyonunu aynı zamanda debuggerda takip ettiğimizde , Size kısmında bizim paketimizdeki 0x61A7 değerini görüyoruz. Yani memcpy’nin size değeri paket içerisinde belirleniyor. Bir overflowu önlemek için de öncesinde paket içerisindeki bu değerin 61A8’den küçük olup olmadığı kontrol ediliyor.  Bu fonksiyonu geçip adım adım paketimizi takip etmeye devam ediyoruz. Bu sefer ikinci bir memcpy fonksiyonu karşımıza çıkıyor;

memcpy222

Dinamik olarak debuggerda yine bu memcpy’nin argümanlarına baktığımızdda “size” parametresinde yine paketimizin içindeki 0x61A7 değerini görüyoruz;

memcpysize

Bu fonksiyonu geçtikten sonra  yine bir memcpy fonksiyonuna geliyoruz;

ucuncumemcpy

 

 

İşte zafiyetimizi burada keşfediyoruz. Malesef üçüncü memcpy fonksiyonun size argümanı gönderdiğimiz paketin geri kalan kısmından belirleniyor (XXXX=0x58585858)..

memcpy-boom

Size parametresi 0x58585858 gibi destionation için ayrılan alandan bir hayli büyük olunca, memcpy fonksiyonu bir  hafıza bozulmasına sebep oluyor;

access-violation

 

PoC kodunun son haline buradan ulaşabilirsiniz: http://www.signalsec.com/publications/ibm-tivolifastback-server-poc.txt

Celil UNUVER

SIGNALSEC Ltd.