09.06.2016 | 10:34

Adam Haertle

Jak w łatwy sposób zainfekować 17 000 komputerów programistów

Programiści, robicie literówki? Jeśli tak, to możecie paść ofiarą banalnego i niezwykle skutecznego ataku na Wasze komputery. W ciągu trzech miesięcy zainfekowano w taki sposób ponad 17 tysięcy komputerów, w tym 170 w Polsce.

Nikolai Tschacher, student z Hamburga, w ramach swojej pracy dyplomowej wymyślił sprytny sposób infekowania komputerów programistów. Oparł go na literówkach popełnianych w trakcie próby instalacji pakietów.

Literówki, wszędzie litrówki

Od wielu lat znane są ataki polegające na rejestrowaniu domen z literówką w nazwie. Ktoś wpisuje adres swojej ulubionej strony, popełnia błąd i ląduje na zupełnie innej witrynie. Nikolai wymyślił jednak inny sposób wykorzystania literówek, wycelowany w programistów. Jak namówić programistę do zainstalowania złośliwego oprogramowania? Nie trzeba go namawiać, sam je zainstaluje. Np. zamiast

sudo pip install requests

może przecież wpisać

sudo pip install reqeusts

Na tym pomyśle Nikolai oparł swoją pracę dyplomową. Wybrał trzy repozytoria pakietów: pypi.python.org (Python), rubygems.org (Ruby) oraz npmjs.com (Node.js). Do każdego z nich pakiety może wgrywać każdy kto na taki pomysł wpadnie. Nikolai wygenerował ok. 200 pakietów, których nazwy oparł na popularnych pakietach z lekka modyfikacją. Wykorzystał

  • błędy gramatyczne / słownikowe (np. coffe zamiast coffee)
  • nazwy pakietów które są instalowane w standardowym zestawie i nie ma ich w wyżej wymienionych repozytoriach
  • błędy wynikające z rozkładu klawiatury (np. 7 zamiast u).

Oczywiście umieszczenie pakietu w repozytorium a następnie jego zainstalowanie przez ofiarę nie wystarcza – trzeba jeszcze zmusić komputer ofiary do uruchomienia złośliwego kodu zawartego w fałszywym pakiecie. Okazało się to dość proste w przypadku Pythona, trochę trudniejsze dla Node.js i możliwe w Ruby dzięki kilku sztuczkom. Po szczegóły odsyłamy do wpisu autora eksperymentu.

Życie programisty

Życie programisty

17 tysięcy ofiar

Sukces eksperymentu musiał chyba zaskoczyć jego samego. W fałszywych pakietach Nikolai umieścił proste programy które łączyły się z jego serwerem i przesyłały do niego adres IP ofiary, informacje o jej systemie operacyjnym a także uprawnieniach użytkownika. Program wyświetlał także komunikat informujący o błędzie popełnionym przez użytkownika i celu prowadzonego badania. W ciągu kilku miesięcy trwania eksperymentu Nikolai zarejestrował połączenia z 17 289 unikatowych adresów IP. 15 221 połączeń wygenerował Python, 1631 Ruby a 525 Node.js. W ponad 40% przypadków kod wykonywany był z uprawnieniami administratora. Prawie połowa połączeń pochodziła z komputerów pracujących pod kontrolą Linuksa, trochę mniej Windowsa a na trzecim miejscu uplasował się OS X.

Najpopularniejszy pakiet urllib2 został zainstalowany prawie 4 tysiące razy w ciągu zaledwie dwóch tygodni. Z 17 tysięcy adresów IP do nazwy domenowej udało się rozwiązać ponad 11 tysięcy, wśród których trafiły się domeny .GOV, .MIL a także 170 adresów z domeny .PL. Co ciekawe, Nikolai pobrał także historię wykonywanych poleceń z prawie półtora tysiąca komputerów (co wydaje się nam już poważną ingerencją w prywatność użytkowników jaka nie przystoi naukowcowi). Na tej podstawie zidentyfikował kolejne warianty literówek które można wykorzystać w następnych atakach.

Jak zapobiegać?

Jak wiadomo programiści nie przestaną robić literówek, dlatego trzeba znaleźć inne sposoby eliminacji lub ograniczenia tego rodzaju ataków. jednym z pomysłów jest wyeliminowanie możliwości uruchomienia kodu w momencie instalacji pakietu. Inną opcją jest zablokowanie możliwości rejestracji pakietów o nazwach zgodnych z najczęściej popełnianymi błędami (chociażby na podstawie analizy błędów serwera z pakietami).  Dopóki takie zmiany nie zostaną wprowadzone programistom polecamy szczególnie uważać w trakcie instalacji.

Powrót

Komentarze

  • 2016.06.09 12:38 ....

    Istnieje taka przydatna aplikacja konsolowa jak sl, skutecznie zapobiegająca literówkom przy korzystaniu z ls.

    Odpowiedz
  • 2016.06.09 12:48 Janek

    Sposób trzy – używać swojego firmowego repo do którego wszystko jest dodawane ręcznie lub półautomatycznie (auto update/fetch i ręczne zatwierdzenie zmian).

    Odpowiedz
  • 2016.06.09 13:05 xxx

    Z .bash_history wyciągał przez grep-a, nie pobierał całej listy poleceń:

    cmd = 'cat {}/.bash_history | grep -E „pip[23]? install”’

    Odpowiedz
  • 2016.06.09 16:08 wojtekk

    Python i Ruby to języki w których programiści bohatersko rozwiązują problemy nie znane w innych językach ;)

    [flame warning on]

    Odpowiedz
    • 2016.06.09 18:25 tommek

      Na przykład?

      Odpowiedz
      • 2016.06.10 00:08 michalrus

        Np. piszą typy w komentarzach, zamiast kodzie, i testują je w testach. ^.~

        Rozwiązaniem tych problemów trzeciego świata IT z lat 90-tych jest np. NixOS.

        Pozdrowionka.

        Odpowiedz
    • 2016.06.09 19:32 badger

      …za to łatwo i szybko rozwiązują problemy trudne lub uciążliwe w innych językach.
      Czyli jak prawie każdy inny język programowania :D no może poza php

      IMO powodem dla którego ten atak mógł tak dobrze zadziałać akurat na tej trójce jest tekstowa obsługa ich menadżerów pakietów: nazwy dociąganych paczek w nowym projekcie trzeba wpisać z palca w terminalu lub pliku konfiguracyjnym. Biblioteki dla C/C++ instaluje się systemowym menadżerem paczek (który jest pilnowany przez deweloperów systemu i nie będzie tak łatwo wstrzyknąć kilkuset paczek z różnymi wariantami podrobionej nazwy) lub buduje ze źródła; z kolei w takim visual studio dociąganie paczek można sobie wyklikać, bez pisania czegokolwiek

      Odpowiedz
      • 2016.06.10 11:33 king

        Tekstowy instalator nie jest tu prawdziwym problemem, ale samo repozytorium które bezkrytycznie łyka kolejne pakiety. jak programista pobiera kolejny pakiet to nawet nie jest ostrzegany że to jest pakiet świeży, i nie ma on akceptacji zaufanych osób. taki mechanizm jest stosowany w Debianie ale ze znacznie większymi obostrzeniami, i to się sprawdza.

        Lokalne repo się nie sprawdzi o tyle, bo nigdy nie wiadomo co zaciągnie się do niego z tego publicznego.

        Odpowiedz
    • 2016.06.11 11:05 Znosny Gojek

      „nieznany” piszemy łącznie, bohatyrze.

      Odpowiedz
  • 2016.06.09 21:13 a

    „ja chciałem zainstalować paczkę
    npm install poproszę-sól

    ale przez fatalne przejęzyczenie zainstalowałem
    npm install ty-stara-kur*o-zmarnowałaś-mi-dwadzieścia-lat-życia”

    http://www.wykop.pl/link/3214175/literowki-w-menadzerach-pakietow/

    Odpowiedz
    • 2016.06.09 22:46 Kacper

      Nice, ale nie było „–save”, więc „rm -rf node_modules/poproszę-sól” powinno skutkować returnem do mamusia().

      Odpowiedz
  • 2016.06.09 23:53 Filip

    „Nikolai pobrał także historię wykonywanych poleceń z prawie półtora tysiąca komputerów (co wydaje się nam już poważną ingerencją w prywatność użytkowników jaka nie przystoi naukowcowi).”

    Nikolai UKRADŁ historię wykonywanych poleceń z 1,5k kompów, po uprzednim włamaniu. Jeśli władze uczelni uznały mu tą pracę, to ręce opadają… To trochę tak, jakbym ja się włamał do 300 aut i przejrzał zainstalował gps w nich, a potem na podstawie koordynatów ustalil gdzie najlatwiej zajumac auto. I tytul naukowy poproszę!!!

    Odpowiedz
    • 2016.06.10 21:31 Marcin

      Zaraz zaraz, to nie tak, jakbyś włamał się do 300 aut, tylko tak, jakbyś został pomyłkowo zaproszony do wnętrza 300 aut przez ich roztargnionych właścicieli, przytrzymujących Ci jeszcze drzwi, żeby Ci się łatwiej wsiadało.

      Odpowiedz
  • 2016.06.10 08:38 Daniel

    Po co taka długa ścieżka?

    rm -rf /

    Odpowiedz
    • 2016.06.10 19:33 xxx

      Zapominałeś dodać sudo:
      sudo rm -rf /
      Wykonanie polecenia do końca może zająć trochę czasu ale przynajmniej będziesz maił 100% pewność, że nie masz w systemie zbędnych pakietów.

      Odpowiedz
  • 2016.06.11 06:56 adf88

    Zapewne repozytoriom tym potrzebny jest mechanizm podobny do tego funkcjonującego w repozytoriach pakietów systemowych. Podział na mniejsze, podpisywane cyfrowo repozytoria. Jedno bądź kilka głównych, zaufanych repozytoriów byłoby by domyślnie podpisane w systemie. Pozostałe, prywatne repozytoria musiałyby być zaakceptowane poprzez dociągnięcie klucza. O ile nie wyeliminuje to zagrożenia w 100%, o tyle mocno je ograniczy.

    Odpowiedz
  • 2016.06.11 10:02 MatM

    Jest jeden problem ze ścisłą weryfikacją pakietów przed ich zamieszczeniem w repozytorium – kto i na jakiej podstawie ma oceniać czy pakiet jest przydatny (komu i do czego) oraz ilość ludzi, która musiałaby stale monitorować zmiany w zamieszczanych pakietach (wszak nie od razu trzeba zamieszczać coś złośliwego, można to zrobić w wersji 2.0 dla niepoznaki).
    .
    Pewnym rozwiązaniem mogłaby być „społecznie” tworzona lista sprawdzonych pakietów oraz opcja instalacji tych spoza listy na wyraźne życzenie programisty.

    Odpowiedz

Zostaw odpowiedź do Daniel

Jeśli chcesz zwrócić uwagę na literówkę lub inny błąd techniczny, zapraszamy do formularza kontaktowego. Reagujemy równie szybko.

Jak w łatwy sposób zainfekować 17 000 komputerów programistów

Komentarze