Mega Sekurak Hacking Party w Krakowie! 20.10.2025 r. Bilety -30%
Kolejny problem Fortineta – podatne FortiSIEM pod ostrzałem
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).

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
.

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