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