Remote Code Execution w OpenSSH. Podatność CVE-2023-38408

Czym jest OpenSSH?

OpenSSH stanowi otwartoźródłową implementację protokołu SSH. Stanowi jedno z najczęściej używanych narzędzi do bezpiecznej komunikacji oraz jest domyślnie zainstalowane w większości systemów operacyjnych z rodziny Linux, ale można z niego korzystać również na systemach z rodzin Windows NT oraz macOS. Standardowo składa się na niego serwer SSH oraz klient SSH.

Niestety, mimo wydawać by się mogło niezachwianej pozycji, OpenSSH tak jak każde inne oprogramowanie może być podatne na luki w bezpieczeństwie. Niedawno zespół z firmy Qualys odkrył podatność, polegającą na zdalnym wykonaniu kodu (Remote Code Execution — RCE), której przypisano numer CVE-2023-38408.

Gdzie jest dziura?

Podatność dotyczy składającego się na OpenSSH programu ssh-agent, który służy do przechowywania kluczy prywatnych w celu uwierzytelniania klucza publicznego. Główny program ssh posiada parametr -A, który umożliwia przekazywanie połączeń z agenta uwierzytelniania (jednym z nich jest ssh-agent). Polega to na tym, że lokalny agent SSH udostępnia swój klucz prywatny serwerowi zdalnemu na czas trwania połączenia. Serwer zdalny nie ma do niego bezpośredniego dostępu, ale może go używać do uwierzytelniania się w Twoim imieniu (np. żeby pobrać kod z zabezpieczonego zdalnego repozytorium). Warto w tym miejscu zaznaczyć, że ta opcja jest opatrzona przez twórców ostrzeżeniem.

Agent forwarding should be enabled with caution. Users with the
ability to bypass file permissions on the remote host … can access
the local agent through the forwarded connection. … A safer
alternative may be to use a jump host (see -J).
(https://man.openbsd.org/ssh.1)

Pomimo tego ostrzeżenia, jest to opcja bardzo często stosowana w nie do końca bezpieczny sposób, tylko dla wygody administratora. Ponadto okazuje się, że w tej opcji znajduje się luka bezpieczeństwa, której poświęcony jest ten artykuł. W dodatku spowodowana jest ona niekompletnym załataniem starszej podatności CVE-2016-10009.

Jak ta dziura wygląda?

Atakujący mający dostęp do serwera, do którego łączy się użytkownik z aktywowanym przekierowaniem agenta SSH ma możliwość załadowania poprzez wywołanie funkcji dlopen() dowolnej współdzielonej biblioteki z /usr/lib* na maszynie użytkownika, po czym jeśli biblioteka nie jest biblioteką pomocniczą PKCS#11 zostaje natychmiastowo wyładowana przez dlclose().
Wydawać by się mogło, że nawet mimo faktu, iż mamy do czynienia ze zdalnym załadowaniem biblioteki to atakujący nie jest w stanie zrobić nic ponadto, mając do dyspozycji tylko ładowanie bibliotek z tego katalogu, które natychmiast ulegają wyładowaniu. Jednakże okazuje się, że część bibliotek może wtedy wpływać na globalny stan programu:

  • Załadowanie pewnych bibliotek czyni stos wykonywalnym
  • Część bibliotek oznaczona jest flagą NODELETE, przez co ich pamięć tak naprawdę zostaje zachowana mimo wyładowania
  • Niektóre biblioteki w trakcie ładowania rejestrują własne funkcje (handlery) obsługujące sygnał SIGSEGV, których następnie nie wyrejestrowują dając możliwość zastąpienia kodu handlera kodem przeskakującym na stosowne miejsce na stosie, gdzie znajdować się może kod wstrzyknięty przez atakującego. Odpowiednia kombinacja tych bibliotek daje możliwość co prawda jednorazowego, ale zdalnego wykonania kodu na maszynie użytkownika.

Co robić, jak żyć?

Podatność została załatana (oby tym razem permanentnie) w wersji 9.3p2 OpenSSH, która została wydana 19 lipca 2023. Nie pozostaje więc nic innego jak aktualizować OpenSSH do najnowszej wersji.

Na pocieszenie można wspomnieć, że odkrywcom luki nie udało się znaleźć sposobu na exploitowanie jej w świeżo zainstalowanym systemie. Jednak nie wykluczają takiej możliwości, więc dla świętego spokoju najlepiej zainstalować najnowszą wersję OpenSSH.