Problemy z XXE (XML eXternal Entity)

28 marca 2014, 09:25 | Teksty | Komentarze: 9

Podatności związane z XXE (XML eXternal Entity) ostatnimi czasy zdobywają coraz większą „popularność” w aplikacjach internetowych. Najczęściej wykorzystanie XXE jest sposobem na wykonanie ataku Path Traversal, czasem może jednak dawać większe możliwości. Przyjrzyjmy się tematowi z bliska.

Kilka słów o XML-u

XML jest językiem formalnym, którego celem jest reprezentowanie danych w strukturalizowany sposób. Typowy dokument XML może wyglądać następująco:

W pierwszej linii mamy deklarację XML. Obowiązkowy jest jedynie atrybut version, ale najczęściej spotyka się ją także z parametrem encoding.  Następnie zdefiniowany zostaje element główny (root element), który składa się z dwóch elementów <strona>. Elementy <strona> zawierają po jednym atrybucie (id) oraz trzech elementach-dzieciach: <nazwa>, <url> oraz <komentarz>.

Przyjrzyjmy się dokładniej elementowi: <komentarz>I &lt;3 Sekurak!</komentarz> w którym pojawia się encja &lt;. De facto encje możemy traktować jako operację w rodzaju „znajdź i zamień”: podczas interpretacji wartości elementu <komentarz>, encja &lt; zostanie zamieniona na znak <. W powyższym przykładzie encja &lt; była obowiązkowa ze względu na specjalne znaczenie znaku <. Gdyby wpisać I <3 Sekurak, otrzymalibyśmy błąd parsera, ponieważ potraktowałby on <3 jako otwarcie tagu.

 

Parsujemy XML

Weźmy bardzo prosty skrypt w PHP do parsowania XML-a z powyższego przykładu.

Kod realizuje następujące operacje:

  1. Czytamy plik test.xml.
  2. Interpretujemy jego zawartość jako XML.
  3. Wypisujemy na wyjściu wartości wszystkich elementów <komentarz>.

Zobaczmy co się stanie, jeśli w pliku test.xml umieścimy nasz przykład.

xxe1

Zgodnie z oczekiwaniem, został wyświetlony tekst I <3 Sekurak – encja &lt; została zamieniona na znak <.

Oczywiście standard XML przewiduje możliwość definiowana własnych encji; można to zrobić w elemencie <!DOCTYPE>. Poniżej modyfikujemy przykład, dodając encję &shp; rozwijaną do „Sekurak Hacking Party” (dla zwięzłości, usunąłem też rekord owasp).

Dodałem wspomnianą encję oraz odniesienie do niej w tagu <komentarz>. Zobaczmy jak teraz zachowa się skrypt.

xxe2

Świetnie! Encja &shp; została zamieniona na „Sekurak Hacking Party”. Jak widać, definiując takie encje możemy sobie oszczędzić pisania ;).

Dopiero teraz zacznie się jednak robić ciekawie. Encje XML-owe mogą być także importowane z plików. Założeniem tego mechanizmu była możliwość utworzenia pewnych definicji encji, które mogą być współdzielone między wieloma dokumentami, bez potrzeby definiowania ich w każdym z osobna. Spróbujmy jednak trochę nadużyć tej funkcji…

Zmieniłem definicję encji &shp; – dołożyłem słowo SYSTEM (to informacja, że encja ma być pobierana z pliku), a jako plik wskazałem /etc/passwd. Zobaczmy co się stanie.

xxe3

Voila! Wykorzystaliśmy niepozorną interpretację plików XML do przeprowadzenia ataku Path traversal.

Atak ma jednak ograniczenia, otóż dołączane pliki:

  • muszą być poprawne w kontekście gramatyki XML,
  • nie mogą zawierać bajtu zerowego (\x00).

Zatem czytanie plików binarnych w ogólnym przypadku odpada. Istnieją różne możliwości obchodzenia tych ograniczeń – są one jednak bardzo mocno zależne od używanej technologii i biblioteki.

Pokażę jak w PHP można obejść problem z użyciem wrappera php://filter. Wpierw jednak sprawdźmy jak zachowa się aplikacja w przypadku próby dołączenia binarnego pliku /bin/bash.

xxe4

Próba nieudana. Przygotujmy więc filtr, który enkoduje wyjście z czytanego pliku do base64. Wygląda następująco: php://filter/convert.base64-encode/resource=/bin/bash

I zobaczmy co się stanie teraz:

xxe5

Tym razem bez błędów – możemy więc czytać dowolny plik na dysku.

Warto zdawać sobie sprawę, że XXE umożliwia nie tylko czytanie plików lokalnych; zwykle da się również wykonywać zapytania http(s), ftp, czasem również inne protokoły. Stąd prosta droga do skanowania sieci lokalnej (np. enumeracji hostów) z użyciem tzw. Server Side Request Forgery. Możliwości jakie daje atak XXE są silnie zależne od używanych technologii, np.

  • W niektórych bibliotekach Javy, odwołanie się do nazwy katalogu (np. /etc/) powoduje wylistowanie jego zawartości.
  • W pewnych implementacjach można używać protokołu gopher://, który umożliwia wysyłanie danych de facto w dowolnym protokole pod dowolny port.

 

Jak się bronić

Ochrona przed atakiem XXE Injection polega po prostu na blokowaniu możliwości importowania zewnętrznych encji – zwykle w danych pobieranych od użytkownika taka funkcja nie jest do niczego potrzebna. Przykładowo w PHP można użyć funkcji:

Inne języki również mają swoje odpowiedniki, odsyłam do odpowiednich dokumentacji. W części interpretatorów XML-a dołączanie zewnętrznych encji jest domyślnie wyłączone.

 

Podsumowanie

Przyjmując dane w postaci dokumentu XML musimy pamiętać o podstawowej zasadzie bezpieczeństwa: nigdy nie ufaj danym otrzymanym od użytkownika. W tym przypadku zagrożenie niesie importowanie encji z zewnętrznych plików, efektywnie umożliwiające atak Path traversal.

Właściwie jedynym powszechnie używanym zabezpieczeniem jest całkowite wyłączenie ładowania zewnętrznych encji w parserze XML-a.

 

Dalsza lektura

Kilka ciekawych linków do dalszej lektury:

– Michał Bentkowski

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



Komentarze

  1. Michał B
    Odpowiedz
  2. SebaVegas

    To jest to co tygryski lubią najbardziej! Następny art tego typu niech będzie o php:unserialize()

    Odpowiedz
    • Michał B

      Nie ukrywam, że mam ten temat ostatnio na oku ;)

      Odpowiedz
  3. Coraz ciekawiej na tym sekuraku, dzięki tobie Michał

    Odpowiedz
  4. Olo

    Brawo ! Zwięźle i na temat. Poziom 1 liga !
    Ludzie : “Keep Calm and Carry On” -^~

    Odpowiedz
    • Olo: “stay tuned”.
      Michał ma już małą bombkę na kolejny tydzień :-) Już jest w zasadzie opisana, tylko czekamy na zapatchowanie problemu przez zainteresowanych – czyli firmę Google :-P

      Odpowiedz
  5. Marek

    Super artykuł. Okazuje się, że w bibliotekach Javy pojawia się potencjalnie insecure default. Nic dziwnego, że programiści o tym zapominają. Bardzo łatwo to przeoczyć.

    Porobiłem parę testów na bibliotekach JDom oraz Dom4J celem rozpracowania tematu dla Javy. Gdyby ktoś był zainteresowany – kod umieszczony został na githubie: https://github.com/marpuch/Java-Sec-Examples

    Odpowiedz

Odpowiedz


+ 7 = 15