Hak PHP w OpenVPN: trusted_ip kontra ifconfig_pool_remote_ip
Dwa adresy o dwóch różnych znaczeniach, czytane przez proces, którego nie uruchomiłeś. Czym są zmienne haka i dlaczego pusta $_ENV niczego nie dowodzi.
Pusta tablica $_ENV w skrypcie haka wygląda jak dowód, że OpenVPN nic nie przekazał. Zwykle dowodzi czegoś zupełnie innego: PHP był skonfigurowany tak, by nie wypełniać tej superglobalnej, a wartości przez cały czas siedziały w środowisku procesu. Drugi błędny wniosek jest subtelniejszy, bo dwie zmienne adresowe w haku połączenia znaczą różne rzeczy i bywają używane zamiennie. Oba błędy kosztują popołudnie, jeśli zaczniesz od niewłaściwego.
Dwa adresy, dwa różne twierdzenia
Zewnętrzny punkt końcowy to to, co serwer zaobserwował przy połączeniu klienta, dostępny jako trusted_ip dla IPv4 i trusted_ip6 dla IPv6. Adres wirtualny to to, co pula przydzieliła tej sesji, dostępny jako ifconfig_pool_remote_ip.
Odpowiadają na różne pytania, a rekord zwykle potrzebuje jednego z nich, nie obu. Pierwszy mówi, skąd przyszło połączenie, co może być współdzielonym adresem NAT używanym przez setki osób. Drugi mówi, gdzie ta sesja mieszka wewnątrz tunelu, i może zostać przydzielony innej sesji później. Mieszanie obu daje rekordy, które wyglądają wiarygodnie i są błędne.
Minimalny odczyt wygląda tak.
$outer4 = getenv('trusted_ip');
$outer6 = getenv('trusted_ip6');
$inner = getenv('ifconfig_pool_remote_ip');
$outer = $outer4 !== false ? $outer4 : $outer6;Żadna wartość nie identyfikuje osoby. Jedna jest obserwacją sieciową, druga dzierżawą, a rekord, który traktuje którąkolwiek z nich jako stały identyfikator urządzenia, będzie błędny za pierwszym razem, gdy klient połączy się ponownie z innej sieci lub otrzyma inny adres z puli. Wybierz pole według pytania, na które rekord ma odpowiadać, a potem zapisz to pytanie obok kolumny.
Sprawdź, jak uruchomiono PHP, a nie swoją powłokę
Hak działa jako dziecko demona VPN ze środowiskiem, które demon buduje. Twoja powłoka interaktywna ma inne, a uruchamianie skryptu ręcznie testuje środowisko powłoki, nie haka.
Zacznij od potwierdzenia, że hak faktycznie zadziałał na etapie, którego oczekiwałeś. Skrypt podpięty do niewłaściwego etapu albo taki, który nigdy nie ruszył, bo dyrektywa wskazuje inną ścieżkę, daje dokładnie ten sam objaw co brakująca zmienna. Dodaj celową linię znacznika na górze skryptu i potwierdź, że się pojawia, zanim sprawdzisz cokolwiek innego. Jedna linia z sygnaturą czasu w logu oddziela „nigdy nie ruszył” od „ruszył bez wartości”.
Następnie potwierdź, którego interpretera i którego pliku konfiguracyjnego używa to wywołanie. Edycja konfiguracji PHP dla serwera WWW nic nie zmienia w procesie CLI uruchomionym przez OpenVPN, a oba mogą wczytać zupełnie różne pliki php.ini.
Dlaczego pusta $_ENV niczego nie dowodzi
PHP dokumentacja getenv opisuje bezpośredni odczyt środowiska procesu, który zwraca false, gdy nazwy nie ma. Superglobalna $_ENV jest wypełniana osobno, a dyrektywa variables_order decyduje, które superglobalne zostaną wypełnione.
Jeśli ta dyrektywa pomija E, $_ENV pozostaje pusta niezależnie od tego, co zawiera środowisko. Kod, który ją indeksuje, zgłasza wtedy brakującą zmienną, która w rzeczywistości jest, a śledztwo idzie w stronę OpenVPN, gdy odpowiedź leży w php.ini. Sprawdź dyrektywę konkretnie dla konfiguracji CLI, nie dla serwera WWW.
Odczyt przez getenv pozwala uniknąć całego tego zamieszania, a skrypt-opakowanie, który czyści środowisko przed wywołaniem interpretera, wprowadza je z powrotem w innej formie.
Przechowuj skojarzenie, nie aktualizację wiersza
Zdecyduj, jakiej wartości potrzebuje rekord, zanim ją zapiszesz. Jeśli celem jest odnotowanie, skąd przyszła sesja, zapisz zewnętrzny punkt końcowy i oznacz go jako obserwację. Jeśli celem jest powiązanie sesji z adresem tunelu na czas połączenia, zapisz adres z puli i powiąż go z sesją.
Aktualizuj według uwierzytelnionej tożsamości i bieżącej sesji, a nie według każdego wiersza dzielącego adres tunelu, bo adresy z puli są używane ponownie i spóźnione zdarzenie rozłączenia może nadpisać dane nowszego połączenia. Obsługuj IPv6 jawnie, zamiast po cichu zapisywać tylko wartość IPv4. Wiersz z NULL w adresie zewnętrznym jest lepszy niż wiersz z błędnym, bo pierwszy jest widocznie niekompletny.
Powiąż zapis z identyfikatorem sesji, który podaje OpenVPN, aby ponowne połączenie tworzyło nowy rekord, a nie edytowało starego. Używaj instrukcji parametryzowanych i konta z tylko tymi uprawnieniami, których wymaga operacja. Hak działa z uprawnieniami demona, więc nieostrożne zapytanie to szerszy problem niż błędna linia logu.
Diagnozuj bez zrzucania środowiska
Zapisuj w logu, które nazwy były obecne, który etap się wykonał i który interpreter został użyty. Nie wypisuj całego środowiska, bo proces haka może odziedziczyć niepowiązane wartości, które nie powinny trafić do pliku logu.
Zweryfikuj jedno połączenie od początku do końca: odczytaj zewnętrzny punkt końcowy, odczytaj przydzielony adres i potwierdź oba wobec własnego widzenia tej sesji przez serwer. Gdy para jest potwierdzona dla jednego klienta, skojarzeniu można ufać gdzie indziej.