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
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.
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.
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.
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.
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.
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ść.
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.
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ć.
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.
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).
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);
Po zasymulowaniu w ten sposób funkcji D3fx5an0kfxq3ww8() otrzymamy sporą porcję JavaScriptu oraz VBScriptu do (już nie tak łatwej) dalszej analizy…
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… :)
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.
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.
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
Świetne! Czekamy na więcej!