Autor: CertiK
Wcześniej zespół CertiK odkrył szereg luk w zabezpieczeniach typu „odmowa usługi” w łańcuchu bloków Sui. Wśród tych luk wyróżnia się nowa luka o dużym wpływie. Luka ta może spowodować, że węzły sieci Sui nie będą w stanie przetwarzać nowych transakcji, co skutkuje całkowitym zamknięciem całej sieci.
W ubiegły poniedziałek firma CertiK otrzymała nagrodę w wysokości 500 000 dolarów za wykrycie tej poważnej luki w zabezpieczeniach. CoinDesk, wiarygodne media w amerykańskiej branży, poinformowały o incydencie, a następnie główne media podążyły za jego raportem i opublikowały odpowiednie wiadomości.
Ta luka w zabezpieczeniach jest powszechnie nazywana „kołem chomika”: jej unikalna metoda ataku różni się od obecnie znanych ataków. Osoba atakująca musi jedynie przesłać ładunek o długości około 100 bajtów, aby uruchomić nieskończoną pętlę w węźle weryfikacji Sui, co uniemożliwia jej wykonanie reagować na nowe transakcje.
Ponadto szkody spowodowane atakiem mogą utrzymywać się po ponownym uruchomieniu sieci i mogą automatycznie rozprzestrzeniać się w sieci Sui, sprawiając, że wszystkie węzły niczym chomik biegający bez przerwy na kole nie będą w stanie przetworzyć nowych transakcji. Dlatego nazywamy ten unikalny typ ataku atakiem „koła chomika”.

Po odkryciu luki firma CertiK zgłosiła ją Sui w ramach programu nagród za błędy Sui. Sui również zareagował tak szybko, jak to możliwe, potwierdził powagę luki i aktywnie podjął odpowiednie działania w celu naprawienia problemu przed uruchomieniem sieci głównej. Oprócz naprawienia tej konkretnej luki Sui wdrożyła rozwiązania zapobiegawcze, aby zmniejszyć potencjalne szkody, jakie ta luka może spowodować.
Aby podziękować zespołowi CertiK za odpowiedzialne ujawnianie informacji, Sui przyznał zespołowi CertiK premię w wysokości 500 000 USD.
Poniższe szczegóły techniczne tej krytycznej luki zostaną ujawnione w celu wyjaśnienia pierwotnej przyczyny i potencjalnego wpływu tej luki.
Szczegółowe wyjaśnienie luk
Kluczowa rola walidatorów w Sui
W przypadku blockchainów opartych na języku Move, takich jak Sui i Aptos, ich mechanizmem ochrony przed złośliwymi atakami typu payload jest głównie technologia weryfikacji statycznej. Dzięki technologii weryfikacji statycznej Sui może sprawdzić ważność ładunku przesłanego przez użytkowników przed wydaniem umowy lub aktualizacją. Walidator udostępnia szereg elementów sprawdzających zapewniających poprawność struktury i semantyki. Dopiero po przejściu kontroli i weryfikacji kontrakt trafi do maszyny wirtualnej Move do realizacji.

Zagrożenia złośliwymi ładunkami w łańcuchu Move
Sieć Sui zapewnia nowy zestaw modeli pamięci masowej i interfejsów oprócz oryginalnej maszyny wirtualnej Move, więc Sui ma dostosowaną wersję maszyny wirtualnej Move. Aby zapewnić obsługę nowych prymitywów pamięci masowej, Sui wprowadza szereg dodatkowych, dostosowanych do indywidualnych potrzeb kontroli mających na celu weryfikację bezpieczeństwa niezaufanych ładunków, takich jak bezpieczeństwo obiektów i globalny dostęp do pamięci masowej. Te niestandardowe kontrole pasują do unikalnych funkcji Sui, dlatego nazywamy je walidatorami Sui.

Kolejność Sui sprawdzania obciążenia
Jak pokazano na powyższym rysunku, większość kontroli w module sprawdzającym przeprowadza weryfikację zabezpieczeń na poziomie strukturalnym względem CompiledModule (który reprezentuje przebieg ładunku kontraktu dostarczony przez użytkownika). Na przykład użyj „Weryfikatora duplikatów”, aby upewnić się, że w ładunku środowiska wykonawczego nie ma zduplikowanych wpisów; użyj „Weryfikatora limitów”, aby upewnić się, że długość każdego pola w ładunku środowiska wykonawczego mieści się w dozwolonym limicie wpisów.
Oprócz kontroli na poziomie strukturalnym kontrola statyczna weryfikatora nadal wymaga bardziej złożonych metod analizy, aby zapewnić niezawodność niezaufanego ładunku na poziomie semantycznym.
Dowiedz się o abstrakcyjnym interpreterze Move:
Analiza liniowa i iteracyjna
Interpreter abstrakcyjny udostępniany przez Move to framework zaprojektowany specjalnie do przeprowadzania złożonej analizy bezpieczeństwa kodu bajtowego poprzez interpretację abstrakcyjną. Mechanizm ten sprawia, że proces weryfikacji jest bardziej wyrafinowany i dokładny, a każdy weryfikator może zdefiniować swój unikalny abstrakcyjny stan do analizy.
Rozpoczynając przebieg, interpreter abstrakcyjny tworzy wykres przepływu sterowania (CFG) ze skompilowanych modułów. Każdy podstawowy blok w tych CFG utrzymuje zestaw stanów, a mianowicie „stan przed zamówieniem” i „stan po zamówieniu”. „Stan przed zamówieniem” zapewnia migawkę stanu programu przed wykonaniem bloku podstawowego, natomiast „stan po zamówieniu” zapewnia opis stanu programu po wykonaniu bloku podstawowego.
Kiedy abstrakcyjny interpreter nie napotyka żadnych skoków (ani pętli) na wykresie przepływu sterowania, postępuje zgodnie z prostą liniową zasadą wykonania: każdy blok podstawowy jest analizowany po kolei, a instrukcja poprzedzająca jest obliczana w oparciu o semantykę każdej instrukcji w bloku. stan sekwencyjny i stan posekwencyjny. Rezultatem jest dokładna migawka każdego podstawowego stanu programu na poziomie bloku podczas jego wykonywania, pomagająca zweryfikować właściwości bezpieczeństwa programu.

Przenieś przepływ pracy interpretera abstrakcyjnego
Jednakże proces ten staje się bardziej skomplikowany, gdy w przepływie sterowania występują pętle. Wystąpienie pętli oznacza, że na wykresie przepływu sterowania znajduje się zbocze odbicia. Źródło zbocza odbicia odpowiada kolejnemu stanowi bieżącego bloku podstawowego, a docelowy blok podstawowy (głowa pętli) zbocza odbicia jest wcześniej analizowanym. Stan wstępnego bloku podstawowego, więc interpreter abstrakcyjny musi dokładnie połączyć stany dwóch podstawowych bloków związanych ze skokiem.
Jeśli okaże się, że stan scalony różni się od istniejącego stanu wstępnego porządku podstawowego bloku głównego pętli, interpreter abstrakcyjny aktualizuje stan podstawowego bloku nagłówka pętli i rozpoczyna analizę od tego podstawowego bloku. Ten proces analizy iteracyjnej trwa do momentu, aż stan wstępny pętli będzie stabilny. Innymi słowy, proces ten jest powtarzany do momentu, aż stan wstępnego bloku podstawowego na początku pętli nie będzie się już zmieniał pomiędzy iteracjami. Osiągnięcie ustalonego punktu oznacza, że analiza pętli została zakończona.
Sui IDLeak weryfikator:
Indywidualna analiza interpretacji abstrakcyjnych
W przeciwieństwie do oryginalnego projektu Move, platforma blockchain Sui wprowadza unikalny, globalny model przechowywania skoncentrowany na „celach”. Godną uwagi cechą tego modelu jest to, że każda struktura danych z atrybutem klucza (przechowywanym jako indeks w łańcuchu) musi mieć typ ID jako pierwsze pole struktury. Pole ID jest niezmienne i nie można go przenieść do innych obiektów docelowych, ponieważ każdy obiekt musi mieć globalnie unikalny identyfikator. Aby zapewnić te właściwości, Sui zbudował zestaw niestandardowej logiki analitycznej w oparciu o interpreter abstrakcyjny.

Weryfikator IDLeak, znany również jako id_leak_verifier, współpracuje z interpreterem abstrakcyjnym w celu przeprowadzenia analizy. Ma swoją własną, unikalną AbstractDomain, zwaną AbstractState. Każdy stan abstrakcyjny składa się z wartości abstrakcyjnej odpowiadającej wielu zmiennym lokalnym. Monitoruj status każdej zmiennej lokalnej za pomocą AbstractValue, aby śledzić, czy zmienna identyfikatora jest nowa.
Podczas procesu pakowania struktury walidator IDLeak pozwala jedynie na spakowanie nowego identyfikatora do struktury. Dzięki abstrakcyjnej analizie interpretacji walidator IDLeak może w sposób wyczerpujący śledzić stan lokalnego przepływu danych, aby zapewnić, że żadne istniejące identyfikatory nie zostaną przeniesione do innych obiektów struktury.
Sui Problem z utrzymaniem spójności stanu walidatora IDLeak
Walidator IDLeak jest zintegrowany z interpreterem abstrakcyjnym Move poprzez implementację funkcji AbstractState::join. Funkcja ta odgrywa integralną rolę w zarządzaniu stanem, szczególnie przy łączeniu i aktualizacji wartości stanu.
Sprawdź szczegółowo te funkcje, aby zrozumieć ich działanie:

W AbstractState::join funkcja pobiera inny AbstractState jako dane wejściowe i próbuje połączyć swój stan lokalny ze stanem lokalnym bieżącego obiektu. Dla każdej zmiennej lokalnej w stanie wejściowym porównuje wartość zmiennej z jej aktualną wartością w stanie lokalnym (jeśli nie zostanie znaleziona, wartością domyślną jest AbstractValue::Other). Jeśli te dwie wartości nie są równe, ustawi flagę „zmieniono” jako podstawę tego, czy ostateczny wynik scalania stanu uległ zmianie, i zaktualizuje wartość zmiennej lokalnej w stanie lokalnym, wywołując AbstractValue::join.

W AbstractValue::join funkcja porównuje swoją wartość z inną wartością AbstractValue. Jeśli są równe, zwróci przekazaną wartość. Jeśli nie jest równa, zwracana jest wartość AbstractValue::Other.
Jednak ta logika utrzymania stanu zawiera ukryty problem niespójności. Chociaż AbstractState::join zwróci wynik wskazujący, że stan scalania uległ zmianie (JoinResult::Changed) w oparciu o różnicę między starą i nową wartością, zaktualizowana wartość połączonego stanu może nadal pozostać niezmieniona.
Ten problem niespójności wynika z kolejności operacji: określenie zmienionego stanu w AbstractState::join następuje przed aktualizacją stanu (AbstractValue::join), a określenie to nie odzwierciedla rzeczywistego wyniku aktualizacji stanu.
Dodatkowo w AbstractValue::join decydującą rolę w wyniku połączenia odgrywa AbstractValue::Other. Na przykład, jeśli stara wartość to AbstractValue::Other, a nowa wartość to AbstractValue::Fresh, zaktualizowana wartość stanu to nadal AbstractValue::Other, nawet jeśli stara i nowa wartość są różne, sam stan nie zmienić po aktualizacji.

Przykład: Niespójność w połączeniach stanu
Wprowadza to niespójność: wynik połączenia podstawowych stanów bloków jest oceniany jako „zmieniony”, ale sama wartość połączonego stanu nie uległa zmianie. W procesie abstrakcyjnej interpretacji i analizy wystąpienie takich niespójności może mieć poważne konsekwencje. Sprawdzamy zachowanie abstrakcyjnego interpretera, gdy na grafie przepływu sterowania (CFG) pojawiają się pętle:
W przypadku napotkania pętli interpreter abstrakcyjny wykorzystuje metodę analizy iteracyjnej w celu połączenia stanu podstawowego bloku docelowego skoku z bieżącym blokiem podstawowym. Jeśli stan scalony ulegnie zmianie, interpreter abstrakcyjny przeanalizuje ponownie, zaczynając od celu skoku.
Jeśli jednak operacja scalania w ramach analizy interpretacji abstrakcyjnej błędnie oznaczy wynik scalania stanu jako „zmieniony”, podczas gdy w rzeczywistości wartość zmiennej wewnętrznej stanu się nie zmieniła, doprowadzi to do niekończącej się ponownej analizy i stworzy nieskończoną pętlę .
dalsze wykorzystywanie tej niespójności
Uruchom nieskończoną pętlę w walidatorze Sui IDLeak
Wykorzystując tę niespójność, osoba atakująca może skonstruować złośliwy wykres przepływu kontroli, aby oszukać walidator IDLeak w nieskończoną pętlę. Ten starannie skonstruowany wykres przepływu sterowania składa się z trzech podstawowych bloków: BB1 i BB2, BB3. Warto zauważyć, że celowo wprowadziliśmy krawędź skoku z BB3 do BB2, aby zbudować pętlę.

Złośliwy status CFG+ może prowadzić do nieskończonej pętli w walidatorze IDLeak.
Proces rozpoczyna się od BB2, gdzie wartość AbstractValue określonej zmiennej lokalnej jest ustawiana na ::Other. Po wykonaniu BB2 proces zostaje przeniesiony do BB3, gdzie ta sama zmienna jest ustawiona na ::Fresh. Na końcu BB3 następuje krawędź skoku, która przeskakuje do BB2.
W procesie abstrakcyjnej interpretacji i analizy tego przykładu kluczową rolę odgrywa wspomniana wcześniej niespójność. Kiedy przetwarzane jest zbocze odbicia, interpreter abstrakcyjny próbuje połączyć stan BB3 po zamówieniu (zmienna to „::Fresh”) ze stanem zamówienia BB2 w przedsprzedaży (zmienna to „::Other”). Funkcja AbstractState::join zauważyła różnicę między starymi i nowymi wartościami i ustawiła flagę „change”, aby wskazać, że BB2 wymaga ponownej analizy.
Jednak dominujące zachowanie „::Other” w AbstractValue::join oznacza, że po połączeniu AbstractValue rzeczywista wartość zmiennej stanu BB2 nadal wynosi „::Other”, a wynik scalania stanów nie uległ zmianie.
Zatem kiedy ten proces cykliczny się rozpocznie, tj. gdy walidator będzie kontynuował ponowną analizę BB2 i wszystkich jego następczych podstawowych węzłów blokowych (w tym przypadku BB3), będzie on trwał w nieskończoność. Nieskończona pętla zużywa wszystkie dostępne cykle procesora, uniemożliwiając przetwarzanie odpowiedzi na nowe transakcje, a sytuacja ta utrzymuje się po ponownym uruchomieniu walidatora.
Wykorzystując tę lukę, węzły walidatora działają w nieskończonej pętli jak chomik biegający bez przerwy na kole, niezdolny do przetwarzania nowych transakcji. Dlatego nazywamy ten unikalny typ ataku atakiem „koła chomika”.
Atak typu „koło chomika” może skutecznie zatrzymać walidator Sui, paraliżując w ten sposób całą sieć Sui.
Po zrozumieniu przyczyny i procesu wyzwalania luki zbudowaliśmy konkretny przykład, korzystając z następującej symulacji kodu bajtowego Move, i pomyślnie uruchomiliśmy lukę w symulacji w środowisku rzeczywistym:

Ten przykład pokazuje, jak wywołać lukę w rzeczywistym środowisku za pomocą starannie skonstruowanego kodu bajtowego. W szczególności osoba atakująca może uruchomić nieskończoną pętlę w walidatorze IDLeak, wykorzystując ładunek o wielkości około 100 bajtów do wykorzystania wszystkich cykli procesora węzła Sui, skutecznie uniemożliwiając przetwarzanie nowych transakcji i powodując odmowę usługi w sieci Sui .
Trwałe szkody spowodowane atakami „koła chomika” w sieci Sui
Program nagród za błędy Sui zawiera rygorystyczne regulacje dotyczące oceny poziomów podatności, głównie w oparciu o stopień szkód w całej sieci. Luka spełniająca ocenę „krytyczną” musi wyłączyć całą sieć i skutecznie uniemożliwić potwierdzenie nowych transakcji, a do naprawienia problemu wymaga zastosowania hard forku; jeśli luka może spowodować tylko odmowę obsługi niektórych węzłów sieci, tak się stanie podatność oceniona najwyżej jako „średnie ryzyko” (średnie)” lub „wysokie”.
Luka w zabezpieczeniach „koła chomika” odkryta przez zespół CertiK Skyfall może spowodować zamknięcie całej sieci Sui i wymaga oficjalnego wydania nowej wersji w celu jej aktualizacji i naprawienia. Na podstawie wagi luki Sui ostatecznie ocenił ją jako „krytyczną”. Aby lepiej zrozumieć poważne skutki ataku „koła chomika”, musimy zrozumieć złożoną architekturę systemu zaplecza Sui, zwłaszcza cały proces udostępniania lub aktualizacji transakcji w łańcuchu.

Przegląd interakcji dotyczący przesyłania transakcji w Sui
Początkowo transakcje użytkowników są przesyłane za pośrednictwem interfejsu RPC i przekazywane do usługi zaplecza po podstawowej weryfikacji. Usługa backendu Sui jest odpowiedzialna za dalszą weryfikację przychodzącego ładunku transakcji. Po pomyślnej weryfikacji podpisu użytkownika transakcja zamieniana jest na certyfikat transakcji (zawierający informacje o transakcji oraz podpis Sui).
Te certyfikaty transakcji stanowią zasadniczą część działania sieci Sui i mogą być propagowane pomiędzy różnymi węzłami weryfikacyjnymi w sieci. W przypadku transakcji tworzenia/aktualizacji kontraktu węzeł weryfikacyjny wywoła walidator Sui w celu sprawdzenia i zweryfikowania ważności struktury kontraktu/semantyki tych certyfikatów, zanim będzie można je umieścić w łańcuchu. To właśnie podczas tej krytycznej fazy weryfikacji można wyzwolić i wykorzystać podatność na „nieskończoną pętlę”.
Wyzwolenie luki powoduje przerwanie procesu weryfikacji na czas nieokreślony, skutecznie ograniczając zdolność systemu do przetwarzania nowych transakcji i powodując całkowite zamknięcie sieci. Co gorsza, po ponownym uruchomieniu węzła sytuacja nadal istnieje, co oznacza, że tradycyjne środki łagodzące są zdecydowanie niewystarczające. Po uruchomieniu tej luki nastąpią „ciągłe szkody”, pozostawiając trwały wpływ na całą sieć Sui.
Rozwiązanie Sui
Po otrzymaniu informacji zwrotnej od CertiK, Sui szybko potwierdziła lukę i opublikowała poprawkę usuwającą krytyczną lukę. Poprawka zapewnia spójność między zmianami stanu i flagami po zmianie, eliminując krytyczny wpływ ataków „kołowrotkiem chomika”.

Aby wyeliminować powyższą niespójność, poprawka Sui zawiera niewielką, ale krytyczną korektę funkcji AbstractState::join. Ta poprawka usuwa logikę określania wyniku scalania stanów przed wykonaniem AbstractValue::join. Zamiast tego najpierw wykonuje funkcję AbstractValue::join w celu wykonania scalania stanów i określa, czy połączenie nastąpi, porównując ostateczny wynik aktualizacji ze stanem oryginalnym. wartość (stara_wartość). Zmień znak.
W ten sposób wynik łączenia stanów będzie zgodny z wynikiem rzeczywistej aktualizacji, a w procesie analizy nie wystąpi nieskończona pętla.
Oprócz naprawienia tej konkretnej luki, Sui wdrożyła rozwiązania zaradcze, aby zmniejszyć wpływ przyszłych luk w zabezpieczeniach modułu sprawdzania poprawności. Zgodnie z odpowiedzią Sui w raporcie o błędzie, ograniczenie polega na zastosowaniu funkcji zwanej Listą Odrzuconych.
„Jednak walidatorzy mają plik konfiguracyjny węzła, który pozwala im tymczasowo odrzucić pewne kategorie transakcji. Tej konfiguracji można użyć do tymczasowego wyłączenia przetwarzania wydań i aktualizacji pakietów. Z powodu tego błędu konieczne jest uruchomienie Sui przed podpisaniem wydania lub pakietu upgrade tx, podczas gdy lista odmów zatrzyma działanie modułu sprawdzającego i usunie złośliwy tx, tymczasowo odmów wystawienie tych typów tx jest w 100% skutecznym środkiem zaradczym (chociaż tymczasowo zakłóci działanie usługi każdemu, kto będzie próbował zwolnić lub zaktualizować kod).
Nawiasem mówiąc, od jakiegoś czasu mamy plik konfiguracyjny listy odmów TX, ale dodaliśmy także podobny mechanizm dla certyfikatów w ramach kolejnego rozwiązania łagodzącego lukę w zabezpieczeniach „nieskończonej pętli walidatora”, którą zgłosiłeś wcześniej. Dzięki temu mechanizmowi będziemy mieli większą elastyczność w przypadku tego ataku: użyjemy konfiguracji listy odrzuconych certyfikatów, aby walidator zapomniał o złych certyfikatach (przerwanie nieskończonej pętli), oraz konfiguracji listy odrzuconych TX, aby wyłączyć wydania/uaktualnienia, zapobiegając w ten sposób tworzeniu nowych transakcji złośliwych ataków. Dziękujemy, że dałeś nam o tym pomyśleć!
Walidator ma ograniczoną liczbę „taktów” (w przeciwieństwie do gazu) do weryfikacji kodu bajtowego przed podpisaniem transakcji, jeśli cały kod bajtowy wydany w transakcji nie może zostać zweryfikowany w określonej liczbie ticków, walidator odmówi podpisania transakcji, uniemożliwiając jej wykonywania w sieci. Wcześniej pomiary działały tylko w przypadku wybranego zestawu złożonych przejść walidatora. Aby uporać się z tym problemem, rozszerzamy pomiary na każdy walidator, aby zapewnić ograniczenie pracy wykonywanej przez walidator podczas procesu weryfikacji każdego znacznika. Naprawiliśmy także potencjalny błąd nieskończonej pętli w walidatorze wycieków ID. "
--Instrukcje od programistów Sui dotyczące poprawek błędów
Podsumowując, Denylist umożliwia weryfikatorom tymczasowe obejście exploitów w walidatorach i skuteczne zapobieganie potencjalnym szkodom spowodowanym przez niektóre złośliwe transakcje poprzez wyłączenie procesu wydawania lub aktualizacji. Kiedy środki łagodzące Denylist zaczną obowiązywać, węzły zapewniają możliwość kontynuowania pracy, rezygnując z własnych funkcji kontraktu publikowania/aktualizowania.

Streszczać
W tym artykule dzielimy się szczegółami technicznymi ataku „kołowrotkiem chomika” wykrytego przez zespół CertiK Skyfall, wyjaśniając, w jaki sposób ten nowy atak wykorzystuje kluczowe luki w zabezpieczeniach, powodując całkowite zamknięcie sieci Sui. Ponadto przyjrzeliśmy się bliżej szybkiej reakcji Sui w celu naprawienia tego krytycznego problemu i udostępniliśmy poprawkę luki oraz późniejsze metody łagodzenia podobnych luk.
