Amatorski błąd w kodzie Rabbit R1 umożliwia dostęp do danych użytkowników

Rabbit, startup technologiczny produkujący plastikowe urządzenie zbudowane przede wszystkim do interakcji z algorytmami generatywnymi i uczenia maszynowego, powszechnie nazywane “sztuczną inteligencją”, został zhakowany w stosunkowo prosty sposób.
Producent tego gadżetu przypominającego szeroki, nieco gruby, plastikowy smartfon w niezwykle jaskrawym odcieniu pomarańczowego, cieszył się szerokim zainteresowaniem od momentu prezentacji ich nowego oprogramowania “Large Action Model” na targach CES w styczniu. Algorytm ma być zdolny do obsługi aplikacji na smartfona bądź stron internetowych, emulując przy tym zwykłego użytkownika, który wydaje jedynie komendę głosową, a algorytm samodzielnie “przeklikuje” się przez interfejs, wykonując polecenie.
Nie jest to wielką rewelacją, różnego rodzaju boty w każdej chwili próbują udawać ludzi i wchodzić w interakcję z aplikacjami, chociaż ich cele często są złośliwe. Potrafią rejestrować fałszywe konta użytkowników, publikować czy udostępniać posty, na przykład propagandowe czy z fałszywymi wiadomościami, skanować strony internetowe, pobierać aplikacje i tak dalej. Innowacyjne jest jednak, że Rabbit powinien pracować w interesie pojedynczego użytkownika, automatyzując jego użycie aplikacji. Rabbit nie tworzy fałszywych kont w usługach, z których korzysta, ale prosi użytkownika o zalogowanie się do własnych.
Według startupu użytkownik może poprosić swojego asystenta, reprezentowanego na ekranie przez przeuroczą ikonę królika, nie tylko o odpowiedź na banalne pytania o pogodę, wysokość Mount Everest czy odległość do księżyca, ale również zamówienie taksówki, jedzenia, włączenie muzyki lub zrobienie zakupów na Amazon i eBay. Wystarczy nacisnąć przycisk, wydać polecenie, na przykład “Zamów Ubera do domu” i po kilku chwilach wsiąść do taksówki. Ilość obsługiwanych aplikacji można policzyć na palcach, jednak głównymi atutami wykorzystania modelu uczenia maszynowego ma być możliwość automatycznego dostosowania do przyszłych zmian w interfejsach aplikacji oraz eksperymentalny “tryb uczenia”, który ma zapisywać ruchy użytkownika i na tej podstawie uczyć się korzystania z kolejnych aplikacji.
Inwestorzy i klienci wykupili pierwsze partie urządzenia w ciągu paru minut od prezentacji i liczyli na potencjalny substytut dla współczesnych smartfonów, oparty w całości o interakcję głosową. Rabbit wierzy w sterowanie głosem do tego stopnia, że mimo zamontowania ekranu dotykowego, jego funkcjonalność jest zupełnie wyłączona, kiedy urządzenie nie wyświetla klawiatury. W każdej innej sytuacji konieczne jest korzystanie z przycisku i pokrętła zamontowanego po prawej stronie.
Cała idea prezentowana przez Rabbita wydaje mi się dosyć ekscentryczna i obarczona wieloma wadami, między innymi z punktu widzenia bezpieczeństwa. Pełne sterowanie głosowe uniemożliwi obsługę urządzenia w głośnych czy zatłoczonych miejscach. Nie wyobrażam sobie ludzi krzyczących na swoje urządzenia w metrze czy na ulicy. Tak samo dziwne byłoby korzystanie z Rabbita w otoczeniu innych ludzi, kiedy nie zawsze chcemy, aby wszyscy w pociągu, windzie czy kawiarni słyszeli nasze pytania i odpowiedzi urządzenia.
Inną kwestią jest bezpieczeństwo kont, do których dostępu trzeba użyczyć Rabbitowi. Odbywa się to przez stronę internetową Rabbit Hole, na której trzeba zalogować się do aplikacji, jakie ma obsługiwać urządzenie, wpisując dosłownie swój login i hasło. Według startupu: “wpisywanie loginu i hasła jest szyfrowane i chronione. Nie przechowujemy tych informacji w naszej bazie danych”. Można domyślać się, co dokładnie znaczy “ochrona” oraz “szyfrowanie” w tym kontekście. Informacja prasowa uchyla jednak rąbka tajemnicy, dodając jeszcze kilka zdań do zacytowanego wcześniej urywku: “Zachowujemy bezpiecznie przechowywany, uwierzytelniony stan aplikacji w naszej chmurze, aby nasze boty mogły działać w Twoim imieniu. Użytkownik może usunąć te dane w dowolnym momencie”. Jeśli dobrze rozumiem ten pół-marketingowy żargon, można się domyślać, że Rabbit prawdopodobnie zachowuje plik cookie, który pozwala utrzymać aplikację w stanie zalogowania. Rodzi to jednak trzy, różne problemy.
Pliki cookie, nazywane po prostu “ciasteczkami”, pozwalają zapisać stronie internetowej jakiegoś rodzaju daną w przeglądarce użytkownika. Mogą to być na przykład preferencje, ustawienia, historia przeglądania, ale też specjalny ciąg znaków, nazywany tokenem, który identyfikuje danego użytkownika. Dzięki niemu nie jest konieczne logowanie się na każde z kont po otwarciu nowej karty czy restarcie przeglądarki. Strona internetowa odczytuje zapisany wcześniej token i automatycznie loguje użytkownika. Takie tokeny są jednak intratnym celem dla cyberprzestępców, którzy coraz częściej obierają je jako swój cel. Wykradzione ciasteczko umożliwia przestępcy podszycie się pod swoją ofiarę bądź sprzedaż takiego pliku innemu złodziejowi za cenę zależną od wartości przejętego konta. Rabbit może więc twierdzić, że nie przechowuje loginów i haseł, ale musi przechowywać jakiegoś rodzaju token, który w praktyce również pozwala zalogować się na przypisane mu konto. Myślę, że można na tej podstawie stwierdzić, że startup posługuje się czystą manipulacją.
Drugą kwestią wartą poruszenia jest typowy mechanizm bezpieczeństwa, który powinien stosować absolutnie każdy, kto zapisuje tokeny uwierzytelniające użytkownika jako ciasteczka. Tak jak każdy produkt spożywczy, cookies mają swoją datę ważności, określaną przez producenta. Po jej upływie powinny zostać wyrzucone i zastąpione świeżymi. Dlatego co jakiś czas jesteś proszony o ponowne wpisanie swojego loginu i hasła. Oznacza to, że termin ważności minął. Te terminy są różne dla różnych typów aplikacji. Mniej istotne, przynajmniej dla większości społeczeństwa, gry online bądź media społecznościowe, potrafią przechowywać dane do logowania przez bardzo długi okres, na przykład rok. Bardziej wrażliwe konta, na przykład bankowe, potrafią unieważniać tokeny nawet po kilkunastu minutach. Jeśli moja spekulacja jest więc poprawna, Rabbit będzie musiał regularnie prosić użytkownika o ponowne zalogowanie do każdej z usług. Teoretycznie stanowi to potrzebny mechanizm bezpieczeństwa, jednak jeśli przykładowe zapytanie o zamówienie taksówki ma być przerwane przez komunikat o przeterminowanym tokenie i konieczności ponownego logowania, chyba wygodniej będzie po prostu zamówić tego samego Ubera na smartfonie.
Trzecim, choć pewnie nie ostatnim problemem jest zupełny brak transparentności w zakresie bezpieczeństwa. Nie znalazłem żadnych, konkretnych informacji na temat sposobu przechowywania i wykorzystywania najbardziej wrażliwych informacji użytkowników. Firma posługuje się prawie wyłącznie pozbawionymi znaczenia sloganami marketingowymi. Jeśli czujesz się przekonany, że użycie słów “bezpiecznie” oraz “szyfrowanie” daje bezpieczeństwo, swobodnie przekaż swoje loginy nowo powstałemu startupowi, który kilka dni temu popełnił amatorski błąd, pozwalający na pobranie pełnej historii odpowiedzi, jakich kiedykolwiek udzielił Rabbit, ale o tym za chwilę 😉
Zanim zakwestionuję sens istnienia całego urządzenia, chciałbym pochwalić kilka praktyk, którymi być może warto się zainspirować. Większość wirtualnych asystentów prowadzi stały nasłuch swojego otoczenia, oczekując na słowa-klucze wywołujące ich aktywację. Wypowiedzenie słów “Ok Google” albo “Hey Siri” jest początkiem każdej interakcji z programem. Nieszczęśliwą konsekwencją jest jednak konieczność ciągłego podsłuchiwania każdej rozmowy prowadzonej w otoczeniu smartfona, często w zaawansowany sposób. Asystent głosowy firmy Apple potrafi rozróżniać głosy różnych osób i reagować tylko na komendy jednej z nich. Niestety powoduje to szerokie pole do nadużyć prywatności. Co by było, gdyby hipotetycznie Google zaczął wprowadzać inne słowa-klucze, na przykład “telewizor” czy “samochód”, żeby dodać je do twojego profilu reklamowego? Apple i Google zostały już przyłapane na wysyłaniu do zewnętrznych partnerów nagrań nieświadomych podsłuchu użytkowników], nawet jeśli nie wypowiedzieli słowa-klucza uruchamiającego asystenta. Rabbit rozwiązuje ten problem w stosunkowo elegancki sposób. Rozpoczęcie interakcji wymaga wciśnięcia fizycznego przycisku.
Kolejną pozytywną praktyką startupu jest zamontowanie aparatu na obracającym się wałku. Takie rozwiązanie pozwala nie tylko na wykorzystanie pojedynczego obiektywu do robienia zdjęć z przodu i z tyłu urządzenia, co obniża koszty produkcji, ale również na fizyczne obrócenie aparatu w taki sposób, aby nie był w stanie wykonać zdjęć czy nagrań, kiedy nie jest potrzebny. Wyświetlanie kolorowej kropki w rogu ekranu przez urządzenia Apple i Android w momencie jego wykorzystania jest znacznie mniej intuicyjne i bezpieczne. Dzięki umieszczeniu aparatu na wałku użytkownik wie, kiedy jest w użytku, a kiedy jest to fizycznie uniemożliwione. Tutaj kończą się pozytywy, więc pora przystąpić do patroszenia królika.
Trudno jest mi wyzbyć się wrażenia, że wszystkie funkcje, które spełnia w tym momencie Rabbit, są od lat dostępne w zwykłych asystentach głosowych. Porównajmy listę funkcji Rabbita z Google Assistant. Zamówić taksówkę można od sześciu lat, do tego możliwy jest wybór wielu różnych dostawców. Zamówić jedzenie można od trzech lat. Uruchomienie nawigacji przez wirtualnego asystenta firmy było możliwe w zasadzie od początku jego istnienia. Wyszukiwanie obiektów oparte o zdjęcia jest dostępne od siedmiu lat i tutaj w zasadzie lista funkcji Rabbita się kończy, podczas gdy asystent z systemu Android pozwala również na zapisywanie wydarzeń w kalendarzu, ustawianie przypomnień i budzików, wysyłanie wiadomości SMS, rozpoczynanie połączeń i wiele więcej. Żadna z tych funkcji nie jest dostępna na Rabbicie, ponieważ nie jest aplikacją na smartfona, a oddzielnym urządzeniem, przynajmniej w teorii.
Nie rozumiem również sensu istnienia Large Action Model, na którym opiera się rzekoma innowacja Rabbita. Aplikacje, które obsługuje urządzenie, od dawna udostępniają oficjalne API. Zamówienie taksówki przez Ubera można nietrudno wywołać w swojej własnej aplikacji czy programie, korzystając z oficjalnego, istniejącego od lat API, bez konieczności programowania botów opartych o złożone algorytmy, starające się odtwarzać ruchy użytkownika wykonując kliknięcia w interfejsie Ubera. Ponadto “eksperymentalny tryb uczenia” przypomina funkcję nagrywania ruchów użytkownika i ponownego ich odtwarzania, dostępną od lat w programach i frameworkach do automatyzacji.
Trzydziestego kwietnia portal Android Authority zadał sobie pytanie: czemu Rabbit męczył się z projektowaniem fizycznego urządzenia, kiedy wszystkie jego funkcje mogą być zastąpione przez aplikację na smartfona? Przystąpili więc do analizy systemu Rabbit OS, na którym podobno oparty jest gadżet. Okazało się, że urządzenie w rzeczywistości działa na systemie Android, na którym uruchamia pojedynczą aplikację, zawierającą całość interfejsu użytkownika. Z pomocą anonimowego źródła wewnątrz firmy, zainstalowali aplikację na smartfonie Pixel 6a firmy Google i otrzymali dostęp do większości funkcji Rabbita.

Firma szybko odpowiedziała, że “Rabbit nie jest aplikacją na Androida. […] Rabbit OS oraz Large Action Model działają przede wszystkim w chmurze”. Faktem jest, że wiele możliwości urządzenia jest oparta o chmurę, co w gruncie rzeczy oznacza, że jego funkcją jest głównie wysyłanie zapytań do serwerowni i wyświetlanie odpowiedzi, co w moich oczach jeszcze bardziej podważa sens istnienia Rabbita. Co jest szczególnego w zapytaniach wysyłanych przez oddzielne urządzenie względem aplikacji na smartfona, który prawdopodobnie mógłby samodzielnie wykonać wiele funkcji przekazywanych do chmury przez Rabbita bez mocniejszego procesora czy pamięci?
Jakby tego było mało, około dwa tygodnie później grupa badaczy Rabbitude, skupiona na inżynierii wstecznej, eksperymentach i hakowaniu urządzenia Rabbit ogłosiła, że weszła w posiadanie jego kodu źródłowego. Komunikat zamieszczony na ich stronie internetowej jest krótki, zwięzły i raczej ubogi w szczegółowe informacje, jednak serwer Discord organizacji zawiera bardziej szczegółowe informacje, publikowane przez administratorów w wiadomościach. Przeciek dotyczył kodu działającego w chmurze Rabbita, chociaż grupa jest również w posiadaniu oprogramowania działającego na samych urządzeniach. Grupa przeanalizowała kod i odnalazła kilka kluczy, zaszytych bezpośrednio w oprogramowaniu, umożliwiających dostęp do chmury obliczeniowej Microsoft Azure, Google Maps, Yelp i Eleven Labs. Ostatnia pozycja z tej listy jest najbardziej istotna, ponieważ umożliwiała dostęp do usługi syntezatora mowy, notabene wyprodukowanej przez polski startup. Przetworzenie tekstu na mowę jest konieczne do obsługi każdego zapytania przez Rabbita, aby nadać urządzeniu głos, który można odtworzyć użytkownikowi. Przejęcie kontroli nad tą funkcją umożliwia więc podejrzenie wszystkich odpowiedzi, które ‘wypowiada’ Rabbit. Możliwe było także modyfikowanie tych odpowiedzi bądź zaprzestanie ich udzielania, co uczyniłoby Rabbita zupełnie bezużytecznym (zakładając, że przed wyciekiem kluczy miał jakiegoś rodzaju zastosowanie). Grupa twierdzi, że znalazła też klucze dostępowe do wewnętrznych usług samego Rabbita, zaszyte w kodzie operującym na samych urządzeniach.
Jeśli chcesz skorzystać z cudzej usługi wewnątrz własnego programu, w wielu przypadkach konieczne będzie użycie API, lub polsku interfejsu programowania aplikacji. Rabbit wysyła do API oferowanego przez Eleven Labs tekst, który ma wypowiedzieć asystent, a w odpowiedzi otrzymuje plik dźwiękowy z jego treścią odczytaną przez wirtualnego lektora. Większość API wymaga jednak uwierzytelnienia, do czego służą klucze prywatne, działające podobnie jak tokeny, o których wspominałem wcześniej. Istotne jest jednak, aby nie zapisywać swoich kluczy bezpośrednio w kodzie, ponieważ każda osoba mająca do niego późniejszy dostęp, uprawniony bądź nie, uzyska również możliwość podszycia się pod właściciela klucza.
Zapisywanie kluczy bezpośrednio w kodzie programu jest banalnym, podstawowym, amatorskim błędem, o którym powinien wiedzieć każdy programista mający do czynienia z API. Programiści Rabbita podobno dowiedzieli się o tym błędzie miesiąc temu, ale nic nie zrobili. Dopiero po publikacji komunikatu przez Rabbitude zaczęli wymieniać stare klucze na nowe. Oficjalny komunikat firmy jest jednak pozbawiony informacji o zmianie sposobu przechowywania kluczy, choć to sugeruje, mówiąc o “uniemożliwieniu programistom wprowadzania kluczy do bazy kodu”.
Mimo działań podjętych przez startup Rabbitude rzekomo znalazł kolejne klucze w kodzie źródłowym, tym razem umożliwiające wysyłanie wiadomości mailowych z oficjalnej domeny firmy, czego nadal wypiera się prezes Rabbita mimo dowodów wysłanych do dziennikarzy.
Jeśli z jakiegoś powodu jesteś jednym z klientów, którzy zamówili Rabbita, możesz mimo wszystko spać spokojnie, ponieważ prezes startupu napisał na serwerze Discord, że uruchomił “program anty-hakerski” i “bierze to bardzo na poważnie oraz podejmuje natychmiastowe działania”. Poza tym prosimy wszystkich sceptyków, aby “nie lekceważyli wysiłku i ilorazu IQ inżynierów [Rabbita]“!
