Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book

Deobfuskacja JavaScript – część druga. JSDetox na przykładzie realnego malware

16 czerwca 2015, 14:30 | Teksty | 1 komentarz
W kolejnym artykule z serii o deobfuskacji JavaScriptu zajmiemy się analizą nieco bardziej zaawansowanego oraz zobfuskowanego złośliwego skryptu JS.

Tym razem będzie to Angler Explot Kit, pobrany z pierwszego pcap’u dostępnego na malware-traffic-analysis.net.

Narzędzia oraz techniki zostały omówione w pierwszym artykule

UWAGA! Złośliwy kod powinien być analizowany w wirtualnym, izolowanym środowisku.

Analiza

Plik można zapisać, używając Wiresharka oraz opcji File -> Export Objects -> HTTP, interesujący nas kod znajduje się w 110 pakiecie transmisji. Na pierwszy rzut oka plik nie wygląda podejrzanie, znajdują się tam rozmaite tagi HTML oraz fragmenty tekstu w języku angielskim.

plik zawierający złośliwe skrypty na pierwszy rzut oka sprawia wrażenie normalnej strony internetowej

1. Plik zawierający złośliwe skrypty na pierwszy rzut oka sprawia wrażenie normalnej strony internetowej.

JSDetox udostępnia opcję automatycznego wycinania skryptów z dokumentu HTML. W tym celu należy otworzyć zakładkę “HTML Document”, zaimportować plik lub wkleić jego zawartość, a następnie kliknąć “Extract Scripts”. Dzięki temu zabiegowi wszystkie skrypty, wraz ze stosownym komentarzem, znajdą się w oknie analizy używanym do dalszej obróbki i uruchamiania kodu.

Po “wyciągnięciu” skryptów z pliku HTML możemy użyć sekwencji przycisków “Analyze” i “Send up”, aby uporządkować nieco kod. Wynik zapiszmy jako wejściowe dane. Jeśli spróbujemy uruchomić kod w środowisku JSDetox, otrzymamy dwa komunikaty o użyciu funkcji eval() oraz jeden błąd, mówiący o niezdefiniowanej zmiennej BPMPIxu. Dzięki temu wiemy, że symulacja kodu nie wykonała się do końca.

2. Za pierwszym razem cały kod nie został zasymulowany w JSDetox.

2. Za pierwszym razem cały kod nie został zasymulowany w JSDetox.

Poszukajmy zatem ciągu BPMPIxu wewnątrz kodu, aby określić, za co jest odpowiedzialny. Ciąg ten występuje w dwóch miejscach, lecz JSDetox skarży się na jego wystąpienie w 133 linii. W tym miejscu wychodzi pierwsza (z licznych, niestety) niedoskonałości emulacji przy użyciu automatycznych narzędzi. To, co jest zrozumiałe dla przeglądarki, niekoniecznie będzie łatwe do zinterpretowania przez JSDetox. W przypadku raportowanego błędu wystarczy dodać słowo kluczowe “var” przed nazwę zmiennej BPMPIxu i cały kod zaczyna wykonywać się poprawnie.

3. Poprawne wykonanie pierwszej fazy - pięciokrotne wywołanie funkcji eval().

3. Poprawne wykonanie pierwszej fazy – pięciokrotne wywołanie funkcji eval().

Udało się dostosować kod w taki sposób, aby wykonał się bez błędów. JSDetox sygnalizuje, że pięć razy użyta została metoda window.eval(). Do każdego z komunikatów można obejrzeć kod, który został przekazany do wspomnianej metody.

Skopiowanie tego kodu i doklejenie go do końca danych wejściowych pozwoli JSDetox zasymulować wykonanie tych właśnie bloków, które nastąpią zaraz po pierwszej części kodu (swoją drogą można by tego oczekiwać od funkcji “Execute eval() statements”, ale niestety nie działa ona w ten sposób).

Kolejne uruchomienie, po dołączeniu pięciu nowych bloków kodu zatrzymuje się na błędzie związanym z obiektem typu Image. Obiekt ten jest użyty w kodzie dwa razy – za każdym razem w lokalnej funkcji Check(), która zawsze zwraca wartość 0 po załadowaniu danego zasobu “s” w postaci obrazka. Jeśli funkcja przy poprawnym wykonaniu powinna zwracać wartość 0, to można pozbyć się części kodu, który powoduje problemy.

Wykomentujmy zatem część odpowiedzialną za ładowanie obrazka, ponieważ JSDetox ma problem z tworzeniem obiektu typu Image. Funkcja w postaci Check(s){ return 0;} powinna skutecznie spełnić swoje zadanie.

4. Funkcja Check(s) powinna zwracać wartość 0, jeśli zostanie wykonana poprawnie.

4. Funkcja Check(s) powinna zwracać wartość 0, jeśli zostanie wykonana poprawnie.

Po wyeliminowaniu kolejnej przeszkody możemy ponownie zasymulować uruchomienie kodu. Tym razem zatrzymamy się w tym miejscu, w którym JavaScript próbuje stworzyć obiekt ActiveXObject. Jak widać wsparcie podstawowych typów obiektów nie jest mocną stroną JSDetox. Obiekt ActiveX ładuje element Kaspersky.IeVirtualKeyboardPlugin, co zapewne służy sprawdzeniu, czy na komputerze znajduje się oprogramowanie antywirusowe. Jeśli ładowanie kontrolki ActiveX się nie powiedzie (co dla złośliwego skryptu będzie równoznacznie z brakiem wtyczki programu Kaspersky), w bloku catch(e){ } do tmp przypisywana jest wartość false. Możemy zatem zakomentować kłopotliwy dla JSDetox fragment kodu i ręcznie przypisać wartość “na sztywno” false do tmp. Drugie wystąpienie kontrolki ActiveX znajduje się w funkcji Ufe3S(txt), dla której również można usunąć całą jej zawartość, ustawiając odpowiednią zwracaną wartość.

5. Ominięcie sprawdzania kontrolki ActiveX poprzez usunięcie kodu i podstawienie wartości zmiennej na sztywno.

5. Ominięcie sprawdzania kontrolki ActiveX poprzez usunięcie kodu i podstawienie wartości zmiennej na sztywno.

Następne uruchomienie zatrzymuje nas na 269 linii kodu, czyli już bardzo blisko końca. JSDetox nie może odnaleźć elementu YOl94cYMYSraF. Jeśli jednak poszukamy tego unikalnego ciągu w całym kodzie znajdziemy przypisanie:

window.YOl94cYMYSraF = '06060A09060F0…..bardzo_dlugi_ciag

kolejne wystąpienie tego ciągu to:

YOl94cYMYSraF = '%u' + YOl94cYMYSraF.match(/(....)/g)[...]

Niestety dla JSDetox YOl94cYMYSraF nie jest równe window.YOl94cYMYSraF. Dopisanie “window.” przed kłopotliwą zmienną powinno naprawić problem. Podobnej korekty trzeba będzie dokonać w kolejnych kilku liniach kodu.

6. Korekta odwołań do kilku zmiennych.

6. Korekta odwołań do kilku zmiennych.

Zbliżamy się do końca, a JSDetox alarmuje kolejny problem – niezdefiniowana wartość LOQPteA. I znowu, wartość ta jest zdefiniowana, ale wykorzystaniem notacji, która jest niezrozumiała dla silnika analizatora. Zmiana definicji funkcji z formatu:

window["LOQPteA"] = new Function('text', "var cryptKey

na:

LOQPteA = function(text) {var cryptKey

pomoże, chociaż autor skryptu, obfuskując kod, domieszał do tej funkcji element łańcucha znaków (zmienna i), które należałoby ręcznie poprawić.

7. Funkcja LOQPteA, odpowiedzialna za odszyfrowanie URLa z explotem, po zmianie definicji oraz uporządkowaniu kodu.

7. Funkcja LOQPteA, odpowiedzialna za odszyfrowanie URL-a z explotem, po zmianie definicji oraz uporządkowaniu kodu.

Ostatnie uruchomienie to pełen sukces – JSDetox emuluje kod bez błędów, a całość kończy się informacją o uruchomieniu funkcji document.write. Po kliknięciu showCode ukaże się nam prawdziwa treść, która powoduje uruchomienie exploita.

8. Osadzenie obiektu Flasha, który spowoduje wykonanie się exploita.

8. Osadzenie obiektu Flasha, który spowoduje wykonanie się exploita.

 

Co się właściwie stało?

Dzięki zaimportowaniu całego pliku HTML JSDetox był w stanie zasymulować funkcję getElementById() oraz odnieść się do ukrytych elementów <p>, które w oryginalnym pliku html przechowywały zakodowany JavaScript. W pliku html znajduje się pięć elementów z ukrytym kodem, z których każdy posiada podobną nazwę:

<p class="text" id = "kWrE...

Pięć wywołań document.eval(), wykrytych przez JSDetox, związanych jest z uruchamianiem tego właśnie kodu. Pierwsza faza służyła wyłącznie do uzyskania docelowego kodu i poza obfuskacją nie wprowadzała żadnej logiki do działania eksploita.

Druga faza ataku jest ciekawsza, ponieważ angażuje inne elementy sprawdzające system użytkownika. Jeden z nich to sprawdzanie, czy eksploit nie jest wykonywany na wirtualnej maszynie oraz czy atakowany system nie posiada zainstalowanych programów antywirusowych. Angler dokonuje tego, sprawdzając obecność wybranych plików .dll oraz .sys, ładując je jako obiekt Image() lub dokument XML. Już na początku drugiej fazy widać tagi, które służą do osadzania elementu Flash, ale faktyczne wartości adresów URL poznamy dopiero po uruchomieniu funkcji deszyfrującej LOQPteA(text).

sprawdzanie obecności plików sys jako metoda sprawdzania czy exploit jest wykonywany w środowisku wirtualnym czy realnym.

9. Sprawdzanie obecności plików sys jako metoda sprawdzania, czy exploit jest wykonywany w środowisku wirtualnym czy realnym.

Co jeszcze kryje Angler EK?

Obiekt Flash, który ukazał się w ostatnim kroku analizy, nie jest jedynym elementem, który może zaserwować nam złośliwy skrypt. Angler jest uważany za jeden z najbardziej zaawansowanych exploit kitów używanych w Internecie, a uruchomienie exploita dla Flasha to tylko jedna z jego funkcji, która jest najprostsza do wykrycia. Co jeszcze potrafi Angler?

Przyjrzyjmy się funkcji D3fx5an0kfxq3ww8(), która wywoływana jest tuż przed odszyfrowaniem adresów URL exploita na Flasha. Funkcję tą można uruchomić w JSDetox niezależnie od reszty kodu, lecz żeby zadziałała poprawnie, należy zmienić parę deklaracji.

W oryginalnym kodzie fragment:

var MD19tsyovd = document.createElement('script');
MD19tsyovd.language = "javascript";
MD19tsyovd.text = B0GR336j1SN("66756E6374696F...")
document.getElementById("U3Rkokj45y").appendChild(MD19tsyovd);

jest niezrozumiały dla JSDetox i zostanie przez niego pominięty. Łatwo można zauważyć, że kod tworzy pewien element JavaScriptu, który zostaje następnie osadzony w elemencie o id U3Rkokj45y. Aby otrzymać wynikowy kod należy zastosować nieco prostszą składnię JS:

MD19tsyovd = B0GR336j1SN("66756E6374696F...")
document.write(MD19tsyovd);
10. Dostęp do kolejnej porcji JavaScriptu, której analiza została pominięta przez JSDetox.

10. Dostęp do kolejnej porcji JavaScriptu, której analiza została pominięta przez JSDetox.

Po zasymulowaniu w ten sposób funkcji D3fx5an0kfxq3ww8() otrzymamy sporą porcję JavaScriptu oraz VBScriptu do (już nie tak łatwej) dalszej analizy…

Aby znaleźć punkt wejścia do nowego JavaScriptu należy przeanalizować zależności między funkcjami (większe prawdopodobieństwo bycia pierwszą wywołaną funkcją ma ta, która nie jest wywoływana przez inne) oraz wyszukać odwołania do funkcji JS w kodzie VBScriptu.

Metodą prób i błędów można dojść do wniosku, że jako pierwsza powinna zostać wywołana funkcja LzqfEQ1peho034s(), a zaraz po niej V72dmg3ve7(). Pierwsza funkcja jest nieco kłopotliwa. Analizując ją, należy pamiętać o opcji JSDetox, która z jednej strony jest bardzo użyteczna przy porządkowaniu dużych bloków kodu, ale z drugiej, może prowadzić do utraty części skryptu. Otóż, jeśli nie zaznaczymy checkboxa “Do not trace variable values”, JSDetox usunie nam zmienne, które jego zdaniem są niepotrzebne, bo nie mają wcześniejszych deklaracji. W tym przypadku narzędzie nie znalazło powiązania między zmiennymi NwQ4242F oraz KzmD7i6r6bYq a resztą kodu, co nie pozwoliło skryptowi wykonać się poprawnie. Znalezienie powodu, dla którego dalszy kod nie będzie działał, może zająć trochę czasu… :)

Usuwanie niepotrzebnych (lub potrzebnych) deklaracji zmiennych przez JSDetox przy analizie kodu

11. Usuwanie niepotrzebnych (lub potrzebnych) deklaracji zmiennych przez JSDetox przy analizie kodu.

Druga z funkcji wejścia, V72dmg3ve7(), zaczyna się od przypisywania do zmiennej PVkf nazwy hosta, więc zapewne druga linia służyć będzie do obliczenia reszty adresu URL. Umieśćmy zatem metodę document.write(), aby poznać lokalizację kolejnego exploita serwowanego przez Anglera. Aby uruchomić ten fragment kodu, potrzebne będzie przekopiowanie deklaracji niektórych zmiennych oraz funkcji z wcześniejszych etapów deobfuskacji, o czym JSDetox będzie nam konsekwentnie przypominał. Ostatecznym rezultatem jest poznanie kolejnego URL-a prowadzącego do exploita, którym posługuje się analizowany JavaScript.

12. Odkrycie URLa do kolejnego exploita serwowanego przez Anglera. Domena zmieniona.

12. Odkrycie URL-a do kolejnego exploita serwowanego przez Anglera. Domena zmieniona.

W ten sposób udało nam się dojść do obu URL-i, które malware-traffic-analysis.net opisuje w sekcji CHAIN OF EVENTS -> 2015-03-23 ANGLER EK.

13. Screen z malware-traffic-analysis.net opisujący znalezione w exploit kicie URL-e.

13. Screen z malware-traffic-analysis.net opisujący znalezione w exploit kicie URL-e.

 

Podsumowanie

Zaawansowane exploitkity potrafią serwować wiele rodzajów exploitów i odkrycie jednego, dwóch czy trzech zakończeń wykonania kodu w postaci adresów URL wcale nie musi oznaczać rozwiązania całej zagadki. Ścieżki wykonania kodu mogą różnić się w zależności od user-agenta, wersji dostępnych wtyczek w przeglądarce oraz innych parametrów, których istnienie ogranicza jedynie wyobraźnia twórców złośliwego kodu.

Analizując kod przy pomocy automatycznych narzędzi, należy jednak pamiętać, że emulacja nie jest doskonała i bez dostatecznej czujności możemy stracić informacje o części kodu, który w normalnych warunkach wykonałby się poprawnie.

Emulując JavaScript, należy także pamiętać, że nie wszystkie zmienne i obiekty są dostępne dla narzędzia JSDetox i czasem dobry pomysł może z powodzeniem nadrobić niedoskonałości automatycznej analizy.

 

–Marcin Szymankiewicz

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. PL

    Świetne! Czekamy na więcej!

    Odpowiedz

Odpowiedz