Sprawdź szkolenie NIS2 dla zarządów od sekuraka.

Probllama – RCE w znanym projekcie do uruchamiania modeli LLM

25 czerwca 2024, 20:21 | W biegu | komentarze 3

Boom na LLM spowodował olbrzymią popularność nie tylko chatów online, udostępnionych przez firmy trzecie, ale także rozwiązań pozwalających na korzystanie z modeli obsługiwanych lokalnie. Jednym ze sposobów dystrybucji i uruchamiania popularnych modeli takich jak np. LLama od firmy Meta jest projekt Ollama, który pokazywaliśmy na szkoleniu z Narzędziownika AI w części III.

Duża popularność Ollamy i jej workflow zbliżony do tego znanego z Dockera, powoduje, że projekt ten stał się bardzo popularny ostatnimi czasy, ponieważ pozwala na niemal bezobsługową konfigurację i uruchomienie dużych modeli językowych. Badacze z Wiz.io opisali lukę okrzykniętą mianem Probllama skatalogowaną jako CVE-2024-37032, która została załatana od wersji 0.1.34 włącznie

Oprogramowanie składa się z dwóch części. Serwera udostępniającego wiele interfejsów programistycznych oraz klienta, który pełni rolę interfejsu użytkownika (np. w postaci binarki oferującej tekstowy interfejs użytkownika). Krytyczna luka wynika z niedostatecznej walidacji zapytań kierowanych do API, co w konsekwencji prowadzi do podatności typu path traversal. Możliwość dostępu do dowolnych plików, w tym zapis do nich, pozwala eskalować podatność do zdalnego wykonania kodu. Oprogramowanie Ollama, w domyślnej konfiguracji nie posiada interfejsu uwierzytelnienia użytkownika, co powoduje, że atakujący nie musi mieć żadnych uprawnień, aby lukę wykorzystać. Wystarczy, że natknie się na dostępny w sieci endpoint. 

Ale właściwie jak odnaleziono path traversal? Ollama umożliwia pobieranie (ang. pulling) modeli ze zdalnych repozytoriów (podobnie jak Docker pozwala na pobieranie obrazów). Modele umieszczone są w rejestrze (ang. registry). Użytkownicy końcowi domyślnie korzystają z publicznego rejestru znajdującego się pod adresem registry.ollama.com. Ale aplikacja daje możliwość pobrania modelu z prywatnego repozytorium (co może być przydatne jeśli np. firma korzystająca z modeli LLM dokonuje fine-tuningu modeli pod swoje potrzeby). Odpowiednio spreparowany manifest zawierający pole digest, może zostać wykorzystany do zapisania dowolnego pliku na dysku. Dzieje się tak dlatego, że parametr digest, wykorzystywany jest między innymi do przechowywania ścieżki zapisywanego modelu. 

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
  "config": {
    "mediaType": "application/vnd.docker.container.image.v1+json",
    "digest": "../../../../../../../../../../../../../../../../../../../traversal",
    "size": 5
  },
  "layers": [
    {
      "mediaType": "application/vnd.ollama.image.license",
      "digest": "../../../../../../../../../../../../../../../../../../../../../traversal",
      "size": 7020
    }
  ]
}

Listing 1.1. PoC wskazujący gdzie zapisać pobrany plik (źródło: wiz.io)

Spreparowany manifest, w momencie wykonania operacji push, która ma na celu wypchnięcie modelu do zdalnego repozytorium, powoduje, że usługa serwera wysyła do rejestru zawartość pliku wskazywanego przez digest. W efekcie atakujący uzyskuje możliwość przeczytania dowolnego pliku na serwerze (ang. arbitrary file read). 

Zapis danych przez błąd opisany wyżej, pozwala na “zepsucie” zawartości poprawnych plików na dysku. Ale można tę technikę wykorzystać do znacznie bardziej niebezpiecznych działań. Domyślnie serwer ollama nasłuchuje tylko na lokalnym interfejsie pętli zwrotnej, co ogranicza skutek tego ataku i jest zredukowany do wykonania polecenia w kontekście użytkownika ollama. W przypadku gdy jednak użytkownik korzysta z opcji uruchomienia usługi ollama przy pomocy obrazu Dockera, to wtedy problem jest znacznie większy, ponieważ domyślne readme projektu proponuje polecenie do uruchomienia kontenera, które spowoduje, że serwer będzie uruchomiony dla adresu 0.0.0.0 – efektywnie dla każdego skonfigurowanego interfejsu. Jakby tego było mało, to oczywiście wewnątrz kontenera serwer działa jako użytkownik root. 

Rysunek 1. Oficjalna dokumentacja Ollama z Docker Hub (źródło: wiz.io)

Badacze proponują nadpisanie plików konfiguracyjnych ld.so, dynamicznego linkera odpowiedzialnego za ładowanie bibliotek współdzielonych podczas uruchamiania dowolnej binarki w systemie. Plik konfiguracyjny – /etc/ld.so.preload umożliwia podanie listy bibliotek, które mają być ładowane do pamięci procesu podczas jego startu. Wykorzystując możliwość nadpisania dowolnego pliku w systemie, można utworzyć złośliwą bibliotekę .so, a następnie zmienić konfigurację w /etc/ld.so.preload w taki sposób, aby kod był wykonywany podczas inicjacji kolejnego procesu. Okazuje się, że stworzenie takowego, jest również możliwe z poziomu api, przez wykonanie zapytania do endpointu /api/chat. 

Okazuje się, że pomimo upływu lat, podatność typu path traversal wciąż może być groźna, nawet dla najnowszej technologii jaką jest AI :) Jeśli chodzi o sposoby poradzenia sobie z tym problemem, to przede wszystkim należy dokonać aktualizacji ollama przynajmniej do wersji 0.1.34. Przy okazji warto zauważyć, że oprogramowanie to pewnie nie powinno być dostępne z sieci zewnętrznej (a być może i nawet nie jest wymagane nasłuchiwanie interfejsach innych niż localhost). Warto też rozważyć dodanie reverse proxy (np. nginx), który będzie uwierzytelniał zapytania płynące do API. 

Na podziw zasługuje fakt, że zespół deweloperski projektu naprawił podatność 4h po uzyskaniu raportu. Tak powinien przebiegać proces wydawania łatek :) 

~fc

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. Szymon

    Jak powiedział prof Zybertowicz : „Technoentuzjazm to prawdopodobnie najniebezpieczniejsza ideologia dzisiejszych czasów”

    Odpowiedz
    • teh123

      Technologia to co odróżnia człowieka od małpy, profesor niech spada na drzewo

      Odpowiedz
      • Marcin

        W sumie masz rację. Małpa nie niszczy środowiska w którym żyje.

        Odpowiedz

Odpowiedz