XXE
| Po angielsku | XML external entity (XXE) |
|---|---|
| Którą formą pisać | bez tłumaczenia Skrót, nazwa własna albo nazwa standardu — nie tłumaczymy w ogóle. |
| Inne formy | XML External Entity · XXE injection · wstrzyknięcie encji zewnętrznej XML |
| Kategoria | Podatności i klasy błędów |
XXE (XML External Entity) to podatność, w której aplikacja przetwarza dokument XML zawierający encje z adresami URI wskazującymi zasoby spoza zamierzonego obszaru kontroli i wstawia te zasoby do wyniku [1]. OWASP opisuje XXE jako atak na aplikacje parsujące XML, w którym niezaufany dokument z odwołaniem do encji zewnętrznej trafia do słabo skonfigurowanego parsera [2]. W zestawieniu OWASP Top 10 z 2017 roku XXE miało osobną kategorię A4 [3]. W katalogu CWE odpowiada mu słabość CWE-611 [1].
Jak działa
Dokument XML może zawierać definicję typu dokumentu (DTD), a w niej deklaracje encji. Encja może wskazywać adres URI, którego treść parser pobiera i wstawia do dokumentu do dalszego przetwarzania [1]. Jeżeli parser rozwija takie encje, atakujący decyduje, jaki zasób zostanie odczytany: plik lokalny przez schemat file:// albo adres sieciowy przez http:// [1]. Gdy aplikacja odsyła wynik parsowania użytkownikowi, odczytana treść wraca do atakującego [1].
Warunki są dwa. Atakujący musi dostarczyć XML, na przykład przesyłając plik albo wstawiając treść do dokumentu XML, a parser musi mieć włączone przetwarzanie encji zewnętrznych [3]. OWASP zaznacza, że podatny może być kod samej aplikacji, jej zależności albo integracje z innymi systemami [3]. Źródłem XML nie musi więc być formularz: bywa nim plik przesłany przez użytkownika, odpowiedź zewnętrznej usługi albo metadane osadzone w pliku multimedialnym. Dlatego ustawienia parsera trzeba sprawdzać także w bibliotekach, nie tylko we własnym kodzie. Przebieg pokazuje schemat poniżej.
Skutki
MITRE wymienia trzy grupy skutków, a OWASP dodaje do nich skanowanie portów z hosta, na którym działa parser [1] [2].
| Skutek | Mechanizm | Pokrewne hasło |
|---|---|---|
| odczyt dowolnych plików | encja ze schematem file:// [1] | ujawnienie informacji wrażliwych |
| żądania z serwera | encja ze schematem http:// [1] | SSRF (Server-Side Request Forgery) [2] |
| wyczerpanie zasobów | encja wskazująca duży plik albo niekończący się strumień [1] | atak odmowy usługi [2] |
| rozpoznanie sieci | skanowanie portów z hosta parsera [2] | skanowanie portów |
Przez żądania z serwera atakujący dociera do systemów, do których z zewnątrz nie ma dostępu [1]. Sekurak opisywał już w 2014 roku wykorzystanie XXE do ataku typu path traversal, do zapytań HTTP i FTP z poziomu serwera oraz do skanowania sieci lokalnej [8]. Ten sam tekst pokazuje, że atakujący potrafi obejść ograniczenia odczytu, kodując treść pliku filtrem base64 w PHP [8]. OWASP w liście Top 10 z 2017 roku zbiera skutki w jednym zdaniu: wyciąganie danych, zdalne żądania z serwera, skanowanie systemów wewnętrznych, odmowa usługi i inne ataki [3].
W WordPressie
XML pojawia się w WordPressie w kilku miejscach: w interfejsie XML-RPC, w importerach treści i w metadanych przesyłanych plików. Najlepiej opisanym przypadkiem jest podatność CVE-2021-29447 w Bibliotece mediów [7].
Według analizy SonarSource WordPress używał biblioteki getID3 do odczytu metadanych z przesyłanych plików audio, a fragment iXML w pliku WAV parsował funkcją simplexml_load_string() z flagą LIBXML_NOENT [5]. Nazwa flagi myli: w rzeczywistości włącza ona podstawianie encji [5]. Wcześniej kod wywoływał libxml_disable_entity_loader(true), ale dla PHP 8 to wywołanie usunięto, bo funkcja została w tej wersji wycofana [5]. Dokumentacja PHP podaje, że od libxml 2.9.0 podstawianie encji jest domyślnie wyłączone, chyba że kod sam włączy je flagą LIBXML_NOENT, LIBXML_DTDVALID albo LIBXML_DTDLOAD [4]. Właśnie ta flaga ponownie otworzyła drogę do XXE [5].
Do ataku wystarczało konto z prawem przesyłania plików, na przykład autora [7]; zob. role i uprawnienia użytkowników. SonarSource wskazało, że niższe uprawnienia wystarczą w połączeniu z inną podatnością albo wtyczką pozwalającą gościom przesyłać media [5]. Skutkiem mógł być odczyt pliku wp-config.php z danymi dostępu do bazy i kluczami uwierzytelniania albo SSRF [5], dlatego po takim incydencie zmienia się klucze bezpieczeństwa i sole i hasło bazy; zob. też utwardzanie pliku wp-config.php.
Jak się bronić
OWASP uznaje za najbezpieczniejsze całkowite wyłączenie DTD, bo chroni ono także przed atakiem odmowy usługi typu Billion Laughs [2]. Inne zalecenia z listy OWASP Top 10 2017 to prostsze formaty danych, takie jak JSON, wyłączenie encji zewnętrznych i DTD we wszystkich parserach XML, walidacja wejścia po stronie serwera oraz sprawdzanie przesyłanego XML schematem XSD [3]. Jako warstwy dodatkowe OWASP wymienia narzędzia SAST i WAF [3].
W PHP ściągawka OWASP zaleca dla wersji starszych niż 8.0 wywołanie libxml_set_external_entity_loader(null), a o PHP 8.0 i nowszym pisze, że domyślnie zapobiega XXE [2]. Przypadek WordPressa pokazuje granicę tej ochrony: flagi parsera mogą ją wyłączyć [5]. Praktyczne zasady:
- nie włączać flagi
LIBXML_NOENTani ładowania DTD, jeśli nie jest to konieczne [4]; - dla starszych wersji PHP wyłączać ładowanie encji zewnętrznych warunkowo, jak pokazuje dokumentacja PHP [4];
- traktować metadane przesyłanych plików jak dane niezaufane i przepuszczać je przez sanityzację;
- utrzymywać wspierane wersje PHP; zob. koniec wsparcia dla wersji PHP.
// Wzorzec z dokumentacji PHP: tylko dla PHP starszego niż 8.0
if ( PHP_VERSION_ID < 80000 ) {
libxml_disable_entity_loader( true );
}
// Parsowanie bez flagi LIBXML_NOENT
$xml = simplexml_load_string( $dane );
Historia i przykłady
Lista MITRE zawiera między innymi CVE-2012-2239, czyli XXE w aplikacji PHP pozwalające odczytać plik konfiguracyjny, oraz CVE-2022-42745 w oprogramowaniu rekrutacyjnym [1].
W WordPressie poprawkę CVE-2021-29447 przyniosła wersja 5.7.1 z 15 kwietnia 2021 roku, opisana jako usunięcie podatności XXE w Bibliotece mediów dotyczącej PHP 8, zgłoszonej przez SonarSource [6]. WPScan podaje jako poprawione wersje 5.7.1, 5.6.3 i 5.0.12 oraz ocenę CVSS 7,5 [7]. Łatka przywróciła wywołanie libxml_disable_entity_loader() także dla PHP 8, z operatorem tłumienia błędów, żeby nie generować ostrzeżeń o wycofanej funkcji [5]. Poprawki trafiły do witryn przez aktualizację rdzenia.
Przypisy
8- [1] CWE-611: Improper Restriction of XML External Entity Reference · MITRE
- [2] XML External Entity Prevention Cheat Sheet · OWASP
- [3] A4:2017 – XML External Entities (XXE) · OWASP
- [4] libxml_disable_entity_loader — PHP Manual · The PHP Group
- [5] WordPress 5.7 XXE Vulnerability · SonarSource
- [6] WordPress 5.7.1 Security and Maintenance Release · WordPress.org
- [7] WordPress 5.6-5.7 – Authenticated XXE Within the Media Library Affecting PHP 8 · WPScan
- [8] Problemy z XXE (XML eXternal Entity) · Sekurak
Hasła w tym artykule
17- podatność
- OWASP Top 10
- CWE
- ujawnienie informacji wrażliwych
- SSRF (Server-Side Request Forgery)
- atak odmowy usługi
- skanowanie portów
- path traversal
- XML-RPC
- role i uprawnienia użytkowników
- klucze bezpieczeństwa i sole
- utwardzanie pliku wp-config.php
- WAF
- sanityzacja danych wejściowych
- koniec wsparcia dla wersji PHP
- CVSS
- aktualizacja rdzenia WordPressa