Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Deobfuskacja JavaScript
Umiejętnie zastosowany JavaScript może jednak służyć do wykonania złośliwego kodu na komputerze nieświadomego użytkownika. W jaki sposób analizować takie zagrożenia?
Aby przekierować nieświadomego użytkownika na stronę, która będzie próbować wykonać złośliwy kod w przeglądarce, wystarczy prosta linijka:
<script> document.location="http://www.sekurak.pl"; </script>
listing 1.Już pierwszy rzut oka na powyższy kod mówi nam, za co jest on odpowiedzialny. Możemy utrudnić identyfikację kodu, na przykład rozbijając adres URL na kilka zmiennych:
<script> a="sek";f="urak";c=".pl";d="http";e="://www."; document.location=d+e+a+f+c; </script>
listing 2.Powyższy kod generuje dokładnie tę samą akcję, co fragment z pierwszego przykładu, chociaż wymaga odrobiny skupienia, aby zrozumieć sens jego działania. Aby jeszcze trochę utrudnić, spróbujmy zakodować łańcuchy znaków, zmienić nazwy zmiennych, a całość rozrzucić po losowych tablicach:
<script> var _0x834b=["\x73\x65\x6B","\x75\x72\x61\x6B","\x2E\x70\x6C","\x68\x74\x74\x70","\x3A\x2F\x2F\x77\x77\x77\x2E","\x6C\x6F\x63\x61\x74\x69\x6F\x6E"];a=_0x834b[0];b=_0x834b[1];c=_0x834b[2];d=_0x834b[3];e=_0x834b[4];document[_0x834b[5]]=d+e+a+b+c; </script>
listing 3.Nadal zbyt jasno widać, że próbujemy przekierować użytkownika? Zastosujmy wobec tego jeszcze parę zabiegów i otrzymamy bardzo zawikłany kod, który realizuje dokładnie to samo zadanie, co kod z pierwszego listingu:
<script> eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('g 6=["\\t\\u\\j","\\w\\n\\f\\j","\\i\\k\\h","\\q\\9\\9\\k","\\r\\l\\l\\8\\8\\8\\i","\\h\\m\\o\\f\\9\\s\\m\\v"];g 7=[6[0],6[1],6[2],6[3],6[4],6[5]];a=7[0];b=7[1];c=7[2];d=7[3];e=7[4];p[7[5]]=d+e+a+b+c;',33,33,'||||||_0x3725|_0x64df|x77|x74||||||x61|var|x6C|x2E|x6B|x70|x2F|x6F|x72|x63|document|x68|x3A|x69|x73|x65|x6E|x75'.split('|'),0,{})) </script>
listing 4.
Pozostałych Czytelników zapraszam do zapoznania się z narzędziami służącymi do analizy obfuskowanego kodu JavaScript.
Obfuskacja kodu
W jakim celu obfuskuje się kod?
Autorzy oprogramowania robią to najczęściej w celu ukrycia działania własnych programów, a hakerzy w celu ukrycia sposobu, w jaki exploit wykonał się na komputerze niczego nieświadomego użytkownika. W trakcie analizy incydentu możemy napotkać na fragmenty kodu JavaScript, który został wykonany w przeglądarce użytkownika. Złośliwy kod może zostać osadzony na stronie internetowej na przykład przez atak XSS lub też wyświetlony użytkownikowi za pośrednictwem odpowiednio przygotowanej reklamy (malvertising). Odszyfrowanie takiego kodu, w celu jego analizy jest możliwe, a dostępne narzędzia ułatwiają tę pracę, automatyzując niektóre jej elementy.
W sieci dostępnych jest sporo obfuskatorów JavaScript, a ich funkcjonalność ograniczona jest jedynie przez fantazję ich twórców. Przyjrzyjmy się ich działaniu dla tego samego kodu źródłowego:
document.location="http://www.sekurak.pl";
listing 5. I tak Javascript Obfuscator pozamienia kodowanie znaków, a funkcję document.location wywoła poprzez argumenty pewnej skomplikowanej tablicy, JS obfuscate wykorzysta funkcję eval(), operacje na łańcuchach znaków oraz funkcje warunkowe, a obfuscator o wdzięcznej nazwie JSFuck wykorzysta fakt, że każdy skrypt JS może zostać zapisany jako łańcuch znaków i zwróci bardzo długi i niezrozumiały kod, zawierający tylko sześć unikalnych symboli: [, ], (, ), + oraz !. Wśród obfuskatorów warto wspomnieć także o projekcie JScrambler, który może służyć nie tylko do obfuskacji, ale także optymalizacji kodu JS. Wykorzystanie JScramblera w celu obfuskacji JavaScriptu wymaga jednak wykupienia abonamentu, chociaż funkcjonalność narzędzia można sprawdzić w bezpłatnym okresie próbnym.
Deobfuskacja
1. JSBeautifier
Jednym z elementów obfuskacji kodu jest usuwanie wcięć, spacji oraz znaków nowej linii. JSbeautifier pomoże pozbyć się tego problemu i jednym kliknięciem “upiększy” nasz złośliwy kod, a przy zaznaczonej opcji “Detect packers and obfuscators” dokona wstępnej deobfuskacji kodu. JSbeautifier dostępny jest w postaci bezpłatnej aplikacji webowej.
Kod z listingu 4 został przerobiony przez JSbeautifier do następującej postaci:
var _0x3725 = ["\x73\x65\x6B", "\x75\x72\x61\x6B", "\x2E\x70\x6C", "\x68\x74\x74\x70", "\x3A\x2F\x2F\x77\x77\x77\x2E", "\x6C\x6F\x63\x61\x74\x69\x6F\x6E"]; var _0x64df = [_0x3725[0], _0x3725[1], _0x3725[2], _0x3725[3], _0x3725[4], _0x3725[5]]; a = _0x64df[0]; b = _0x64df[1]; c = _0x64df[2]; d = _0x64df[3]; e = _0x64df[4]; document[_0x64df[5]] = d + e + a + b + c;
listing 6.Jeśli wybierzemy dodatkowo opcje “Unescape printable chars encoded as \xNN or \uNNNN” nasz kod staje się na tyle czytelny, że możemy przewidzieć, jaki będzie rezultat jego wykonania:
var _0x3725 = ["sek", "urak", ".pl", "http", "://www.", "location"]; var _0x64df = [_0x3725[0], _0x3725[1], _0x3725[2], _0x3725[3], _0x3725[4], _0x3725[5]]; a = _0x64df[0]; b = _0x64df[1]; c = _0x64df[2]; d = _0x64df[3]; e = _0x64df[4]; document[_0x64df[5]] = d + e + a + b + c;
listing 7.Zbliżoną funkcjonalnością do JSbeautifier cechuje się na przykład web aplikacja JSPretty.com. Warto sprawdzić wynik deobfuskacji w kilku “upiększaczach” lub używać ich naprzemiennie, ponieważ każdy może inaczej radzić sobie z przesłanym kodem.
2. JSDetox
JSDetox to linuxowe narzędzie do analizy JavaScriptu napisane w języku ruby. Strona domowa projektu zawiera krótki poradnik instalacji JSDetox pod Linuxem, która sprowadza się do pobrania paru paczek związanych z frameworkiem ruby oraz sklonowaniem repozytorium z githuba. Narzędzie uruchamia mały serwer HTTP, domyślnie otwarty na porcie 3000, na którym czeka graficzny interfejs użytkownika. JSDetox umożliwia szerszą analizę złośliwych skryptów JavaScript, zmianę nazw używanych zmiennych, a nawet kontrolowane uruchomienie kodu w emulowanym środowisku. Użyjmy go do kodu z listingu 4, uruchamiając go w JSDetox. W zakładce Execution pojawi się ostrzeżenie, że analizowany JavaScript próbował uruchomić funkcję eval(), a po kliknięciu “Show Code” można zobaczyć, jaki argument przesłany został do tej właśnie funkcji.
Używając przycisku “Send to Analyze”, możemy otrzymany wynik przekazać do okienka analizy i ponownie użyć opcji formatowania i upiększania. Dużą zaletą JSDetox jest możliwość zmiany nazw zmiennych, dzięki czemu analityk może łatwiej prześledzić, gdzie w skrypcie wykorzystywane są obliczane wartości. Ta prosta refaktoryzacja wymaga jedynie kliknięcia w interesującą nas zmienną i podania jej nowej nazwy. Zmiany należy następnie zatwierdzić i przeanalizować kod ponownie. Używając opcji dostępnych w pakiecie JSDetox, możemy bardzo szybko uporządkować kod z listingu 4 do następującej postaci:
var url = ["sek", "urak", ".pl", "http", "://www.", "location"]; var zmienna = [url[0], url[1], url[2], url[3], url[4], url[5]]; a = zmienna[0]; b = zmienna[1]; c = zmienna[2]; d = zmienna[3]; e = zmienna[4]; document[zmienna[5]] = d + e + a + b + c;
listing 8. Jego dalsza, ręczna analiza nie powinna już przysporzyć większych problemów.
JSDetox posiada wirtualne funkcje, które wspomagają analizę podejrzanych skryptów. Analizowany kod może w dowolnym miejscu zostać przerwany przy użyciu wbudowanej funkcji jsdetox.break(), a każda zmienna może zostać zalogowana do konsoli przy użyciu funkcji jsdetox.puts(). JSDetox może także przetwarzać fragmenty kodu osadzone w elementach strony internetowej oraz pomóc przy analizie umieszczonego shellcode’u.
Mimo ciekawej funkcjonalności JSDetoxowi zdarza się utracić responsywność (w przypadku przesłania do analizy dużej porcji nieparsowalnego kodu) lub też działać inaczej, niż można by się tego spodziewać (przy zmianie nazw zmiennych). Z tego powodu zalecane jest kopiowanie wyników pośrednich do plików tekstowych, aby możliwe było ich przywrócenie w przypadku awarii GUI. Mimo tych małych wad i delikatnych problemów ze stabilnością i użytecznością JSDetox jest bardzo przydatnym narzędziem podczas analizy obfuskowanych plików .js.
3. JSUNPACK
JSUNPACK to webaplikacja do automatycznej analizy kodu JavaScript. Po przekazaniu do JSUNPACK kodu z listingu 4 bardzo szybko otrzymaliśmy informację, że JavaScript próbuje wykonać przekierowanie.
//jsunpack.url documentlocation = http://www.sekurak.pl
listing 9. Na tym jednak analiza się nie zakończyła, JSUNPACK przeanalizował także docelową stronę i przekazał informacje o wszystkich jej mniej lub bardziej podejrzanych fragmentach. W odróżnieniu od JSDetox, JSUNPACK wymaga przesłania danych na zewnętrzny serwer, wobec czego nie powinien być używany do analizy treści zawierających poufne dane. Istnieje co prawda opcja “Private”, której zaznaczenie spowoduje, że analiza nie będzie publicznie dostępna, ale wciąż może być współdzielona z innymi analitykami bezpieczeństwa. Do użytku offline twórcy zalecają skorzystanie z jsunpack-n, który jest silnikiem strony webowej i może zostać uruchomiony lokalnie. Innymi narzędziem podobnym do JSUNPACK jest wepawet.
Analiza złośliwego JavaScriptu
Przeanalizujmy zatem JS-redirect wykorzystywany przez Exploit Pack Fiesta. Plik pcap, w którym znajduje się JavaScript, można pobrać ze strony, a złośliwy skrypt znajdziemy w 61 pakiecie podsłuchanej transmisji.
Pierwsze spojrzenie na plik nie nasuwa zbyt wiele koncepcji o jego działaniu, chociaż można się spodziewać, na jaką stronę przekierowuje (autorzy nie zadali sobie za dużo trudu, aby to ukryć):
W pierwszej kolejności damy popisać się omawianej w artykule web aplikacji JSbeautifier. Wstępna deobfuskacja, a raczej uporządkowanie kodu, daje już pierwsze efekty. Pojawiają się słowa kluczowe, widać podział na funkcje i ogólny zarys struktury skryptu.
W paru miejscach ciągi znaków są intencjonalnie przerwane i połączone przy pomocy operatora dodawania. Możemy wrzucić plik w takiej postaci do JSDetoxa, który połączy je z powrotem, bądź też zrobić to ręcznie w edytorze plików, przy okazji zaznajamiając się z kodem.
Kod jest już podzielony na logiczne bloki, czas spojrzeć, w jaki sposób działa, i odnaleźć miejsce startu. Jedyny fragment, nie objęty funkcjami to początek kodu oraz jego ostatnia linia. Na początku skryptu znajdują się jednak tylko przypisania, wobec czego można spodziewać się, że właściwe działanie zaczyna się od wywołania funkcji lwnScmat0x() z argumentem naKtBhuNiPs.
Aby uzyskać bardziej przejrzysty obraz, zmieńmy ich nazwę przy pomocy funkcji Rename wbudowanej w GUI JSDetox. Nowa nazwa nie musi odzwierciedlać działania funkcji, ale powinna być w miarę unikalna. Zmiana nazw funkcji z losowych na łudząco podobne (np. temp1, temp2, temp3 itd.) na pewno nie ułatwi analizy kodu. Po zmianie nazw dużo łatwiej jednak znaleźć definicje obu funkcji oraz zidentyfikować sposób działania skryptu.
Doszliśmy do momentu, gdzie należy spełnić 3 warunki w instrukcji if, aby wykonać potencjalnie złośliwy kod.
Jeśli odszukamy te funkcje u góry kodu, zauważymy, że pierwsza z nich odpowiedzialna jest za pliki cookie, druga zawiera w jednym z przypisań ciąg “Trident”, a trzecia wydaje się sprawdzać architekturę systemu operacyjnego Windows… Nadajmy im zatem tymczasowe nazwy:
Pora na kolejne wnioski. Obie funkcje odwołują się do dwóch funkcji: DXUIZPlEg() zwracającej ciąg User Agent przeglądarki użytkownika oraz IwASNDXkbz() sprawdzającej zawartość jednego łańcucha znaków w drugim.
Można wobec tego wywnioskować, że funkcja, którą do tej pory nazywaliśmy trident_XX() ma na celu identyfikację przeglądarki Internet Explorer, a funkcja Windows_platform_ver() pozwala stwierdzić, czy JavaScript ma do czynienia z wersją 64 bitową systemu operacyjnego Microsoftu. Pora wykonać kolejny Rename.
Po sprawdzeniu instrukcji warunkowej można dojść do wniosku, że exploit kierowany jest do użytkowników Internet Explorera na systemach innych niż 64-bitowy Windows.
Co dzieje się po spełnieniu warunków? Do tego przyda się znowu notatnik i manualne przeklejanie zawartości zmiennych, które są przypisywane tuż przed instrukcją if. Niejasna pozostaje jeszcze linia 84 i 85 z poniższego screena.
Wyjaśnienia można szukać u góry skryptu, w prostych przypisaniach, mających na celu zaciemnienie kodu. Po raz kolejny warto użyć funkcji Rename, aby uzyskać czysty obraz lub też przekleić wartości bezpośrednio do zmiennych w bloku instrukcji warunkowej.
Kiedy już wiemy, co chce zrobić skrypt i przy jakich warunkach, możemy wydrukować sobie wynik przy pomocy wbudowanej w JSDetox funkcji jsdetox.puts(). Warto pamiętać, że JSDetox działa w emulowanym środowisku i że niektóre zmienne środowiskowe są dla niego obce. Dlatego też wykomentowaliśmy instrukcję warunkową oraz elementy listenera w funkcji final_func(). Efekt końcowy otrzymujemy w konsolce JSDetox:
Dalsza analiza
Ze względu na różne techniki obfuskacji JavaScriptu, omawiane w artykule narzędzia warto używać naprzemiennie. Czasem może okazać się, że to, czego nie rozwiąże jeden deobfuskator, z powodzeniem można odszyfrować w innym. Często jednak obfuskacja będzie na tyle złożona, że dopiero manualna edycja całego kodu pozwoli na poznanie jego zawartości.
Po kolejne próbki obfuskowanego kodu zajrzeć można chociażby na wspomnianą już stronę
Linki
1. Obfuskatory
- Javascript Obfuscator
- JS obfuscate
- JSFuck
- JScrambler (płatny, darmowy trial)
2. Upiększacze kodu
- JSBeautifier (upiększa także HTML oraz JSON)
- JSPretty.com
3. Deobfuskacja
4. Pliki pcap – tu można szukać obfuskowanych skryptów JavaScript
–Marcin Szymankiewicz
Bardzo dobry, techniczny artykuł. Ciekawie przedstawiony i przydatny temat. Ciekawą opcją narzędzia jest jeszcze Malzilla. Wskazane przez Ciebie chętnie przeklikam.
Gratulacje :)
a wiecie że eval wystarczy zmienić na alert lub odpowiedniki eval na odpowiednik alert i to cała deobfuskacja !
Bo wiecie że obfuskacja w językach skryptowych w założeniach ma uniemożliwiać detekcje automatycznym systemom detekcji (AV itp)