Podczas Embedded World 2019 dużo miejsca poświęcono tematowi Embedded Security. To wyraźne odwrócenie trendu ignorowania problemów podatności i zabezpieczeń tego typu systemów, które dominowało do tej pory. Na pewno duży wpływ na to ma rozwój Internet Of Things zapewniający nam stały dopływ niezabezpieczonych urządzeń. Swoje w tym temacie na pewno zrobiły też podatności związane z hardware’m takie jak Meltdown i Spectre. Sam w żadnym wypadku nie uważam się od eksperta od Embedded Security, ale chętnie podzielę się wiedzą otrzymaną podczas konferencji i dołożę cegiełkę do zwiększania świadomości programistów o tego typu zagrożeniach.
Ataki na bootloader
W mikrokontrolerach program zapisany jest w pamięci FLASH, której nie możemy tak łatwo modyfikować. Dlatego wykonanie złośliwego kodu jest nieco trudniejsze niż w przypadku PC. W takim wypadku wektorem ataku jest bootloader, który wgrywa aktualizację całej aplikacji. Jeśli uda się wgrać inną binarkę, atakujący przejmuje kontrolę nad peryferiami układu.
Zanim atakujący przygotuje złośliwy wsad, musi najpierw wykonać reverse engineering. Musi więc pobrać, przeanalizować i zmodyfikować istniejący wsad, albo utworzyć nowy. Pierwszym sposobem utrudnienia takiego ataku jest więc zabezpieczenie przed odczytem pamięci programu. Następnie atakujący będzie wgrywać różne wersje zmodyfikowanego softu i sprawdzał, czy działają tak jak chce. Możemy mu to utrudnić stosując prosty licznik wgrań nowego softu – raczej nikt podczas zwykłego użytkowania nie będzie wykonywać więcej niż 10 aktualizacji w krótkim czasie. Możemy również liczyć ilość aktualizacji softu od początku użytkowania urządzenia.
Bardziej zaawansowaną metodą ochrony jest enkrypcja danych przesyłanych do bootloadera i Secure Boot. Dzięki temu mamy pewność, że update softu jest wgrywany z zaufanego źródła. Stosując enkrypcję należy pamiętać oczywiście o odpowiednim składowaniu klucza prywatnego. Nie należy go hardkodować w firmwarze ani używać tego samego klucza we wszystkich sztukach naszego urządzenia. Producenci układów udostępniają procedury bezpiecznego nadawania i przechowywania kluczy prywatnych.
Podglądanie poboru mocy
Jednak klucz prywatny nawet jak jest bezpiecznie składowany, może zostać odgadnięty przez atakującego. Służą do tego tzw. Side Channel Attacks w tym DPA – Dual Power Analysis. W atakach tego typu chodzi o obserwowanie poboru mocy procesora. Okazuje się, że podając odpowiednie dane wejściowe i obserwując pobór mocy podczas dekrypcji klucza AES możemy go odgadnąć, ponieważ pobór mocy podczas wykonywania algorytmu gdy na danym bicie jest jedynka, różni się od mocy gdy jest zero. Podając odpowiednio spreparowane dane wejściowe możemy więc odkryć cały klucz. Na GitHubie można znaleźć skrypty do wykonywania tego typu ataku. Projekt nazywa się ChipWhisperer i jego autor miał prezentację podczas Embedded World.bIstnieją rozwiązania hardware’owe broniące przed tego typu atakami. Uniezależniają one zużycie mocy od zer i jedynek.
Glitching
Innym wektorem ataku jest tzw. glitching. Zwykle po wgraniu programu przez bootloader wykonuje się procedurę blokowania pamięci przed zapisem. Zwykle polega to na wpisaniu odpowiedniej sekwencji do rejestru. Jeżeli spowodujemy błąd wykonywania jednej z tych instrukcji, sekwencja zostanie wpisana niepoprawnie i pamięć nie zostanie zabezpieczona przed zapisem.
Nie ułatwiajmy atakującym zdobywać informacji o naszym systemie
Systemy embedded udostępniają na zewnątrz niewiele informacji o swoim działaniu. Atakujący musi się nieźle namęczyć, żeby wykonać reverse engineering. Nie powinniśmy ułatwiać mu zadania. Dlatego powinniśmy pamiętać o takich rzeczach jak wyłączenie konsoli debugowej w buildzie produkcyjnym. Taki debugowy UART daje często informacje o wewnętrznych zmiennych i modułach, które potem mogą być wykorzystane przeciwko nam.
Bardziej zdeterminowany atakujący może naruszyć fizyczną strukturę procesora, aby wydobyć z niego informacje. Przed takim atakiem broni zabezpieczenie Tamper udostępniane w większości mikrokontrolerów.
Dlaczego temat jest ważny?
Dlaczego bezpieczeństwo systemów embedded jest ważne? Czy zagrożenie jest realne? Autor prezentacji o ChipWhispererze jako przykład podał sprzętowy portfel kryptowalut Trezor, na który udało się za pomocą przedstawionych powyżej technik wgrać złośliwy firmware. Systemy embedded w dzisiejszych czasach sterują samochodami, rozrusznikami serca, procesami chemicznymi i wieloma innymi systemami. Twórcy takich systemów na pewno muszą zainteresować się tematem. Świadomość zagrożeń powinni mieć jednak wszyscy programiści, których urządzenia korzystają z internetu, bluetootha, czy bootloaderów.
Autor innej prezentacji zauważył, że nie we wszystkich produktach opłaca się dodawać mechanizmy obronne przeciwko takimi atakami. W produkcji małoseryjnej wystarczy security by obscurity i mały potencjalny zysk ze złamania zabezpieczeń. Dlatego nie powinniśmy ułatwiać zadania publikując kod źródłowy, czy dokładne schematy połączeń naszych układów. Co jednak jeżeli security by obscurity nie wystarczy?
Sposoby obrony przed atakami
Przed większością podatności można się bronić stosując programowanie defensywne. Dodatkowe checki w kodzie mogą wykryć podejrzane zachowanie. W ten sposób można poradzić sobie z glitchingiem i atakami na bootloader. Techniki defensywne powinny być wspierane przez odpowiedni proces wytwarzania oprogramowania zawierający Code Review, analizę statyczną, testy funkcjonalne, testy penetracyjne, odpowiednią politykę updatów firmware’u.
Dobrym sposobem obrony może być również wykorzystanie mechanizmów udostępnionych przez producentów procesorów, takich jak wspomniane wcześniej SecureBoot, Tamper, czy metody uniemożliwiające ataki DPA. Warto również korzystać z MPU (Memory Protection Unit) czy MMU (Memory Management Unit) jeżeli nasz procesor je udostępnia. Tworzymy nasz system wtedy w taki sposób, że tylko kernel ma dostęp do peryferiów, a pozostałe moduły mogą pośrednio uzyskać dostęp do peryferiów przez niego. Wtedy dodajemy kolejną warstwę do sforsowania dla atakującego i możemy wyłączyć niepotrzebne tryby peryferiów.
Podsumowanie
Jak widać temat mimo, że mało zbadany, jest bardzo ciekawy. Tworząc małoseryjnie proste urządzenia wystarczy nam security by obscurity. Jednak jeżeli myślimy o czymś większym i do tego podłączonym do internetu na pewno warto zainteresować się tematem. Tym bardziej, że podatności systemów embedded to nie jest jakiś wyimaginowany problem. W zeszłym roku znaleziono między innymi luki bezpieczeństwa we FreeRTOSie.
Jeżeli temat Cię zainteresował i chcesz dowiedzieć się więcej, zapraszam do śledzenia kanałów ekspertów takich jak LiveOverflow, Azeria, twórca ChipWhisperera Colin O’Flynn, czy Joe Fitz.
10 marca 2019 at 13:49
Odnośnie luk w bootloaderach: W 8bitowych prockach SiliconLabs bootloader wbudowany miał małą lukę. Generalnie można było zablokować odczyt danych przez niego, żeby nikt nie mógł za jego pomocą wprost odczytać wsadu – no i ok, pewnie wszyscy producenci urządzeń to robili. Ale istniała tam także funkcja, która umożliwiała weryfikacje poprawności danych w pamięci i dało się nią „sprawdzić” czy pod danym adresem jest taka wartość o jaką zapytaliśmy, czy nie. Czyli python + prosta pętla z odpytywaniem aż do skutku kolejnych bajtów i sobie odczytujemy wsady z urządzeń – jest to na gicie do znalezienia.