Mega Sekurak Hacking Party w Krakowie! 20.10.2025 r. Bilety -30%

Kolejny problem Fortineta – podatne FortiSIEM pod ostrzałem

18 sierpnia 2025, 02:32 | W biegu | 0 komentarzy

Mamy wrażenie, że nie tylko nas zaczynają nużyć problemy produktów bezpieczeństwa, zwłaszcza od kilku firm… . Tym razem legendarny badacz SinSinology prezentuje krytyczną podatność (9.8 w skali CVSS w biuletynie bezpieczeństwa producenta) w produkcie dedykowanym dużym organizacjom – FortiSIEM.

TLDR:

  • @SinSinology z WatchTowr opublikował analizę, wykorzystywanej przez cyberprzestępców, podatności w produkcie FortiSIEM
  • Podatność pozwala na zdalne wykonanie kodu bez uwierzytelnienia
  • Zalecana jest natychmiastowa aktualizacja lub ograniczenie dostępu do portu tcp/7900, na którym działa phMonitor – proces odpowiedzialny za sprawdzanie poprawności działania FortiSIEMa

Sprawa nie jest błaha, ponieważ jak informuje Fortinet luka ta jest wykorzystywana w rzeczywistości przez przestępców. Podatność dotyka następujących wersji:

FortiSIEM 7.4	Not affected	Not Applicable
FortiSIEM 7.3	7.3.0 through 7.3.1	Upgrade to 7.3.2 or above
FortiSIEM 7.2	7.2.0 through 7.2.5	Upgrade to 7.2.6 or above
FortiSIEM 7.1	7.1.0 through 7.1.7	Upgrade to 7.1.8 or above
FortiSIEM 7.0	7.0.0 through 7.0.3	Upgrade to 7.0.4 or above
FortiSIEM 6.7	6.7.0 through 6.7.9	Upgrade to 6.7.10 or above
FortiSIEM 6.6	6.6 all versions	Migrate to a fixed release
FortiSIEM 6.5	6.5 all versions	Migrate to a fixed release
FortiSIEM 6.4	6.4 all versions	Migrate to a fixed release
FortiSIEM 6.3	6.3 all versions	Migrate to a fixed release
FortiSIEM 6.2	6.2 all versions	Migrate to a fixed release
FortiSIEM 6.1	6.1 all versions	Migrate to a fixed release
FortiSIEM 5.4	5.4 all versions	Migrate to a fixed release

FortiSIEM (jak nazwa może sugerować) to SIEM (Security Information and Event Management) czyli rozwiązanie służące do zbierania i analizowania zdarzeń w sieci w celu wykrycia incydentów bezpieczeństwa a następnie pozwalające odpowiednio taki incydent obsłużyć. Generalnie jest to całkiem ważny (centralny) element pozwalający spojrzeć od góry na bezpieczeństwo środowiska teleinformatycznego. A ponieważ oprogramowanie takie zbiera logi z wielu systemów, zawierające przeróżne informacje, to bezpieczeństwo samego SIEMa jest kluczowym składnikiem całej organizacji. Warto więc zadbać o to, aby rozwijany był w sposób rozsądny, z zastosowaniem najlepszych praktyk programistycznych. Prezentowana podatność powoduje, że podchodzimy lekko sceptycznie do takiego scenariusza. Ale spokojnie, to nie pierwszy command injection w FortiSIEM.

Nie pierwszy raz opisujemy podatność, która została ponownie odkryta przez badaczy na podstawie wykrywania różnic w wersji poprawionej oraz podatnej – jest to tzw. patch-diffing. Można go wykonać nie tylko na kodzie źródłowym, ale także na binariach, co czasami bywa jedyną metodą w przypadku braków źródeł (czyli standardowo w większości rozwiązań enterprise na licencjach własnościowych). 

Porównanie binarek poprawionych, oraz tych dziurawych przynosi standardowy widok ostatnimi czasy – dużo zmian zostało wprowadzonych między wersjami. Jednak tylko nieliczne aktualizacje łatają rzeczywiste, wykorzystywane podatności (może reszta to tzw. hardening? albo implementacja nowych funkcjonalności? albo poprawa elementów, co do których producent wie, że również mogą stanowić problemy bezpieczeństwa? nikt by przecież nie ukrywał podatności w masie aktualizacji). 

Rysunek 1. Fragment listy zmienionych funkcji (źródło)

Jednak odrobina ręcznej analizy zawsze pokazuje potencjalne wzorce, które wskazują na to, że w danym miejscu usunięto podatność. Tym razem również tak się stało. Za winną zamieszania, badacz wskazał funkcję phMonitorProcess::handleStorageArchiveRequest. Jest to metoda obsługująca żądanie archiwizacji, która pod spodem parsuje przesłanego XML’a a następnie, wykorzystując wyłuskane parametry, wywołuje lokalnie narzędzie /opt/phoenix/deployment/jumpbox/datastore.py.

Rysunek 2. Różnica pomiędzy fragmentem podatnego kodu (lewa strona) i poprawionego (prawa strona) (źródło)

Kluczowym elementem podatnego kodu, jest fragment przedstawiony na listingu 1. Odsyłamy do oryginalnego posta, gdzie przedstawiony został pełen kontekst podatności.

ShellCmd::addParaSafe(&v129, &archive_nfs_server_ip);  // [15] Add NFS server IP as parameter
    ShellCmd::addParaSafe(&v129, &archive_nfs_archive_dir);  // [16] Add NFS archive directory as parameter
    std::string::basic_string<std::allocator<char>>(v134, " \\t\\r\\n\\v'");
    v71 = v132;
    std::string::basic_string<std::allocator<char>>(v132, "archive");
    ShellCmd::addPara(&v129, v132, v134);  // [17] Add "archive" parameter
    if ( v132[0] != v133 )
      operator delete(v132[0]);
    if ( (_BYTE *)v134[0] != v135 )
      operator delete(v134[0]);
    LOBYTE(requested_time.tv_sec) = 0;
    ShellCmd::str[abi:cxx11](v134, &v129);  // [18] Build the complete command string
    phMiscUtils::do_system_cancellable(  // [19] Execute the system command
      v134[0],
      (const char *)&requested_time,
      (bool *)&dword_0 + 1,
      0,
      (unsigned int)&v98,
      0,
      v62);

Listing 1. Podatny fragment kodu (źródło)

Przytoczony fragment funkcji odpowiada za zbudowanie polecenia, które jest wywoływane przez metodę phMiscUtils::do_system_cancellable. Pythonowy skrypt przywołany wcześniej operuje na parametrach pozyskanych z przesłanego dokumentu XML (do jego przesłania nie jest wymagane uwierzytelnienie). Dane pochodzące od użytkownika, takie jak adres IP serwera NFS oraz katalog są sanityzowane przez metodę ShellCmd::addParaSafe, która dokonuje escapowania (umieszcza znak ucieczki \) cudzysłowów, co w zamierzeniu autorów miało ograniczyć możliwość wykonania ataku typu command injection (czyli wstrzyknięcia własnego polecenia w komendę wykonywaną przez aplikację). 

Jeśli w przesyłanym XML, przekazywano następujące wartości (listing 2)

<root>
    <archive_storage_type>nfs</archive_storage_type>
    <archive_nfs_server_ip>127.0.0.1</archive_nfs_server_ip>
    <archive_nfs_archive_dir>/nfs1</archive_nfs_archive_dir>
    <scope>local</scope>
</root>

Listing 2. Przykładowe dane zapytania (źródło)

to wynikiem działania metody phMonitorProcess::handleStorageArchiveRequest było wywołanie polecenia:

/opt/phoenix/deployment/jumpbox/datastore.py nfs test 127.0.0.1 /nfs1 archive

Jak widać samo określenie “safe” w metodzie dokonującej tzw. sanityzacji nie jest wystarczające, aby była ona bezpieczna. Trywialnym obejściem tego zabezpieczenia jest wykorzystanie znaku ` (gravis/backtick) w celu umieszczenia jednego polecenia wewnątrz innego. Wewnętrzna komenda zostanie wykonana wcześniej a jej wynik zostanie, przez powłokę, załączony do wywołania zewnętrznej komendy – command injection technique 101 ;)

Krótki PoC pozwalający na utworzenie pliku /tmp/boom wygląda więc następująco:

<root>
    <archive_storage_type>nfs</archive_storage_type>
    <archive_nfs_server_ip>127.0.0.1</archive_nfs_server_ip>
    <archive_nfs_archive_dir>`touch${IFS}/tmp/boom`</archive_nfs_archive_dir>
    <scope>local</scope>
</root>

Listing 3. Payload tworzący plik /tmp/boom z wykorzystaniem command injection (źródło)

watchTowr Labs opublikowało narzędzie pozwalające określić, czy Wasz SIEM jest zabezpieczony przed tym atakiem. Nie pozostaje nic innego jak życzyć bezproblemowej aktualizacji oraz liczyć na to, że dostęp do organizacyjnych SIEMów jest na tyle utrudniony, że atakujący nie będą mieli okazji wykorzystać tej podatności do czasu wgrania potrzebnych łatek. Jednym z proponowanych obejść, w przypadku braku możliwości zaaplikowania patcha jest zablokowanie na zaporze systemowej portu 7900. 

~Black Hat Logan

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

Odpowiedz