Czasami najlepsze błędy to te najprostsze. Nie potrzebujesz skomplikowanych łańcuchów RCE ani magii z przepełnieniem bufora, żeby dobrać się do wrażliwych danych. Czasem wystarczy po prostu… ładnie zapytać serwer, używając nieco innej metody HTTP. Tak właśnie było podczas moich ostatnich testów penetracyjnych platformy Computer Vision Annotation Tool (CVAT).
Znaleziony przeze mnie błąd dorobił się oficjalnego numerka CVE-2024-47172 oraz biuletynu bezpieczeństwa na GitHubie (GHSA-gxhm-hg65-5gh2). Luka została załatana, więc możemy bez ogródek zajrzeć pod jej maskę.
Podatność otrzymała scoring 5.4 (wektor: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N). Zobaczmy, jak deweloperzy zapomnieli o podstawowej zasadzie: nigdy nie ufaj danym od użytkownika, ani metodom, którymi je przesyła.
TL;DR - Najważniejsze wnioski
- Co poszło nie tak?
- Proof of Concept (Weryfikacja Koncepcji)
- Co wyciekało?
- Jak to naprawić? (Remediacja)
Co poszło nie tak?
Aplikacja CVAT (podatne wersje m.in. Server: 2.16.3, UI: 1.64.5) to potężne narzędzie do adnotacji danych w projektach Computer Vision. Znajdziemy tam podział na Projekty, Zadania (Tasks) i Prace (Jobs). Każdy z tych elementów ma swój własny, sekwencyjny identyfikator numeryczny (np. /api/jobs/2137).
Gdy standardowy, zalogowany użytkownik próbuje odpytać API o zadanie należące do kogoś innego za pomocą metody GET, aplikacja działa bezbłędnie. Zwraca soczyste:
Listy kontroli dostępu (ACL) robią to, za co im płacą. Ale co, jeśli przepuścimy ruch przez narzędzie takie jak Burp Suite i w module Repeater zmienimy metodę z GET na PATCH?
Proof of Concept (Weryfikacja Koncepcji)
Wysyłając zmodyfikowane żądanie:
Nagle zaporowy mur znika. Serwer odpowiada kodem HTTP/1.1 200 OK i wypluwa pełnego JSON-a z danymi cudzego zadania! Ominęliśmy sprawdzanie uprawnień na poziomie obiektu (Insecure Direct Object Reference - IDOR).
Skala problemu
Błąd ten występował na wielu krytycznych endpointach: /api/jobs/<ID>, /api/projects/<ID> oraz /api/tasks/<ID>. Wystarczyło użyć modułu Intruder, iterować parametr <ID> (skoro to zwykły int, to brute-force jest banalny) i zgarniać dane innych użytkowników.
Co wyciekało?
Informacje takie jak project_id, organization_id, issues_url, adresy repozytoriów docelowych (target_storage) czy dane przypisanych osób (assignee, username, first_name, last_name). Dla atakującego to prawdziwa kopalnia wiedzy do dalszego rekonesansu lub ataków phishingowych.
- project_id i organization_id, identyfikatory pozwalające na mapowanie struktury organizacyjnej ofiary.
- assignee (username, first_name, last_name), dane osobowe przypisanych użytkowników.
- target_storage, adresy repozytoriów docelowych, potencjalnie ujawniające infrastrukturę chmurową.
- issues_url, linki do trackerów błędów, mogące zawierać poufne informacje o projektach.
Dlaczego to groźne?
Wyciek tych danych to nie tylko naruszenie prywatności. Atakujący uzyskuje pełny obraz organizacji: kto pracuje nad jakimi projektami, jak wygląda infrastruktura i gdzie szukać kolejnych podatności. To idealny punkt wyjścia do ataków socjotechnicznych.

Jak to naprawić? (Remediacja)
Ten przypadek to klasyczne przypomnienie o dwóch kluczowych rzeczach w bezpieczeństwie aplikacji:
- Kompletna kontrola dostępu: Sprawdzanie uprawnień (Access Control) musi być zaimplementowane dla każdego punktu końcowego i każdej obsługiwanej metody HTTP (GET, POST, PUT, PATCH, DELETE), a nie tylko dla domyślnego GET.
- Koniec z sekwencyjnymi ID: Przestańmy w końcu używać sekwencyjnych identyfikatorów numerycznych! Zastąpienie zwykłych ID-ków losowymi wartościami UUID (podejście Defense-in-depth) sprawiłoby, że nawet przy błędnie napisanym ACL, atakujący miałby drastycznie utrudnione zadanie ze ślepym odgadywaniem (brute-force) identyfikatorów zasobów.
Złota zasada pentestera
Testując API, zawsze żonglujcie metodami (PUT, PATCH, DELETE, OPTIONS). Czasami serwer po prostu zapomina, że z innej strony też trzeba zamknąć drzwi.
Sekwencyjne ID = trywialne do odgadniecia (brute-force)
UUID v4 = 2122 mozliwych wartosci (Defense-in-depth)

Podsumowanie
CVE-2024-47172 to podręcznikowy przykład podatności IDOR, w której zmiana jednej metody HTTP (z GET na PATCH) wystarczyła do ominięcia kontroli dostępu w popularnym narzędziu do adnotacji danych CVAT. Luka pozwalała na enumerację i odczyt danych innych użytkowników, ich projektów, zadań i danych osobowych. Została odpowiedzialnie zgłoszona i załatana, ale pozostaje doskonałą lekcją: kontrola dostępu musi obejmować każdy endpoint i każdą metodę HTTP, a sekwencyjne identyfikatory to zaproszenie dla atakujących.
Bibliografia
Oficjalny wpis w bazie NIST NVD opisujący podatność IDOR w CVAT z oceną CVSS 5.8.
Biuletyn bezpieczeństwa opublikowany na GitHubie przez zespół CVAT, zawierający szczegóły podatności i informacje o poprawce.
Kategoria OWASP opisująca podatności związane z nieprawidłową kontrolą dostępu na poziomie obiektów, dokładnie ten typ błędu, który został wykorzystany w CVE-2024-47172.
Repozytorium open-source narzędzia CVAT do adnotacji danych w projektach uczenia maszynowego i Computer Vision.

