Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book

Jenkins łata krytyczne luki… po raz kolejny

29 stycznia 2024, 14:29 | W biegu | 0 komentarzy

Deweloperzy Jenkinsa opublikowali kolejną wersję ich flagowego narzędzia, która łata dziewięć podatności. Jedna z nich otrzymała identyfikator CVE-2024-23897 i zgodnie z opublikowaną notką oceniana jest jako krytyczna, bo pozwala na odczyt dowolnych plików przez tekstowy interfejs użytkownika, a w najgorszym przypadku może prowadzić do zdalnego wykonania kodu (RCE). Na blogu Sonara pojawił się wyczerpujący raport opisujący techniczne aspekty podatności. 

Jenkins oferuje różne poziomy autoryzacji, od niezabezpieczonego dostępu zezwalającego na wykonywanie akcji użytkownikom, którzy się nie zalogowali po szczegółowe ACLe definiowane w macierzy (zwane matrix-based security). Dodatkowo, możliwe jest zezwolenie na dodawanie nowych kont w systemie przez opcję “Allow users to sign up”, co umożliwia uzyskanie dostępu “read only” do zasobów jenkinsa. 

Krytyczna luka sklasyfikowana jako CVE-2024-23897 wykorzystuje funkcjonalność związaną z CLI. Wszystkiemu winna jest biblioteka args4j, która odpowiada za parsowanie argumentów podczas korzystania z CLI. Jedną z cech tej biblioteki jest zastępowanie znaku małpy (“@”) zawartością pliku (expandAtFiles). Opcja ta jest domyślnie włączona dla Jenkinsa w wersji do 2.441 w głównej gałęzi oraz do wersji 2.426.2 w gałęzi z rozszerzonym wsparcie (LTS). Działanie metody expandAtFiles dobrze ilustruje grafika załączona w oryginalnym poście Sonara:

W momencie wykrycia symbolu ‘@’, wskazany plik jest czytany linia po linii i umieszczany w jako kolejne argumenty.

CLI Jenkinsa używać można z wykorzystaniem SSH, javowej binarki czy też poprzez dwa zapytania POST do endpointu http://jenkins/cli?remoting=false. Jak łatwo się domyślić pierwsze zapytanie POST wywołuje komendę (tzw. uploader) a drugie pobiera jej wyniki (tzw. downloader). Gdy komponent odpowiedzialny za uruchamianie komend natrafi na odpowiednią metodę ze ścieżki /cli rzucany jest wyjątek, który kończy się wywołaniem metody generateResponse:

public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
    try {
        UUID uuid = UUID.fromString(req.getHeader("Session"));
        //...
        if (req.getHeader("Side").equals("download")) {
            FullDuplexHttpService service = createService(req, uuid);
            //...
            try {
                service.download(req, rsp);
            }
            //...
        } else {
            FullDuplexHttpService service = services.get(uuid);
            //...
            try {
                service.upload(req, rsp);
            }
            //...
}
}

Znajdując komendę, która zwraca w odpowiedzi wywołane argumenty można poznać zawartość plików takich jak /etc/passwd czy kluczy SSH. Badacze prezentują podatność na komendzie connect-to-node, która wymaga dodatkowych uprawnień do wykonania. Ale ponieważ wyjątek w obsłudze polecenia zostaje rzucony wcześniej i generowana jest odpowiedź zawierająca treść odczytywanego pliku (każda linia rozwinięta do kolejnego argumentu polecenia) jako kolejne argumenty, to atakujący nie musi dysponować uprawnieniami do wykonania operacji CONNECT. PoC został opublikowany np. tu

Atakujący posiadający uprawnienia Overall/Read jest w stanie poznać zawartość dowolnych całych plików znajdujących się na atakowanym systemie (arbitrary file read). W przypadku braku tego uprawnienia wciąż jest możliwe odczytanie pierwszych kilku linii plików. Działania te nie są ograniczone tylko do zasobów tekstowych i atakujący jest w stanie zapoznać się również z plikami binarnymi (np. zawierającymi klucze kryptograficzne). 

W zależności od warunków, podatność ta może prowadzić do zdalnego wykonania kodu, chociaż jest to sytuacja obwarowana kilkoma założeniami. W opublikowanym biuletynie bezpieczeństwa zaproponowano kilka scenariuszy, chociaż jak stwierdza zespół Jenkinsa nie jest to lista wyczerpująca problem.

  1. Zdalne wykonanie kodu przez główny URL zasobów (resource root URL). Wymagania:
  • funkcja “Resource Root URL” jest włączona
  • atakujący jest w stanie odczytywać zawartość plików binarnych
  • dostępny jest endpoint WebSocket dla interfejsu wiersza poleceń (co oznacza, że Jenkins działa na serwerze Jetty) 
  • atakujący jest w stanie odgadnąć nazwę użytkownika z uprawnieniami Overall/Read
  • alternatywnie zamiast podpunktu C i D atakujący jest w stanie pozyskać token API dla zdefiniowanego (non-anonymous) użytkownika. W tym przypadku uprawnienie Overall/Read nie jest wymagane

2. Zdalne wykonanie kodu przez ciasteczko “zapamiętaj mnie” – podrobienie zawartości ciasteczka “zapamiętaj mnie” pozwala zalogować się do interfejsu webowego Jenkinsa. Stamtąd droga do RCE jest już bardzo prosta, pod warunkiem że uda się pozyskać ciasteczko dla konta z uprawnieniami administratora. 

  • funkcja “remember me” jest włączona (jest to ustawienie domyślne)
  • atakujący może czytać pliki binarne
  • atakujący ma uprawnienia Overall/Read aby odczytywać pełną zawartość plików

3. Zdalne wykonanie kodu przez stored XSS w logach budowania aplikacji. 

  • atakujący kontroluje build log (np. przez pull request)
  • atakujący może czytać pliki binarne

4. RCE przez obejście zabezpieczenia CSRF. Cross-Site Request Forgery token, to ciąg znaków zabezpieczających przed możliwością wykonania tzw. one-click attack czyli zmuszenia przeglądarki ofiary do wykonania zapytania do podatnej aplikacji (np. przez spreparowany tag img).

  • atakujący może czytać pliki binarne
  • identyfikator sesji webowej nie jest częścią CSRF (domyślnie jest)

5. Odczytywanie sekretów przechowywanych w Jenkinsie

  • Resource Root URL jest włączone 
  • atakujący może czytać pliki binarne
  • atakujący zna/odgaduje nazwę użytkownika z uprawnieniami Overall/Read. 

6. Pobranie zrzutu obiektów z pamięci JVM (Java heap dump) procesu kontrolera Jenkinsa lub dowolnego agenta

  • Resource Root URL jest włączone
  • Atakujący może czytać binarne pliki
  • Atakujący zna/odgaduje nazwę użytkownika z uprawnieniami Overall/Read

Jak widać obostrzeń jest sporo (odczytywanie plików binarnych też jest ograniczone), ale sposobów wykonania kodu na zdalnym systemie nie jest mało. Zaproponowane rozwiązanie problemu wyłącza funkcję parsera argumentów, która podmienia znak “@” na zawartość pliku.

Administratorom i użytkownikom pozostaje pilna aktualizacja Jenkinsa i trzymanie ręki na pulsie. 

Oprócz tej krytycznej luki notka zawiera też inne podatności sklasyfikowane jako HIGH w tym arbitrary file read przez plugin git (CVE-2024-23898). 10 miesięcy temu Jenkins łatał też inne metody uzyskania RCE. 

~fc

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



Komentarze

Odpowiedz