RFI (Remote File Inclusion)
| Po angielsku | remote file inclusion (RFI) |
|---|---|
| Którą formą pisać | po angielsku Polski odpowiednik istnieje, ale w praktyce nikt tak nie pisze. Zostaw angielski, polski trzymaj jako synonim. |
| Inne formy | Remote File Inclusion · dołączenie pliku zdalnego · zdalne dołączanie plików |
| Kategoria | Podatności i klasy błędów |
RFI (Remote File Inclusion) to podatność aplikacji PHP, w której instrukcja include albo require dołącza plik wskazany przez atakującego z zewnętrznego serwera i wykonuje go jak własny kod. MITRE opisuje ją jako sytuację, w której aplikacja PHP przyjmuje dane z zewnątrz i nie ogranicza ich albo ogranicza błędnie, zanim użyje ich w require, include lub podobnych funkcjach [1]. Skutkiem jest możliwość wskazania adresu URL, z którego PHP pobierze i wykona kod [1]. RFI jest bliską krewną LFI (Local File Inclusion); obie należą do rodziny błędów dołączania plików [2].
Jak działa
W PHP instrukcja include wczytuje wskazany plik i przetwarza go jako skrypt. Dokumentacja języka wyjaśnia, że gdy włączone są tak zwane URL include wrappers, plik do dołączenia można podać jako adres URL zamiast ścieżki lokalnej [4]. Plik zdalny musi przy tym dawać poprawny skrypt PHP, bo zostanie przetworzony na serwerze lokalnym [4]. Właśnie to zachowanie wykorzystuje RFI.
Podatność powstaje według OWASP wtedy, gdy strona przyjmuje jako parametr ścieżkę pliku do dołączenia i nie oczyszcza jej, więc da się wstawić zewnętrzny adres [2]. Zdalny plik zostaje dołączony, a zawarty w nim kod wykonuje serwer [2]. Przebieg pokazuje schemat poniżej.
Mechanizm widać na przykładzie. Pierwsza linia dołącza plik o nazwie wziętej wprost z żądania. Druga część zamienia parametr na identyfikator z listy dozwolonych plików, tak jak zaleca OWASP [2].
// podatne: nazwa pliku z parametru trafia do include
include $_GET['strona'] . '.php';
// bezpieczne: tylko pliki z listy dozwolonych
$dozwolone = array( 'kontakt' => 'kontakt.php', 'onas' => 'onas.php' );
$klucz = isset( $_GET['strona'] ) ? sanitize_key( $_GET['strona'] ) : '';
if ( isset( $dozwolone[ $klucz ] ) ) {
include __DIR__ . '/szablony/' . $dozwolone[ $klucz ];
}
Warunki w konfiguracji PHP
Dołączanie plików przez URL zależy od dwóch dyrektyw. Dyrektywa allow_url_fopen włącza obsługę adresów URL w funkcjach plikowych i domyślnie ma wartość 1 [3]. Dyrektywa allow_url_include pozwala używać tych adresów w include, include_once, require i require_once; domyślnie ma wartość 0 i wymaga włączonego allow_url_fopen [3]. Od PHP 7.4.0 allow_url_include jest oznaczona jako przestarzała [3]. Obie dyrektywy mają tryb INI_SYSTEM, więc nie da się ich zmienić z poziomu skryptu [3].
| Cecha | RFI | LFI |
|---|---|---|
| Skąd plik | z serwera atakującego [1] | z dysku ofiary [1] |
| Warunek w PHP | włączone allow_url_include [3] | nie wymaga dostępu do URL [1] |
| Typowe wzmocnienie | brak | path traversal [1] |
| Kod do wykonania | dostarczony z zewnątrz [1] | wcześniej wstrzyknięty do pliku lokalnego [1] |
MITRE zauważa, że LFI występuje, gdy pobieranie zdalne jest wyłączone albo atakujący przez przechodzenie ścieżek sięga do pliku, w którym wcześniej umieścił kod PHP [1]. Wyłączenie allow_url_include zamyka więc drogę RFI, ale nie usuwa samego błędu w kodzie.
W WordPressie
W ekosystemie WordPressa RFI pojawia się w kodzie wtyczek i motywów, a nie w rdzeniu; zob. podatność we wtyczce. Jeden z wzorców błędu to plik wtyczki, który ścieżkę do katalogu WordPressa bierze z parametru żądania, zamiast z bezpiecznej stałej.
Przykładem jest wtyczka Canto. Według GitHub Advisory Database wersje do 3.0.4 włącznie były podatne na RFI przez parametr wp_abspath [5]. Nieuwierzytelniony atakujący mógł wykonać zdalny kod, jeśli na serwerze włączono allow_url_include, a przy wyłączonej dyrektywie dołączyć lokalnie wcześniej wgrany plik PHP [5]. Luce przypisano wynik CVSS 9,8 i słabość CWE-98 [5]. Był to więc przypadek podatności wykorzystywanej bez uwierzytelnienia, w którym jedna błędnie użyta zmienna prowadzi do wgrania dowolnego pliku lub wykonania kodu.
Ryzyko rośnie przy porzuconych wtyczkach, których nikt już nie poprawia, i na starych instalacjach PHP. Znaczenie ma też hosting współdzielony, gdzie właściciel strony zwykle nie kontroluje pliku php.ini.
Zagrożenia i skutki
MITRE podaje, że atakujący może wskazać dowolny kod do wykonania ze zdalnej lokalizacji [1]. W praktyce oznacza to zdalne wykonanie kodu (RCE) z uprawnieniami procesu serwera WWW. OWASP wymienia jako możliwe skutki błędów dołączania plików [2]:
- wykonanie kodu na serwerze WWW,
- wykonanie kodu po stronie klienta, na przykład JavaScriptu, co prowadzi do XSS (Cross-Site Scripting),
- odmowę usługi,
- ujawnienie informacji wrażliwych.
Dołączony kod zwykle służy do umieszczenia na serwerze webshella, który zostaje po załataniu pierwotnej luki. Dlatego po wykryciu RFI samo usunięcie wtyczki nie wystarcza.
Jak się bronić
OWASP za najskuteczniejsze rozwiązanie uznaje niepodawanie danych od użytkownika do żadnego API systemu plików [2]. Gdy to niemożliwe, aplikacja powinna utrzymywać listę dozwolonych plików i odwoływać się do nich przez identyfikator, a żądania z nieznanym identyfikatorem odrzucać [2]. MITRE zaleca podobnie strategię akceptowania tylko znanych dobrych wartości [1].
Warstwa konfiguracji dopełnia poprawny kod. MITRE zaleca ustawienie allow_url_fopen na wartość wyłączoną, co ogranicza dołączanie plików ze zdalnych lokalizacji, oraz trzymanie plików bibliotek poza katalogiem głównym serwera WWW, jeśli to możliwe [1].
; php.ini — brak dołączania plików przez URL
allow_url_fopen = Off
allow_url_include = Off
Wyłączenie allow_url_fopen może zepsuć wtyczki pobierające dane z sieci funkcjami plikowymi, więc zmianę warto sprawdzić na środowisku testowym. Dalsze warstwy to blokada wykonywania PHP w katalogu uploads, która utrudnia wariant lokalny, WAF filtrujący parametry z adresami URL oraz sanityzacja danych wejściowych we własnym kodzie.
Historia i przykłady
Błędy dołączania plików w PHP są znane od lat. Wśród przykładów obserwowanych w słabości CWE-98 MITRE wymienia zgłoszenia z 2002 roku, takie jak CVE-2002-1704 i CVE-2002-1707, oraz serię z 2005 roku [1]. Wśród zaleceń dla tej słabości MITRE wymienia też wyłączenie dyrektywy register_globals i rezygnację z jej emulowania w kodzie [1]. Nowszym przypadkiem z WordPressa jest opisana wyżej luka CVE-2023-3452 we wtyczce Canto, dodana do GitHub Advisory Database 12 sierpnia 2023 roku [5].
Przypisy
5- [1] CWE-98: Improper Control of Filename for Include/Require Statement in PHP Program ('PHP Remote File Inclusion') · MITRE
- [2] Testing for Remote File Inclusion — Web Security Testing Guide v4.2 · OWASP
- [3] Filesystem and Streams Configuration Options (allow_url_fopen, allow_url_include) · The PHP Group
- [4] include — PHP Manual · The PHP Group
- [5] CVE-2023-3452: The Canto plugin for WordPress is vulnerable to Remote File Inclusion (GHSA-r7j9-2qv5-fpm9) · GitHub Advisory Database
Hasła w tym artykule
18- podatność
- LFI (Local File Inclusion)
- path traversal
- podatność we wtyczce
- CVSS
- podatność wykorzystywana bez uwierzytelnienia
- wgranie dowolnego pliku (arbitrary file upload)
- porzucona wtyczka
- hosting współdzielony
- zdalne wykonanie kodu (RCE)
- XSS (Cross-Site Scripting)
- atak odmowy usługi
- ujawnienie informacji
- webshell
- środowisko testowe
- blokada wykonywania PHP w katalogu uploads
- WAF
- sanityzacja danych wejściowych