OpenBSD, dystrybucja systemu operacyjnego typu open source, jest dobrze znana administratorom systemu, zwłaszcza tym, którzy zarządzają serwerami, ze względu na skupienie się na bezpieczeństwie, a nie szybkości, funkcjach i fantazyjnym interfejsie użytkownika.
Być może trafnie, jego logo to rozdymka – napompowana, z kolcami gotowymi do odparcia wszelkich przebiegłych hakerów, którzy mogą się pojawić.
Ale zespół OpenBSD jest prawdopodobnie najbardziej znany nie z całej dystrybucji, ale z zestawu narzędzi do zdalnego dostępu OpenSSH który został napisany pod koniec lat 1990. w celu włączenia go do samego systemu operacyjnego.
SSH, skrót od bezpieczna powłoka, został pierwotnie stworzony przez fińskiego informatyka Tatu Ylönen w połowie lat 1990. w nadziei na odzwyczajenie administratorów od ryzykownego nawyku używania protokołu Telnet.
Problem z Telnetem
Telnet był niezwykle prosty i skuteczny: zamiast podłączania fizycznych przewodów (lub korzystania z modemu przez linię telefoniczną) do nawiązywania połączenia dalekopisowego ze zdalnymi serwerami, używano połączenia TELetype NETwork.
Zasadniczo dane, które zwykle przepływałyby tam iz powrotem przez dedykowane połączenie szeregowe lub linię telefoniczną, były wysyłane i odbierane przez Internet przy użyciu połączenia sieciowego TCP z komutacją pakietów zamiast łącza punkt-punkt z komutacją obwodów .
Ten sam znajomy system logowania, tańsze połączenia, brak potrzeby stosowania dedykowanych linii danych!
Ogromną wadą Telnetu był oczywiście całkowity brak szyfrowania, więc wywęszenie dokładnej sesji terminala było trywialne, pozwalając hakerom zobaczyć każde wpisane polecenie (nawet błędy, które popełniłeś i wszystkie trafienia [Backspace]
), a każdy wyprodukowany bajt danych wyjściowych…
…i oczywiście swoją nazwę użytkownika i hasło na początku sesji.
Każdy na twojej ścieżce sieciowej mógłby nie tylko z łatwością zrekonstruować twoje sesje administratora w czasie rzeczywistym na własnym ekranie, ale prawdopodobnie także manipulować twoją sesją, modyfikując polecenia wysłane do zdalnego serwera i udając, że wracają odpowiedzi, abyś nie zauważył podstęp.
Mogą nawet założyć serwer oszustów, zwabić cię na niego i sprawić, że zaskakująco trudno będzie ci wykryć oszustwo.
Silne szyfrowanie FTW
SSH firmy Ylönen miało na celu dodanie warstwy silnego szyfrowania i uwierzytelniania na każdym końcu sesji podobnej do usługi Telnet, tworząc bezpieczna powłoka (to właśnie oznacza nazwa, jeśli kiedykolwiek się zastanawiałeś, chociaż prawie wszyscy to nazywają es-es-aitch w te dni).
To był natychmiastowy hit, a protokół został szybko przyjęty przez administratorów systemu na całym świecie.
Wkrótce potem pojawił się OpenSSH, jak wspomnieliśmy powyżej, po raz pierwszy pojawił się pod koniec 1999 roku jako część OpenBSD 2.6 zwolnić.
Zespół OpenBSD chciał stworzyć darmową, niezawodną implementację protokołu open-source, którą oni i ktokolwiek inny mógłby skorzystać, bez żadnych komplikacji licencyjnych ani komercyjnych, które utrudniały pierwotną implementację Ylönen w latach bezpośrednio po jej wydaniu.
Rzeczywiście, jeśli uruchomisz serwer Windows SSH i połączysz się z nim teraz z komputera z systemem Linux, prawie na pewno będziesz polegać na implementacji OpenSSH na obu końcach.
Protokół SSH jest również używany w innych popularnych usługach klient-serwer, w tym SCP i SFTP, skrót od bezpieczna kopia i bezpieczny FTP odpowiednio. SSH luźno oznacza „połącz się bezpiecznie i uruchom polecenie SHell na drugim końcu”, zwykle w przypadku logowania interaktywnego, ponieważ program Unix dla powłoki poleceń jest zwykle /bin/sh
. SCP jest podobny, ale dla kopiowania plików, ponieważ polecenie kopiowania plików w systemie Unix jest ogólnie nazywane /bin/cp
, a nazwa SFTP jest bardzo podobna.
OpenSSH nie jest jedynym zestawem narzędzi SSH w mieście.
Inne znane implementacje to: libssh2, dla programistów, którzy chcą wbudować obsługę SSH bezpośrednio we własne aplikacje; niedźwiedź, uproszczony serwer SSH od australijskiego programisty mat johnston jest to powszechnie spotykane na tak zwanych urządzeniach IoT (Internet of Things), takich jak domowe routery i drukarki; oraz PuTTY, popularna, bezpłatna kolekcja narzędzi związanych z SSH dla systemu Windows, stworzona przez niezależnego programistę typu open source Szymon Tatham w Anglii.
Ale jeśli jesteś zwykłym użytkownikiem SSH, prawie na pewno łączyłeś się dzisiaj z co najmniej jednym serwerem OpenSSH, między innymi dlatego, że większość współczesnych dystrybucji Linuksa zawiera go jako standardowe narzędzie do zdalnego dostępu, a Microsoft oferuje zarówno klienta OpenSSH, jak i OpenSSH server jako oficjalne komponenty systemu Windows.
Podwójna bezpłatna naprawa błędów
Wersja OpenSSH 9.2 właśnie wyszedł i Informacje o wydaniu zgłosić w następujący sposób:
To wydanie zawiera poprawki […] problemu z bezpieczeństwem pamięci. Uważa się, że [ten błąd] nie jest możliwy do wykorzystania, ale większość błędów pamięci dostępnych w sieci zgłaszamy jako błędy bezpieczeństwa.
Błąd wpływa na sshd
, serwer OpenSSH (tzw -d
przyrostek oznacza Demon, uniksowa nazwa rodzaju procesu działającego w tle, który system Windows nazywa a usługa):
sshd(8): naprawić błąd podwójnego zwolnienia pamięci przed uwierzytelnieniem wprowadzony w OpenSSH 9.1. Uważa się, że nie można tego wykorzystać i występuje w nieuprzywilejowanym procesie pre-aut, który podlega chroot (2) i jest dalej piaskownicą na większości głównych platform.
Podwójnie wolny błąd oznacza, że blok pamięci, który już zwróciłeś do systemu operacyjnego, ma być ponownie użyty w innych częściach twojego programu…
…później zostanie ponownie zwrócona przez część programu, która faktycznie nie „posiada” tej pamięci, ale o tym nie wie.
(Lub celowo oddane z powrotem na monit kodu, który próbuje celowo sprowokować błąd, aby włączyć wrażliwość w wykorzystać.)
Może to prowadzić do subtelnych i trudnych do rozwiązania błędów, zwłaszcza jeśli system oznaczy uwolniony blok jako dostępny, gdy pierwszy free()
dzieje się, później przypisuje go do innej części kodu, gdy prosi o pamięć przez malloc(
), a następnie ponownie oznacza blok wolny, gdy zbędne wezwanie do free()
pojawia się.
To pozostawia cię w sytuacji, której doświadczasz, gdy meldujesz się w hotelu, który mówi: „Och, dobre wieści! Myśleliśmy, że jesteśmy pełni, ale inny gość postanowił wymeldować się wcześniej, abyś mógł zająć jego pokój.”
Nawet jeśli pokój jest starannie posprzątany i przygotowany na przyjęcie nowych mieszkańców, kiedy wchodzisz, i wygląda na to, że został odpowiednio przydzielony do Twojego wyłącznego użytku, nadal musisz ufać, że karta dostępu poprzedniego gościa rzeczywiście została prawidłowo anulowana i że ich „ wcześniejsze wymeldowanie” nie było przebiegłym podstępem, by wymknąć się później tego samego dnia i ukraść laptopa.
Poprawka błędu dla poprawki błędu
Jak na ironię, jeśli spojrzysz na najnowszą historię kodu OpenSSH, zobaczysz, że OpenSSH miał skromny błąd w funkcji o nazwie compat_kex_proposal()
, używany do sprawdzania, jakiego rodzaju algorytmu wymiany kluczy należy użyć podczas konfigurowania połączenia.
Ale naprawa tego skromnego błędu wprowadziła zamiast tego poważniejszą lukę.
Nawiasem mówiąc, obecność błędu w części oprogramowania, która jest używana podczas konfiguracji połączenia, powoduje, że jest to tzw. dostępne w sieci wstępne uwierzytelnianie podatność (lub błąd przed autoryzacją w skrócie).
Błąd podwójnego zwolnienia występuje w kodzie, który musi zostać uruchomiony po klient zainicjował sesję zdalną, ale zanim miało miejsce jakiekolwiek uzgodnienie klucza lub uwierzytelnienie, więc teoretycznie luka może zostać uruchomiona, zanim jakiekolwiek hasła lub klucze kryptograficzne zostaną przedstawione do weryfikacji.
W OpenSSH 9.0, compat_kex_proposal
wyglądał mniej więcej tak (tutaj znacznie uproszczony):
char* compat_kex_proposal(char* suggestion) { if (condition1) { return suggestion; } if (condition2) { suggestion = allocatenewstring1(); } if (condition3) { suggestion = allocatenewstring2(); } if (isblank(suggestion)) { error(); } return suggestion; }
Pomysł polega na tym, że dzwoniący przekazuje swój własny blok pamięci zawierający ciąg tekstowy sugerujący ustawienie wymiany kluczy i otrzymuje z powrotem albo zgodę na użycie sugestii, którą wysłał, albo nowo przydzielony ciąg tekstowy ze zaktualizowaną sugestią .
Błąd polega na tym, że jeśli warunek 1 jest fałszywy, ale oba warunki 2 i 3 są prawdziwe, kod przydziela drugiej nowe ciągi tekstowe, ale tylko zwraca pierwszej.
Blok pamięci przydzielony przez allocatenewstring1()
nigdy nie jest zwalniany, a kiedy funkcja powraca, jej adres pamięci zostaje utracony na zawsze, więc nie ma możliwości, aby jakikolwiek kod free()
to w przyszłości.
Ten blok jest zasadniczo porzucony, powodując tzw wyciek pamięci.
Z biegiem czasu może to powodować problemy, być może nawet zmuszając serwer do zamknięcia w celu odzyskania sprawności po przeciążeniu pamięci.
W OpenSSH 9.1 kod został zaktualizowany, aby uniknąć przydzielania dwóch łańcuchów, ale porzucić jeden z nich:
/* Always returns pointer to allocated memory, caller must free. */ char* compat_kex_proposal(char* suggestion){ char* previousone = NULL; if (condition1) { return newcopyof(suggestion); } if (condition2) { suggestion = allocatenewstring1(); } if (condition3) { previousone = suggestion; suggestion = allocatenewstring2(); } free(previousone); } if (isblank(suggestion()) { error(); } return suggestion; }
Ma to błąd podwójnego zwolnienia, ponieważ jeśli warunek 1 i warunek 2 są fałszywe, ale warunek 3 jest prawdziwy, to kod przydziela nowy ciąg znaków do odesłania jako odpowiedź…
… ale niepoprawnie zwalnia łańcuch, który pierwotnie przekazał wywołujący, ponieważ funkcja allocatenewstring1()
nigdy nie jest wywoływana w celu aktualizacji zmiennej suggestion
.
Przekazany ciąg sugestii jest pamięcią należącą do dzwoniącego, i że dzwoniący zwolni później motywy, co prowadzi do niebezpieczeństwa podwójnego uwolnienia.
W OpenSSH 9.2 kod stał się bardziej ostrożny, śledząc wszystkie trzy możliwe bloki pamięci: oryginalny suggestion
(pamięć należąca do kogoś innego) oraz dwa możliwe nowe ciągi, które mogą zostać przydzielone po drodze:
/* Always returns pointer to allocated memory, caller must free. */ char* compat_kex_proposal(char* suggestion) { char* newone = NULL; char* newtwo = NULL; if (condition1) { return newcopyof(suggestion); } if (condition2) { newone = allocatenewstring1(); } if (condition3) { newtwo = allocatenewstring2(); } free(newone); newone = newtwo; } if (isblank(newone)) { error(); } return newone; }
Jeśli warunek 1 jest prawdziwy, używana jest nowa kopia przekazanego ciągu, więc wywołujący może to zrobić później free()
pamięci przekazanego ciągu znaków, kiedy tylko zechcą.
Jeśli przekroczymy warunek 1, a warunek 2 jest prawdziwy, ale warunek 3 jest fałszywy, wówczas alternatywna sugestia utworzona przez allocatenewstring1()
zostanie zwrócony i przekazany suggestion
ciąg zostaje sam.
Jeśli warunek 2 jest fałszywy, a warunek 3 jest prawdziwy, zostanie wygenerowany i zwrócony nowy ciąg, a następnie przekazany suggestion
ciąg zostaje sam.
Jeśli zarówno warunek 2, jak i warunek 3 są prawdziwe, po drodze przydzielane są dwa nowe łańcuchy; pierwszy zostaje zwolniony, ponieważ nie jest potrzebny; drugi jest zwracany; i przekazany suggestion
ciąg zostaje sam.
Możesz RTxM aby to potwierdzić, jeśli zadzwonisz free(newone)
jeśli chodzi o komunikację i motywację newone
is NULL
, to „żadna operacja nie jest wykonywana”, ponieważ zawsze jest to bezpieczne free(NULL)
. Niemniej jednak wielu programistów nadal solidnie chroni się przed nim za pomocą kodu takiego jak if (ptr != NULL) { free(ptr); }
.
Co robić?
Jak sugeruje zespół OpenSSH, wykorzystanie tego błędu będzie trudne, między innymi ze względu na ograniczone uprawnienia, które zapewnia sshd
program ma podczas konfigurowania połączenia do użytku.
Niemniej jednak zgłosili to jako lukę w zabezpieczeniach, ponieważ tak właśnie jest, więc upewnij się, że dokonałeś aktualizacji OpenSSH 9.2.
A jeśli piszesz kod w C, pamiętaj, że bez względu na to, jak bardzo masz doświadczenie, zarządzanie pamięcią jest łatwe do pomyłki…
…więc uważaj na siebie.
(Tak, Rust i jego współcześni przyjaciele będą pomoc w napisaniu poprawnego kodu, ale czasami nadal będziesz musiał używać C, a nawet Rust nie może tego zagwarantować powstrzymaj się od pisania nieprawidłowego kodu jeśli programujesz nierozsądnie!)
- Dystrybucja treści i PR oparta na SEO. Uzyskaj wzmocnienie już dziś.
- Platoblockchain. Web3 Inteligencja Metaverse. Wzmocniona wiedza. Dostęp tutaj.
- Źródło: https://nakedsecurity.sophos.com/2023/02/03/openssh-fixes-double-free-memory-bug-thats-pokable-over-the-network/