hamburger

(jeśli zgłaszasz przypadek phishingu, zapisz mail (przesuń go z programu pocztowego na pulpit komputera lub wybierz opcję plik/zapisz jako), a następnie załącz)

Podejrzany SMS prześlij na nr 508 700 900

Jeśli zgłoszenie dotyczy bezpieczeństwa dzieci, zgłoś je również pod http://www.dyzurnet.pl
@CERT_OPL

Poznaj swoją podatność – CVE-2024-1597

Podatności, które opisywałem do tej pory w serii „Poznaj swoją podatność”, choć wykryte, zgłoszone i poprawione bardzo daaawno temu (Log4j, Struts2 czy SnakeYAML) niestety cały czas są wykrywane w aplikacjach, działających w sieci. W przypadku dzisiejszego bohatera to akurat nie dziwi, bowiem to niespełna kilkutygodniowe zgłoszenie, dotyczące popularnym connectora do bazy danych PostgreSQL – CVE-2024-1597.

Czym jest PostgreSQL JDBC Driver?

Mowa o bibliotece w języku Java, służącej do komunikacji aplikacji Java z bazami danych PostgreSQL. Umożliwia ona aplikacjom wykonywanie zapytań SQL, aktualizowanie danych i zarządzanie transakcjami w sposób zoptymalizowany dla PostgreSQL. Dzięki niej, programiści mogą łatwo integrować bazę danych PostgreSQL z aplikacjami napisanymi w Javie, korzystając z standardowego API JDBC.
Prepared Statements natomiast to zaawansowane narzędzie w popularnych frameworkach, pozwalające na wydajne i bezpieczne wykonywanie zapytań SQL. Umożliwiają one prekompilację zapytania, co znacząco przyspiesza jego wykonanie, szczególnie przy wielokrotnym użyciu z różnymi parametrami. Ponadto, mechanizm ten chroni przed atakami SQL Injection, separując zapytania od danych wejściowych.

W Javie korzystanie z PreparedStatement wygląda następująco:

String sql = "SELECT * FROM users WHERE email = ?";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setString(1, "user@example.com");
ResultSet resultSet = statement.executeQuery();

W Pythonie, przy użyciu biblioteki psycopg2 dla PostgreSQL, przykład może wyglądać tak:

import psycopg2

conn = psycopg2.connect("dbname=test user=postgres")
cur = conn.cursor()
cur.execute("SELECT * FROM users WHERE email = %s", ("user@example.com",))
rows = cur.fetchall()

Niestety, pomimo dostępności tego typu funkcjonalności, w dalszym ciągu w weryfikowanych aplikacjach spotykam się z poniższą realizacją komunikacji do bazy danych:

String sql = "SELECT * FROM users WHERE email = '" + userEmail + "'";
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(sql);

W tym przypadku, userEmail jest bezpośrednio włączane do zapytania bez walidacji lub escape’owania, co pozwala na potencjalne wstrzyknięcie szkodliwego kodu SQL. Używanie tego podejścia zamiast PreparedStatement otwiera aplikację na ryzyko ataków SQL Injection, gdyż nie zapewnia żadnych mechanizmów bezpieczeństwa dla danych wejściowych.

I wtedy wjeżdża CVE-2024-1597

Czy zatem jeśli słuchasz zaleceń (m.in. moich), to możesz spać spokojnie? Niekoniecznie. Podatność CVE-2024-1597 pozwala bowiem na wstrzyknięcie kodu SQL do naszej aplikacji mimo tego, iż wszędzie do komunikacji z bazą wykorzystujemy mechanizm `prepared statement`. Oczywiście aby Twoja aplikacja była podatna na tego typu atak musi być spełnionych kilka warunków:

Włączenie prostego sposobu parsowania zapytań

Podczas inicjowania sterownika do bazy danych PSQL mamy do dyspozycji bogaty zestaw ustawień, pozwalający na odpowiednie dostosowanie konfiguracji. Jedno z tych ustawień dotyczy preferQueryMode

domyślnie ten parametr przyjmuje wartość extended, ale jeśli z jakiegoś powodu programista zdecyduje się na zmienienie tej wartości na preferQueryMode=simple, wyłączona zostaje duża część parsowania. A wtedy kreator zapytań wchodzi w tryb tekstowy. Samo włączenie tej opcji nie jest specjalnie niebezpieczne, jednak może przełożyć się na wydajność komunikacji z bazą danych w kontekście parsowania odpowiedzi na odpowiednie obiekty.

Zapytanie umieszczone w PreparedStatement musi zawierać negatywny parametr “-?”

Używanie negatywnych parametrów takich jak “-?” nie jest standardową praktyką i na szczęście nie znajduje zastosowania w dużej liczbie aplikacji. W zasadzie żaden przypadek aplikacji, który analizowałem w ciągu ostatnich 12 lat, nie implementował tego typu funkcjonalności. W rzeczywistości może być jednak różnie. Najlepiej wiesz jak to wygląda w Twojej aplikacji 🙂

Wykorzystanie podatności

Aby zilustrować na czym polega podatność spójrz na ten przykład:

PreparedStatement stmt = conn.prepareStatement("SELECT -?, ?");
stmt.setInt(1, -1);
stmt.setString(2, "\nWHERE false --");
ResultSet rs = stmt.executeQuery();

Zapisano tutaj proste zapytanie w formie select, z dwoma atrybutami do pobrania z bazy danych. Następnie umieszczono w dwóch kolejnych placeholderach wartości liczby całkowitej -1 oraz ciąg znaków \nWHERE false --. Dzięki temu, że w oryginalnym zapytaniu przed pierwszym placeholderem znajduje się - oraz temu, że -1 jest poprawną liczbą całkowitą, która mieści się w typie Integer. W rzeczywistości zapytanie, które wykona się na bazie danych będzie wyglądało jak poniżej:

SELECT --1,'
WHERE false --'

Zastosowanie negatywnego parametru i specjalnie sformatowanego ciągu tekstu może zmienić strukturę wykonanego zapytania, co pozwala na wstrzyknięcie niezamierzonej logiki. W szczególności, przez manipulację parametrami zapytania, atakujący może zmienić warunki zapytania lub wykonać zupełnie inne polecenia SQL, co może prowadzić do nieautoryzowanego dostępu do danych lub ich modyfikacji.

Usuwanie zagrożenia

Na szczęście, zaraz po opublikowaniu informacji o wykrytym zagrożeniu CVE-2024-1597 społeczność wypuściła zaktualizowaną wersję biblioteki. Poprawka zakłada, że nawet przy ustawieniu preferQueryMode=simple parametry parsowane są poprawnie. W konsekwencji próba stworzenia zapytania zaprezentowanego powyżej będzie skutkowała wykonaniem:

SELECT -('-1'::int4), ('
WHERE false --')

Czyli format, odporny na atak SQL Injection.

Wersje biblioteki z wdrożoną poprawką:

źródło: https://github.com/pgjdbc/pgjdbc/security/advisories/GHSA-24rp-q3w6-vc56

Jeśli z jakiegoś powodu nie masz możliwości jednak na “podbicie” wersji org.postgresql:postgresql zostaje Ci możliwość mitygacji poprzez pilnowanie tego, aby preferQueryMode nie przyjmował wartości simple.

Na koniec przypomnę:

Aplikacje starzeją się jak mleko, a nie jak wino – pilnuj tego aby w Twoim kodzie wykorzystywać aktualne wersje bibliotek.

Grzegorz Siewruk


Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Zobacz także

Komunikat dotyczący plików cookies

Ta witryna używa plików cookies (małych plików tekstowych, przechowywanych na Twoim urządzeniu). Są one stosowane dla zapewnienia prawidłowego działania strony oraz do zbierania informacji o Twoich preferencjach i nawykach użytkowania witryny.

Pliki cookies niezbędne do działania strony używamy do zapewnienia podstawowych funkcji, takich jak logowanie oraz zapewnienie bezpieczeństwa witrynie. Ich wykorzystanie nie wymaga Twojej zgody.

Pliki cookies funkcyjne. Pozwalają nam zbierać informacje na temat zalogowanych sesji oraz przechowywać dane wpisane przez Ciebie w formularzach znajdujących się na stronie takich jak: czas trwania zalogowanej sesji , nazwę użytkownika.

Pozostałe kategorie wykorzystywania plików cookies, które wymagają Twojej zgody na używanie

Pliki cookies statystyczne/analityczne. Pozwalają nam zbierać anonimowe informacje o ruchu na stronie (liczba odwiedzin, źródło ruchu i czas spędzony na witrynie). Te dane pomagają nam zrozumieć, jak nasi użytkownicy korzystają z witryny i poprawiają jej działanie.

Możesz zmienić swoje preferencje dotyczące plików cookies w każdej chwili. W celu zarządzania plikami cookies lub wycofania zgody na ich używanie, prosimy skorzystać z ustawień przeglądarki internetowej.