Potwornie Dziurawy Format - JavaScript a luki w PDF Tomasz Grudziecki, Paweł Jacewicz NASK/CERT Polska, 2009 CZĘŚĆ I Trochę o PDF-ach Wszędobylski PDF. Każdy z nas spotkał się z plikami PDF. Są one jednym z najpopularniejszych formatów służącym przenoszeniu i udostępnianiu informacji. Ich obsługa jest możliwa w każdym systemie operacyjnym oraz w większości urządzeń przenośnych. Powszechność formatu szybko wzbudziła zainteresowanie środowisk, które specjalizują się w poszukiwaniach podatności oraz potencjalnych metod ich wykorzystania. Nie trzeba było długo czekać, aby w sieci pojawiły się pierwsze złośliwe pliki PDF wykorzystujące luki w najpopularniejszym czytniku Acrobat Readerze. Znaczny wzrost ilości krążących w sieci złośliwych PDF ów nastąpił w drugiej połowie 2008 roku. Miało to najprawdopodobniej związek z uwolnieniem standardu przez Adobe Systems w lipcu 2008 i publikacją pełnego dokumentu opisującego strukturę i funkcjonalność formatu. Rys. 1: Udział procentowy aktywnych w sieci typów podatnościzwiązanych z plikami PDF (w odniesieniu do maksimum aktywności w październiku 2008) CVE- 2007-5659 podatność w funkcji JavaScript CollabEmailInfo() CVE- 2008-2992 podatność w funkcji util.printf() (X)
PDF od środka. Pliki PDF są dość proste w budowie. Możemy wyróżnić w nich: nagłówek, obiekty, tablicę referencji oraz stopkę dokumentu. Najważniejsze są obiekty, które przechowują większość informacji. Format udostępnia funkcje umożliwiające osadzanie w pliku PDF praktycznie dowolnej zawartości od standardowego tekstu, poprzez obrazy i nagrania audio do nawet całych animacji i krótkich filmów. Ułożenie obiektów w dokumencie jest prawie dowolne, a za prawidłowe ich lokalizowanie odpowiada wspomniana tablica referencji. Nie taki bezpieczny jak by się wydawało. Rozpatrując aspekty związane z bezpieczeństwem informacji musimy zwrócić uwagę na metody jakie mogą być użyte w celu zarażenia komputera. Przede wszystkim nowe zagrożenia maskują się przed skanerami antywirusowymi, głównie z wykorzystaniem polimorfizmu, który zapewnia format: od zamiany kolejności obiektów w dokumencie, kodowanie i kompresję strumieni na zaciemnianiu kodu infekującego komputer kończąc. Napotkane w sieci pliki z reguły łączą kilka z wymienionych technik przez długi czas pozostając nie wykryte przez popularne antywirusy. Potęga strumieni. To co stanowi o sile formatu PDF to strumienie. Od wprowadzenia obsługi języka JavaScript, mogą one przechowywać kod wykonywany przez interpreter. Dostępne w formacie funkcje pozwalają na maskowanie go, np. kompresowanie, kodowanie lub nawet szyfrowanie. W tabeli poniżej wymienione są filtry, które dekodują dane zawarte w strumieniu do postaci oryginalnej. Przedstawiono tylko te, które mogą odzyskać dane w ich oryginalnej formie. Niektóre są parametryzowane, co dodatkowo utrudnia heurystykom analizę. Nazwa filtru Parametryzowany Opis ASCIIHexDecode ASCII85Decode LZWDecode FlateDecode RunLengthDecode Crypt Nie Nie Tak Tak Nie Tak Dekoduje dane binarne zapisane w reprezentacji heksadecymalnej Dekoduje dane binarne zapisane z wykorzystaniem reprezentacji base-85 Dekompresuje dane zakodowane z użyciem metody LZW (Lempel-Ziv-Welch) Dekompresuje dane zakodowane z użyciem metody zlib/deflate Dekompresuje dane zakodowane z użyciem algorytmu kodowania długości serii (RLE) zorientowanego na bajty Dekoduje dane zakodowane z wykorzystaniem algorytmów AES, RC4 lub kryptografii klucza publicznego. W zaobserwowanych złośliwych plikach PDF kod JavaScript był kompresowany z użyciem biblioteki zlib/deflate. Dodatkowo często był zaciemniany poprzez użycie różnego rodzaju pakerów, np. udostępnionego na stronie http://dean.edwards.name/packer/. Zwykła linijka w postaci document.write("hello world!");
Zostaje zamieniona na prawie nieczytelną formę: eval(function(p,a,c,k,e,r){e=string;if(!''.replace(/^/,string)) {while(c--)r[c]=k[c] c;k=[function(e){return r[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}('0.1("2 3!");',4,4,'document write Hello world'.split(' '),0,{})) Takie modyfikacje znacznie utrudniają analizę lub powodują generowanie fałszywych alarmów gdy napotka się niegroźny kod skompresowany z użyciem takiego narzędzia. Dziurawy silnik. Obsługa kodu JavaScript w aplikacji nie oznacza od razu, że oprogramowanie jest podatne na atak. Głównym odpowiedzialnym jest tu interpreter języka. To błędy w nim zawarte pozwalają na uruchamianie złośliwego kodu. Najczęściej polegają one na błędach przepełnienia bufora oraz wstrzyknięciu tzw. shellcode u, który uruchomiony w działającym programie (np. Adobe Reader a) pozwala na zainfekowanie komputera wirusem. Wszystko odbywa się oczywiście za plecami użytkownika. Najczęściej jedynym objawem jest wzmożony ruch sieciowy generowany przez komputer. Warto zauważyć, że chociaż najczęściej atakowane są wersje czytników PDF pod system Windows, to luki występują także w ich wersjach pod systemy uniksowe. Tylko w tym roku firma Adobe załatała już dwie podatności w programie Reader, obie miały status krytycznych i występowały zarówno w wersjach dla platformy Windows, jak i Unix oraz Macintosh. Informacje bezpieczeństwa dotyczące programu Adobe Reader dla systemów uniksowych można uzyskać pod adresem http://www.adobe.com/support/security/#readerunix. Jak się (nie) zarazić. Najwięcej złośliwych plików PDF udało się znaleźć na skompromitowanych serwisach WWW. Odkąd razem z Adobe Reader em instalowane są rozszerzenia do przeglądarek ta forma ataku jest najczęściej wykorzystywana. Bardzo rzadko zdarzają się złośliwe pliki PDF przesyłane w postaci załączników w SPAM ie. W takim przypadku użytkownik musi sam otworzyć plik. Ochroną przed zarażeniem się jest przede wszystkim zdrowy rozsądek. Nie otwierajmy plików pochodzących z nieznanych źródeł oraz wyłączmy obsługę plików PDF w przeglądarce. Dodatkowo możemy wyłączyć obsługę JavaScript w czytniku. Odrobinę ochrony przed złośliwymi PDF ami zapewniają programy antywirusowe (dotyczy tylko platformy Windows). Niestety szybkość aktualizacji baz antywirusowych może trwać nawet kilka miesięcy. Na szczęście sytuacja nie jest aż tak straszna. Producenci aplikacji i systemów operacyjnych starają się szybko wypuszczać aktualizacje. Utrzymanie systemu i oprogramowania w aktualnej wersji to podstawowa linia obrony. Często grasujące w sieci złośliwe pliki PDF wykorzystują lukę już załataną. Zachęcamy także do monitorowania informacji na portalach związanych z bezpieczeństwem komputerowym. Będąc na bieżąco z tym, co dzieje się w sieci
pomoże uniknąć nieprzyjemnej niespodzianki, która może nas kosztować nie tylko dane ale często także fundusze. Doktorze, skalpel proszę Zobaczmy jak funkcjonuje złośliwy plik PDF na który można się natknąć w sieci. Za przykład posłuży nam plik, który był skanowany z użyciem serwisu VirusTotal.com. Na początek jednak parę uwag dla amatorów zabaw z wirusami. 1. NIGDY ale to NIGDY nie nie należy otwierać tego typu plików na komputerze używanym na co dzień. Najlepszym rozwiązaniem jest praca na maszynie wirtualnej (np. VirtualBox) lub w systemie Linux. Polecam drugie rozwiązanie ze względu na ilość dostępnych narzędzi pomocnych w analizie zawartości plików PDF. 2. Nie należy odwiedzać serwerów, których adresy można znaleźć wewnątrz kodu. A z całą pewnością błędem są próby włamywania się na takie serwery (nawet jeśli intencje macie dobre). Autorzy takich PDFów mają z reguły słabe poczucie humoru i mogą odpowiedzieć na tego typu postępowanie atakiem (typowo: DDoS). Najlepszym wyjściem jest zgłoszenie do CERT adresu URL strony www (zwłaszcza jeśli jest z Polski) na której wykryliście zagrożenie. 3. Zdrowy rozsądek bez niego nie należy zabierać się do roboty. 4. Zestaw narzędzi będą przedstawione w dalszej części. Z takim ekwipunkiem można śmiało zaczynać sekcję na pliku PDF. Pierwsze cięcie Na początku warto zorientować się czy dany plik PDF zawiera kod JavaScript. Jak wcześniej było wspomniane, lwia część obecnych w sieci złośliwych plików wykorzystuje błędy w silniku JS. Bardzo prostym i dającym dobre wyniki narzędziem jest PDFiD i. Jest to skaner napisany w języku Python, który potrafi wykrywać i usuwać proste techniki zaciemniania w nazwach (patrz rozdział 7.3.5 w opisie formatu PDF ii ). Podaje także statystyki dotyczące obiektów w pliku PDF (patrz rys.2. Gdy narzędzie stwierdzi, że dany plik zawiera JavaScript możemy przystąpić do kolejnego kroku, czyli do zlokalizowania i wyodrębnienia kodu.
Rys. 2: Analiza pliku PDF z wykorzystaniem narzędzia PDFiD Szukamy głębiej Stwierdzenie, że plik PDF zawiera JavaScript nie oznacza od razu, że jest on złośliwy, ale daje poważne przesłanki by tak sądzić, zwłaszcza jeżeli pochodzi z niewiadomego źródła. Aby się przekonać o szkodliwości kodu JS w danym pliku należy go wydobyć i poddać analizie. Pomocnym narzędziem w tym etapie może być PDF-Parser iii. Potrafi on analizować struktury wewnętrzne i wyszukuje zależności pomiędzy obiektami. Jego bardzo pomocną funkcją jest także możliwość dekompresji strumieni zachowanych z wykorzystaniem biblioteki zlib/deflate (bardzo często stosowana technika ukrywania kodu JS). Z reguły kod, jeśli jest złośliwy, jest zaciemniony. W przypadku gdy developer poszedł na łatwiznę i wykorzystał jedną z ogólnie dostępnych metod możemy w prosty i szybki sposób odzyskać oryginalny kod. Jednak coraz częściej stosowane są autorskie sposoby kodowania, wtedy musimy użyć specjalnych narzędzi do analizy JavaScript u. CZĘŚĆ II Trochę o JavaScript-ach Ręczna analiza złośliwego JavaScript-a jest nie tylko czasochłonna, ale również wymaga kosztownego i niedeterministycznego narzędzia jakim jest człowiek. Dlatego automatyzacja
analizy kodu jest pożądana szczególnie tam, gdzie robi się to w sposób masowy. Potencjalnie złośliwy kod JavaScript czy to pochodzący ze strony www czy z pliku PDF można analizować na dwa sposoby: z użyciem narzędzi nisko-interaktywnych oraz wysokointeraktywnych. Jak mądrze i z premedytacją się zarazić? Przykładem analizy wysoko-interaktywnej jest monitorowanie zmian w systemie podczas wejścia na podejrzaną stronę poprzez przeglądarkę internetową, a w przypadku pliku PDF w trakcie jego otwarcia w odpowiednim czytniku. Dzięki temu możemy w pełni dowiedzieć się co złośliwy kod robi i pozyskać wszelkie pobrane podczas infekcji pliki. Tak działa dosyć popularny w środowisku ludzi zajmujących się tym tematem Capture-HPC iv rozwijany w ramach projektu The Honeynet Project. Niestety, warunkiem koniecznym do przeprowadzenia tej analizy jest posiadanie odpowiedniej wersji podatnej aplikacji działającej na konkretnym systemie operacyjnym. Oznacza to, że do analizy pliku PDF potrzebne byłoby od kilku do kilkudziesięciu systemów na których podejrzany dokument otwierany byłby w różnych wersjach różnych czytników. W przypadku stron www używane byłyby różne wersje najpopularniejszych przeglądarek, każda z kombinacją najpopularniejszych wtyczek. Takie rozwiązanie jest czasochłonne (nawet gdy monitorowane systemy są zwirtualizowane), oraz kosztowne (cena serwerów na których działają zwirtualizowane systemy, a także koszt licencji systemów operacyjnych i aplikacji). Plusem jest możliwość pozyskania kompletnych danych gdy uda się uruchomić złośliwy PDF/stronę www w podatnej wersji aplikacji i systemu. Analiza sygnaturowa nie działa Przykładem analizy nisko-interaktywnej jest porównanie zawartości (pliku czy strony www) do wcześniej zdefiniowanych sygnatur. Tak działają najczęściej programy antywirusowe czy systemy detekcji ataków sieciowych IDS (np. popularny Snort). Takie podejście ma swoje zalety, jak szybkość działania, niezależność od wersji podatnej aplikacji i niski koszt zarówno nabycia bądź stworzenia jak i utrzymania. Jest też bezpieczne, ponieważ nie następuje wykonanie złośliwego kodu (exploit'a oraz shellcod'u) ani rzeczywista infekcja. Jednak, szczególnie w najprostszej formie jaką jest zwykłe porównywanie sygnatur, nie jest w stanie wykryć złośliwego kodu JavaScript zaciemnionego (ang. obfuscated) na różne sposoby (jak było wcześniej podane, możliwości zaciemniania kodu mogą być nieograniczone). Pomimo tego sytuacja nie jest tak beznadziejna. W połowie 2007 roku ruszył projekt HoneySpider Network (HSN) v, który ma na celu zbudowanie nowych oraz wykorzystanie istniejących technik klienckich honeypotów do wykrywania ataków na aplikacje klienckie (szczególnie przeglądarki internetowe). Jest to wspólne przedsięwzięcie działającego w ramach NASK zespołu CERT Polska, rządowego CERTu holenderskiego GOVCERT.NL oraz akademickiego operatora w Holandii SURFnet. System wykorzystuje zarówno komponenty nisko-interaktywne (LIM Low Interaction Module), jak i wysoko-interaktywne (HIM High Interaction Module). Zbawienie pochodzi z heurystyk W obecnej wersji systemu HSN część nisko-interaktywna zwana LIM skupia się głównie na analizie kodu JavaScript. Stworzone rozwiązanie jest dosyć złożone, a klasyfikacja
analizowanego skryptu JS opiera się na technikach uczenia maszynowego (ang. machine learning) i tzw. data mining. Użyte w tym celu zostały narzędzia Weka vi i Google N-grams vii. Weka jest zestawem algorytmów uczenia maszynowego zaimplementowanym w języku JAVA i udostępniona na zasadach open source. Może być użyta zarówno jako oddzielne narzędzie, jak i zintegrowane z innym. W systemie HSN wykorzystywany jest jej klasyfikator Bayesowski (ang. Naive Bayes Classifier) jako dający najlepsze rezultaty. Oczywiście system musi zostać wcześniej nauczony, dlatego stworzony został przez człowieka zbiór danych uczących (trenujących), oraz zbiór danych weryfikujących (testujących) umiejętności klasyfikatora (patrz rys. 3). Zbiory te mogą być cały czas wzbogacane o nowe dane zarówno przez człowieka, jak i automatycznie poprzez dodawanie do zbioru trenującego ostatnio sklasyfikowanego skryptu JS. Rys. 3: Proces nauczania klasyfikatora Weka Doświadczenia pokazały viii, że analiza całego skryptu JS nie jest optymalna, a duże lepsze rezultaty daje podział kodu na mniejsze fragmenty. Do tego celu w projekcie HSN wykorzystywany jest rozpowszechniany na zasadzie open source i napisany w języku C++ pakiet Google N-grams. Analizowany przez LIM JavaScript jest dzielony na części zwane n- gramami o określonej długości znaków, przy czym każdy kolejny n-gram powstaje przez przesunięcie w kodzie JS o jeden znak względem poprzedniego n-grama (jest to tzw. mechanizmu przesuwnego okna, ang. sliding window mechanism). Następnie z powstałego w ten sposób zbioru n-gramów wybierane są najczęściej występujące i poddawane analizie w Weka. Po wcześniejszym nauczeniu Weka bardzo dobrze radzi sobie w wykrywaniu zaciemnionego kodu JS. Oczywiście zaciemniony JavaScript nie jest jednoznaczny ze złośliwym skryptem wiele stron niezłośliwych stosuje zaciemnienie dla różnych celów, np. ochrona praw autorskich czy pakowanie kodu. Dlatego każdy zaciemniony JavaScript jest odciemniany (ang. deobfuscate) z wykorzystaniem narzędzia Rhino ix (jest to implementacja w JAVA silnika JavaScript zarządzana przez Fundację Mozilla, udostępniona na zasadach open source). Po odciemnieniu (nieraz nawet wielokrotnym) kod JS poddawany jest ponownemu podziałowi na n-gramy i analizie w Weka tym razem pod kątem bycia złośliwym. Proces ten pokazuje rys. 4.
Rys. 4: Proces analizy skryptów JS w LIM systemu HSN Stosując dodatkowe heurystyki w trakcie oraz po wykonaniu skryptu JS w Rhino można poprawić skuteczność LIM i weryfikować rezultaty analizy zwracane przez Weka. Zarówno w kodzie JavaScript (jednocześnie przed odciemnieniem jak i po) oraz w pamięci Rhino (podczas wykonywania JS) wyszukiwane są słowa kluczowe. Ponadto Rhino jest monitorowany czy nie nastąpiło wyczerpanie przydzielonej mu pamięci (out of memory error) lub JavaScript nie wykonuje się podejrzanie długo (execution timeout). Ostatecznie kod JavaScript pod względem zaciemnienia może być sklasyfikowany przez LIM jako obfuscated (zaciemniony), obfuscated unconfirmed (Weka twierdzi, że JS jest zaciemniony, ale Rhino tego nie potwierdza), oraz non-obfuscated (niezaciemniony). Natomiast pod względem złośliwości skrypt JS może być sklasyfikowany jako benign (niezłośliwy), suspicious (podejrzany) bądź malicious (złośliwy). Analiza (prawie) idealna W przeważającej większości przypadków LIM nie będzie w stanie pozyskać ostatecznej aplikacji typu malware, która zostanie uruchomiona w wyniku wykorzystania luki (czy to w przeglądarce www, czy czytniku plików PDF). Jednakże jest w stanie skutecznie zdiagnozować, czy zawarty na stronie internetowej lub w pliku PDF JavaScript jest złośliwy lub chociaż podejrzany o bycie złośliwym. Ponieważ analiza ta jest stosunkowo szybka LIM może służyć jako filtr dla komponentu wysoko-interaktywnego tylko obiekty sklasyfikowane w LIM jako złośliwe lub podejrzane są kierowane do ponownej analizy w HIM. Zastosowane w LIM rozwiązanie nie bazuje na typowym porównywaniu sygnatur, dlatego jest ono w stanie wykrywać nieznany mu wcześniej złośliwy kod, w tym również wykorzystujące nieznane dotychczas luki (tzw. 0-day exploit). Mechanizmy machine learning
pozwalają także systemowi weryfikować swoje błędy. Jeżeli LIM pomimo wielu heurystyk nieprawidłowo sklasyfikuje dany JavaScript, jego kod może zasilić zbiór trenujący klasyfikator Weka, przez co w przyszłości podobny fałszywy alarm nie powinien się zdarzyć. Dotyczy to zarówno fałszywych klasyfikacji malicious (tzw. false-positives) jak i benign (tzw. false-negatives). Na zakończenie. Mamy nadzieję, że tym krótkim artykułem udało mi się pokazać jak ważną rzeczą jest świadomość tego, że zagrożenia mogą czaić się wszędzie. Nie tylko w formie robaków internetowych lub wirusów ale także zwykłych plików. Wybraliśmy przykład formatu PDF najpopularniejszego i najszerzej obsługiwanego standardu udostępniania informacji. Drogi Czytelniku, miej oczy szeroko otwarte!
i PDFiD, a tool to triage PDF documents, http://blog.didierstevens.com/2009/03/31/pdfid/ ii Portable document format http://www.adobe.com/devnet/acrobat/pdfs/pdf32000_2008.pdf iii PDF-parser in Python, http://blog.didierstevens.com/programs/pdf-tools/#pdf-parser iv Capture-HPC, https://projects.honeynet.org/capture-hpc v The HoneySpider Network Project, http://www.honeyspider.net vi Weka: Data Mining Software in Java, http://www.cs.waikato.ac.nz/~ml/weka/index.html vii Google N-grams package, http://code.google.com/p/ngrams viii Piotr Kijewski, Carol Overes, Rogier Spoor The HoneySpider Network fighting client-side threats : http://www.honeyspider.net/wp-content/uploads/2009/06/hsn-first2008-article-v02.pdf ix Rhino JavaScript interpreter, http://www.mozilla.org/rhino