Serwer MLflow w domyślnej konfiguracji nie ma żadnego uwierzytelniania. Jeśli ktoś udostępnił go w sieci, przyjmie od dowolnej osoby polecenie wysłania żądania pod wskazany adres i odeśle jej treść odpowiedzi. Wystarczy jedno przekierowanie, żeby tym adresem stał się wewnętrzny punkt metadanych chmury, spod którego można wyciągnąć poświadczenia. Amerykańska agencja CISA wpisała tę podatność do katalogu luk wykorzystywanych w atakach i wyznaczyła instytucjom federalnym termin naprawy na 2 września. Poprawka istnieje i jest dostępna od końca lipca. Kto jednak zajrzy na stronę ostrzeżenia w repozytorium MLflow, przeczyta, że wersji z poprawką nie ma.
Punkt końcowy, który nie pyta o hasło i odsyła treść odpowiedzi
MLflow to jedno z podstawowych narzędzi zespołów uczenia maszynowego. Służy do śledzenia eksperymentów i prowadzenia rejestru modeli, a dziś opisuje się także jako platforma dla agentów i dużych modeli językowych. Uruchomiony poleceniem mlflow server, bez dodatkowej konfiguracji, nie ma żadnego uwierzytelniania.
Problem siedzi w powiadomieniach o zdarzeniach w rejestrze modeli. MLflow potrafi wysłać takie powiadomienie pod adres wskazany przez użytkownika, a do sprawdzenia, czy adres działa, ma osobne polecenie testowe. Na domyślnym serwerze to polecenie jest dostępne bez logowania.
Kluczowa jest jedna właściwość testu. Odpowiedź serwera zawiera kod stanu oraz całą treść tego, co przyszło z drugiej strony. Napastnik nie musi więc niczego zgadywać ani wnioskować z czasu odpowiedzi. Dostaje zawartość wprost. Luka ma ocenę 9,3 w dziesięciostopniowej skali powagi, czyli poziom krytyczny.
Warto wyjaśnić, czym jest wspomniany punkt metadanych, bo na nim opiera się cały sens tego ataku. Maszyny wirtualne u dużych dostawców chmury mają dostęp do wewnętrznego adresu, spod którego pobierają informacje o samych sobie. Jeżeli maszyna ma przypisaną rolę, pod tym samym adresem leżą też tymczasowe poświadczenia do niej. Z zewnątrz nie da się tam zajrzeć, bo adres działa wyłącznie z wnętrza maszyny. Kiedy więc napastnik zmusza serwer, żeby sam odpytał ten adres i odesłał wynik, może w ten sposób dostać klucze do zasobów, z których serwer korzysta.
Zabezpieczenie sprawdzało adres i zaraz o nim zapominało
Najciekawsze jest to, że zabezpieczenie przed takim nadużyciem w MLflow było. Dodano je wcześniej, w wydaniu 3.10.0. Funkcja sprawdzająca rozwiązuje nazwę z adresu podanego przez użytkownika i odrzuca wszystko, co wskazuje na adresy prywatne, pętlę zwrotną albo zakres metadanych chmury.
Zawiodło połączenie dwóch drobiazgów. Po pierwsze, funkcja sprawdzająca po wykonaniu swojej pracy wyrzuca ustalony adres. Nie przekazuje go dalej, więc właściwe żądanie rozwiązuje nazwę jeszcze raz. Robi to samodzielnie i bez żadnej pamięci o kontroli. Po drugie, moduł dostarczający powiadomienia nie wyłącza podążania za przekierowaniami.
Z tego wychodzą dwie drogi obejścia. Prostsza polega na tym, że napastnik podaje własny, publiczny adres. Kontrolę przechodzi on bez zarzutu, a w odpowiedzi odsyła przekierowanie w głąb sieci ofiary. Celu przekierowania nikt już nie sprawdza. Druga droga jest subtelniejsza i korzysta z tego, że obie operacje pytają serwer nazw niezależnie. Odpowiedź może się więc między nimi zmienić. Zgłaszający zwrócił przy tym uwagę na rzecz, która boli najbardziej. MLflow miał już zabezpieczenie przed tą drugą sztuczką, tyle że założone na ruch przychodzący, a nie na własne żądania wychodzące.
Poprawka wyszła 31 lipca, a strona ostrzeżenia nadal jej nie widzi
Tu zaczyna się część praktyczna i to jest jedyna rzecz, którą trzeba zapamiętać. Strona ostrzeżenia bezpieczeństwa w repozytorium MLflow, czyli miejsce, do którego prowadzą wszystkie odnośniki, w odczycie z wieczora 20 sierpnia podawała w rubryce wersji poprawionych słowo “brak”. W rubryce wersji podatnych stało “3.13.0 i starsze”. Oba pola wprowadzają w błąd.
Sprawdziliśmy to na kodzie, nie na opisie. Poprawka została scalona 2 lipca i dokłada do projektu nowy moduł. Jego zadaniem jest przypięcie sprawdzonego adresu do połączenia. Ten plik znajduje się w wydaniu 3.15.0 z 31 lipca. Pod znacznikiem poprzedniego wydania, czyli 3.14.0 z 17 czerwca, tego pliku nie ma. Porównanie historii zmian potwierdza, że poprawki tam nie było. Wersja 3.14.0 jest więc podatna, choć rubryka na stronie ostrzeżenia jej nie obejmuje.
Amerykańska baza podatności i globalny rejestr GitHuba podają to zgodnie i inaczej niż strona projektu. Dotknięte są wszystkie wydania poniżej 3.15.0, a pierwszym poprawionym jest właśnie 3.15.0. Najnowsze dostępne wydanie to 3.15.1 z 3 sierpnia. Praktyczny wniosek jest prosty. Administrator, który w sierpniu zajrzał na stronę ostrzeżenia, mógł w dobrej wierze uznać, że nie ma czego wdrażać.
Od publicznego zgłoszenia do katalogu CISA minęły 54 dni
Wbrew pierwszemu wrażeniu nie mamy tu do czynienia z luką, którą ktoś ukrywał. Historia jest odwrotna i przez to bardziej pouczająca.
Podatność opisano publicznie w otwartym zgłoszeniu w repozytorium MLflow 26 czerwca, z analizą konkretnych funkcji i wskazaniem obu dróg obejścia. Projekt zareagował szybko i poprawka trafiła do kodu 2 lipca, czyli po sześciu dniach. Wydanie z poprawką wyszło 31 lipca, a formalne ostrzeżenie w repozytorium 2 sierpnia. Rekord w międzynarodowym katalogu podatności opublikowano dopiero 17 sierpnia. Tego samego dnia wpis pojawił się w bazie amerykańskiego instytutu oraz w globalnym rejestrze GitHuba. Dwa dni później podatność wylądowała w katalogu CISA, z terminem naprawy dla instytucji federalnych wyznaczonym na 2 września.
Katalog CISA nie jest listą rzeczy groźnych w teorii. Trafiają do niego luki, dla których agencja ma dowody wykorzystania w atakach. Między publicznym opisem problemu a tym momentem minęły 54 dni. Przez ostatnie 19 z nich poprawka była już do pobrania. Warto też zwrócić uwagę na to, do czego CISA odsyła w swoim wpisie. Nie do komunikatu producenta, tylko wprost do czerwcowego zgłoszenia i do poprawki. Opis mechanizmu był więc jawny od czerwca, a gotowa poprawka od końca lipca. Przy takim układzie ochronę daje wyłącznie faktyczna aktualizacja serwera, a nie samo istnienie wydania z łatką.
Trzeci produkt ze stosu uczenia maszynowego w katalogu w tym miesiącu
MLflow jest jedynym wpisem dodanym do katalogu 19 sierpnia, ale nie jedynym z tej rodziny narzędzi w sierpniu. Dwa dni wcześniej dopisano Ray, o którym pisaliśmy przy okazji jego wejścia do tego katalogu. Na początku miesiąca doszedł kolejny wpis dotyczący Langflow, który w tym katalogu gości regularnie.
Trzy różne produkty ze stosu uczenia maszynowego w piętnaście dni to już nie przypadek i warto zaryzykować interpretację. Wspólną cechą tych narzędzi jest domyślna konfiguracja bez uwierzytelniania, wygodna wtedy, gdy wszystko stoi na jednej maszynie w zaufanym otoczeniu. Kłopot zaczyna się, kiedy to samo narzędzie obrasta rolami, kluczami i dostępem do danych.
Przy MLflow trzeba wyraźnie odrzucić pocieszającą interpretację, że dotyczy to laboratorium badacza albo pojedynczej maszyny. Serwer śledzący eksperymenty bywa wystawiony w sieci firmowej, żeby cały zespół mógł do niego zaglądać, bywa też uruchamiany w chmurze. Łupem są przy tym poświadczenia chmurowe, więc skutek nie kończy się na samym serwerze. Ile takich instancji jest wystawionych, nie podaje żadne dostępne źródło. Lepiej nie wypełniać tej luki zgadywaniem.
Pierwsza Misja AI · Kodożercy
Używasz AI codziennie, ale czy robisz to dobrze?
Kurs Pierwsza Misja AI pokazuje techniki promptowania, które naprawdę działają. Praktyczne ćwiczenia na działającym modelu, gamifikacja i certyfikat na koniec.
Sprawdź program kursu →

Najczęstsze pytania
Czy luka w MLflow dotyczy serwera dostępnego tylko w sieci firmowej?
Tak, choć droga ataku jest wtedy inna. Podatność polega na tym, że serwer wysyła żądania w swoim imieniu, a napastnik czyta odpowiedzi. Do wykorzystania potrzebuje możliwości wywołania testu powiadomienia. W sieci wewnętrznej wystarczy do tego dostęp z dowolnej stacji roboczej albo z innej przejętej wcześniej usługi. Sensem tej luki jest właśnie sięganie po zasoby niedostępne z zewnątrz. Umiejscowienie serwera w sieci wewnętrznej nie jest tu więc argumentem uspokajającym.
Jak sprawdzić, czy dana instalacja jest podatna?
Decyduje numer wydania. Podatne są wszystkie wersje poniżej 3.15.0, łącznie z 3.14.0, której nie wymienia rubryka na stronie ostrzeżenia. Aktualne wydanie to 3.15.1. Jeżeli aktualizacja musi poczekać, warto tymczasem odciąć dostęp do interfejsu programistycznego serwera dla ruchu spoza zaufanej sieci. Drugi krok to przejrzenie dzienników pod kątem wywołań polecenia testowego powiadomień.
Podsumowanie
Luka w MLflow pokazuje, że szybka reakcja na zgłoszenie nie kończy sprawy. Opis podatności był publiczny od czerwca, poprawka powstała w sześć dni, a wydanie z nią wyszło pod koniec lipca, i mimo to podatność trafiła w sierpniu do katalogu CISA. Słabym ogniwem okazał się przepływ informacji do osób, które te serwery utrzymują. Strona ostrzeżenia podaje, że poprawionej wersji nie ma, i pomija jedno podatne wydanie, więc sumienne sprawdzenie źródła prowadzi do złego wniosku. Kto ma u siebie MLflow starszy niż 3.15.0, ma do wykonania aktualizację i nie stoi przed żadną decyzją. Reszta liczb krążących wokół tej sprawy, łącznie z rzekomą liczbą wystawionych serwerów, nie ma źródła pierwszej ręki i lepiej jej nie powtarzać.
Newsletter · DevstockAcademy & Kodożercy
Bądź na bieżąco ze światem IT, AI i automatyzacji
Co wtorek: newsy z branży, praktyczne tipy i narzędzia które warto znać. Zero spamu.




