Linux Sistemlerde Zararlı Yazılım Analizi – İleri Seviye Statik Analiz

İleri seviye statik analizde zararlı çalıştırılmadan, temel seviye statik ve dinamik analizde toplanan bilgiler ışığında önemli olabilecek fonksiyonlar disassembler ile incelenerek işlevi analiz edilir. Zararlının kullandığı dil ve mimari el verirse decompile ederek incelemede daha hızlı sonuçlar alınabilir.

Temel statik ve temel dinamik analiz yazılarında da örnek olarak kullanılan Bill Gates (dosya adı elknot) zararlısı IDA ile açılır. Varsayılan olarak solda olan “Function name” penceresinden fonksiyon isimlerine genel bir göz gezdirildiğinde zararlının DDoS amaçlı kullandığı fonksiyonlar/metodlar göze çarpmaktadır.

CPacketAttack::CPacketAttack(bool,CSubTask &,CConfig &)     .text 080831FE 0000015B 0000002C 00000010 R . . . B . .
CAttackCompress::CAttackCompress(bool,CSubTask &,CConfig &) .text 0808335A 00000073 0000001C 00000010 R . . . B . .
CAttackSyn::CAttackSyn(bool,CSubTask &,CConfig &)           .text 080833CE 0000002F 0000000C 00000010 R . . . B . .
CAttackUdp::CAttackUdp(bool,CSubTask &,CConfig &)           .text 080833FE 0000002F 0000000C 00000010 R . . . B . .
CAttackDns::CAttackDns(bool,CSubTask &,CConfig &)           .text 0808342E 0000008D 0000001C 00000010 R . . . B . .
CAttackAmp::CAttackAmp(bool,CSubTask &,CConfig &)           .text 080834BC 00000056 0000000C 00000010 R . . . B . .
CAttackPrx::CAttackPrx(bool,CSubTask &,CConfig &)           .text 08083512 0000008D 0000001C 00000010 R . . . B . .
CAttackIcmp::CAttackIcmp(bool,CSubTask &,CConfig &)         .text 080835A0 0000002F 0000000C 00000010 R . . . B . .
CTcpAttack::CTcpAttack(CSubTask &)                          .text 080835D0 000001A1 0000001C 00000008 R . . . B . .

Bu fonksiyonların bir çoğunun az çok ne işe yaradığı adlarına bakılarak da anlaşılabilir. İleri seviye statik analizin etkili kullanım alanının, temel statik ve dinamik analizdeki ipuçlarının detaylarını araştırmak olduğu söylenebilir. Örneğin ilginç gözüken bir stringin geçtiği fonksiyonun veya strace çıktısında dikkat çeken bir fonksiyonun detaylı analizi için bir disassembler kullanmak mantıklı olabilir.

Örnek olarak zararlının başlangıç mekanizması analiz edilmiştir. Bunun için temel dinamik analizdeki strace çıktısında karşılaştığımız fork fonksiyonu (libc içerisindeki) başlangıç ipucu kabul edilmiştir. IDA Functions penceresinden fork bulunup çift tıklanarak fonksiyona gelinir ve başlangıcına tıklanıp “x” tuşuna basılarak kod içinde çağrıldığı yerler listelenir.

Direction Type Address                                      Text       
——— —- ——-                                      —-       
Up        p    CSysTool::RunLinuxShell(char const*)+9       call    fork
Up        p    CThreadKernelAtkExcutor::ProcessMain(void)+6 call    fork
Up        p    connectback(char const*,ushort)+EB           call    fork
Up        p    CThreadShell::ProcessMain(void)+1D           call    fork
Down      p    _IO_proc_open:loc_80ACB60                    call    fork
Down      p    daemon+7                                     call    fork
Down      p    __unix_grantpt:loc_80BC865                   call    fork

Listede kalın font ile yazılı olan metodların hepsi incelemeye değer gibi dursa da başlangıç işleyişine odaklanmak adına ismi “ProcessMain” olan iki metottan analize başlanmıştır.  CThreadShell::ProcessMain metodu, IP2String isimli başka bir metodu çağırdıktan sonra fork ile yeni bir süreç oluşturup burada da herşey yolunda giderse connectback fonksiyonunu çağırmaktadır.

.text:0808840F                 push    eax
.text:08088410                 push    edx
.text:08088411                 call    _ZN8CUtility9IP2StringEj ; CUtility::IP2String(uint)
.text:08088416                 add     esp, 0Ch
.text:08088419                 call    fork
.text:0808841E                 mov     [ebp+pid], eax
.text:08088421                 cmp     [ebp+pid], 0
.text:08088425                 jns     short loc_8088441
………
2                 call    _ZNKSs5c_strEv  ; std::string::c_str(void)
.text:080884B7                 add     esp, 10h
.text:080884BA                 sub     esp, 8
.text:080884BD                 push    [ebp+var_18]
.text:080884C0                 push    eax
.text:080884C1                 call    _Z11connectbackPKct ; connectback(char const*,ushort)
.text:080884C6                 add     esp, 10h
.text:080884C9                 jmp     short loc_80884DD

Metod sonunda her halükarda CManager sınıfının recycleShell metodunu çağırmaktadır. connectback fonksiyonun da temel olarak verilen IP, port değerine bağlanıp socketten gelen  veriyi /bin/sh’e, bunun çıktısını da geri socket’e yönlendirdiği söylenebilir. Kısa ismiyle bir “reverse shell” işlevi görmektedir ancak analiz hedefini dağıtmamak adına  detaylı analizine yer verilmemiştir.

İlk iki metodun analizinde aranan bölüm bulunamadığı için üçüncü sırada CSysTool::RunLinuxShell metodu ile analize devam edilmiştir. Metod fork işleminden sonra CSysTool::CloseResources metodunu çağırarak açtığı tüm soketleri ve dosyaları kapatıyor ve fonksiyona parametre olarak gelen değeri sistemde komut olarak çalıştırıyor.

.text:0807630F                 call    _ZN8CSysTool14CloseResourcesEv ; CSysTool::CloseResources(void)
.text:08076314                 lea     ecx, [ebp+var_108]
.text:0807631A                 mov     edx, offset _ZZN8CSysTool13RunLinuxShellEPKcE6C_1223 ; CSysTool::RunLinuxShell(char const*)::C.1223
.text:0807631F                 mov     eax, 100h
.text:08076324                 sub     esp, 4
.text:08076327                 push    eax
.text:08076328                 push    edx
.text:08076329                 push    ecx
.text:0807632A                 call    memcpy
.text:0807632F                 add     esp, 10h
.text:08076332                 sub     esp, 8
.text:08076335                 push    [ebp+arg_0]
.text:08076338                 lea     eax, [ebp+var_108]
.text:0807633E                 push    eax
.text:0807633F                 call    strcpy

.text:08076344                 add     esp, 10h
.text:08076347                 sub     esp, 0Ch
.text:0807634A                 lea     eax, [ebp+var_108]
.text:08076350                 push    eax
.text:08076351                 call    system
.text:08076356                 add     esp, 10h

Metodun analizinden de açıkça görüldüğü üzere bu metodu çağıran metodların analizi bizi başlangıç işlevini çözmeye daha da yaklaştıracaktır. Çapraz referanslara bakıldığında ismi başlangıç metoduna en çok benzeyen CSysTool::ReleaseAndStartGates’in analizinden devam edilmiştir.

Direction Type Address                                        Text                                                                        
——— —- ——-                                        —-                                                                        
Up        p    CManager::UpdateProcess(CUpdateGates &)+2BC    call    _ZN8CSysTool13RunLinuxShellEPKc; CSysTool::RunLinuxShell(char const*)
Down      p    CSysTool::DoSystemCmd(char const*)+C           call    _ZN8CSysTool13RunLinuxShellEPKc; CSysTool::RunLinuxShell(char const*)
Down      p    CSysTool::ReleaseAndStartGates(char const*)+2F call    _ZN8CSysTool13RunLinuxShellEPKc; CSysTool::RunLinuxShell(char const*)
Down      p    CSysTool::DoUpdate(int,char **)+4FA            call    _ZN8CSysTool13RunLinuxShellEPKc; CSysTool::RunLinuxShell(char const*)

Metod analiz edildiğinde sadece CSysTool::ReleaseGates ve CSysTool::RunLinuxShell metodlarını aldığı parametreyi kullanarak çağırdığı görülüyor. Yine çapraz referanslardan MainBeikong fonksiyonunun analizi ile devam edilmiştir.

Direction Type Address                               Text                                                                                      
——— —- ——-                               —-                                                                                      
Up        p    MainBeikong(void)+1C7                 call    _ZN8CSysTool20ReleaseAndStartGatesEPKc; CSysTool::ReleaseAndStartGates(char const*)
Up        p    MainBeikong(void)+250                 call    _ZN8CSysTool20ReleaseAndStartGatesEPKc; CSysTool::ReleaseAndStartGates(char const*)
Down      p    CThreadMonGates::ProcessMain(void)+51 call    _ZN8CSysTool20ReleaseAndStartGatesEPKc; CSysTool::ReleaseAndStartGates(char const*)

MainBeikong fonksiyonunun analizi ile nihayet istenilen bölüme ulaşılabilmiştir. Burada çapraz referansı oluşturan bölüm basitçe arka kapı (backdoor) dosyasının sistemdeki yolu alınıp CSysTool::ReleaseAndStartGates fonksiyonuna parametre olarak veriliyor. (Dokümanda yukarı çıkıldıkça bu fonksiyonun bu parametre ile neler yaptığı görülebilir.)

.text:0806259D                 push    edx
.text:0806259E                 call    _ZN8CSysTool15GetBackDoorFileEPKc ; CSysTool::GetBackDoorFile(char const*)
.text:080625A3                 add     esp, 0Ch
.text:080625A6                 sub     esp, 0Ch
.text:080625A9                 lea     eax, [ebp+var_10]
.text:080625AC                 push    eax
.text:080625AD                 call    _ZNKSs5c_strEv  ; std::string::c_str(void)

.text:080625B2                 add     esp, 10h
.text:080625B5                 sub     esp, 0Ch
.text:080625B8                 push    eax
.text:080625B9                 call    _ZN8CSysTool20ReleaseAndStartGatesEPKc ; CSysTool::ReleaseAndStartGates(char const*)

.text:080625BE                 add     esp, 10h
.text:080625C1                 jmp     short loc_80625DD

Fonksiyonun geneli analiz edildiğinde de çalıştırdığı süreçleri senkronize etmek amaçlı oluşturduğu kilit dosyalarının varsa eskilerini silip yenilerini oluşturuyor, kendisini sistem başlangıcına yerleştirerek kalıcılık sağlıyor. Bunu da nasıl yaptığı CUtility::SetAutoStart metodu analiz edilerek görülebilir.  Kabaca /etc/init.d/ altında kendisini çalıştıracak basit bir rc dosyası oluşturduğu söylenebilir.

.text:080904D1                 lea     eax, [ebp+var_11]
.text:080904D4                 push    eax
.text:080904D5                 push    offset aEtcInit_d ; “/etc/init.d/”
.text:080904DA                 lea     eax, [ebp+var_18]
.text:080904DD                 push    eax
.text:080904DE                 call    _ZNSsC1EPKcRKSaIcE ; std::string::string(char const*,std::allocator<char> const&)

…..

.text:080905D4                 push    eax
.text:080905D5                 push    offset aBinBashS ; “#!/bin/bashn%sn”
.text:080905DA                 lea     eax, [ebp+addr]
.text:080905E0                 push    eax
.text:080905E1                 call    sprintf

.text:080905E6                 add     esp, 10h
……
.text:0809067D                 push    [ebp+arg_0]
.text:08090680                 push    [ebp+arg_4]
.text:08090683                 push    eax
.text:08090684                 push    offset aEtcRcD_dSDS ; “/etc/rc%d.d/S%d%s”
.text:08090689                 lea     eax, [ebp+pathname]
.text:0809068F                 push    eax
.text:08090690                 call    sprintf

.text:08090695                 add     esp, 20h
.text:08090698                 sub     esp, 8
.text:0809069B                 push    0               ; mode
.text:0809069D                 lea     eax, [ebp+pathname]
.text:080906A3                 push    eax             ; pathname
.text:080906A4                 call    access

.text:080906A9                 add     esp, 10h
.text:080906AC                 test    eax, eax
.text:080906AE                 setz    al
.text:080906B1                 test    al, al
.text:080906B3                 jnz     short loc_80906E5
.text:080906B5                 lea     eax, [ebp+pathname]
.text:080906BB                 push    eax
.text:080906BC                 push    [ebp+arg_0]
.text:080906BF                 push    offset aLnSEtcInit_dSS ; “ln -s /etc/init.d/%s %s”
.text:080906C4                 lea     eax, [ebp+var_220]
.text:080906CA                 push    eax
.text:080906CB                 call    sprintf

.text:080906D0                 add     esp, 10h
.text:080906D3                 sub     esp, 0Ch
.text:080906D6                 lea     eax, [ebp+var_220]
.text:080906DC                 push    eax
.text:080906DD                 call    system

Bonus olarak en son çapraz referanslarda görülen CThreadMonGates::ProcessMain metodunun analizi de faydalı bilgiler verecektir.

İleri seviye statik analizde ilgili kod bölümünün ürettiği sonuçtan çok ne iş yaptığına odaklanılır. Buradan edinilen bilgiler ışığında ileri seviye dinamik analize geçilerek zararlının istenilen kod bölümlerinde çalışma anındaki davranışı gözlenir. Bu sayede bellek ve işlemci registerları üzerindeki gerçek değerler kolayca elde edilebilir. Yazı boyunca program, bilinen bir noktasından geriye doğru analiz edilerek istenilen bölüme ulaşılmıştır. Bu açıdan işleme neden tersine mühendislik dendiğini de açıklayan bir örnek olduğunu düşünüyorum.