Badanie Cyberbezpieczeństwa Aplikacji CakePHP – Omijanie Mechanizmów Zabezpieczeń podczas Skanowania Podatności w CakePHP
Skanowanie Podatności w Aplikacjach CakePHP
Jeśli chcesz przeprowadzić skanowanie podatności w swojej aplikacji webowej opartej na CakePHP, musisz odpowiednio skonfigurować narzędzie skanujące. W przeciwnym razie skanowanie nie będzie skuteczne, a Ty możesz uzyskać fałszywe poczucie bezpieczeństwa, ponieważ narzędzie nie wykryje rzeczywistych podatności aplikacji.
W przypadku aplikacji webowej opartej na CakePHP poprawna konfiguracja narzędzia do skanowania podatności może być bardzo trudna, a w niektórych przypadkach wręcz niemożliwa. Istnieją jednak metody pozwalające rozwiązać ten problem i skutecznie przeprowadzić skanowanie podatności.
Przykłady, które tutaj przedstawiam, bazują na skanerze Burp Suite Pro – jednym z najpopularniejszych skanerów DAST używanych przez ekspertów ds. cyberbezpieczeństwa, testerów penetracyjnych, łowców bugów oraz organizacje wdrażające tego typu rozwiązania w ramach procesów CI/CD.
Skanowanie podatności a uwierzytelnianie
Uwierzytelnianie to jeden z najważniejszych mechanizmów bezpieczeństwa w większości aplikacji webowych – nie tylko tych opartych na CakePHP. Proces ten polega na weryfikacji tożsamości użytkownika. Za każdym razem, gdy podajesz swoją nazwę użytkownika i hasło podczas logowania do aplikacji, przechodzisz proces uwierzytelniania. Jeśli aplikacja obsługuje uwierzytelnianie wieloskładnikowe (MFA) lub logowanie za pomocą mediów społecznościowych, są to również formy uwierzytelniania.
To ensure that the vulnerability scanning process scans as many endpoints as possible, we must ensure that the scanner can successfully authenticate to the application. Otherwise, the scanner will only see the login page and a few other pages that are available to unauthenticated users.
Aby skanowanie podatności obejmowało jak najwięcej endpointów, musimy upewnić się, że skaner jest w stanie pomyślnie uwierzytelnić się w aplikacji. W przeciwnym razie zobaczy jedynie stronę logowania oraz kilka innych stron dostępnych dla niezalogowanych użytkowników.
Framework CakePHP umożliwia programistom implementację różnych metod uwierzytelniania za pomocą dedykowanych wtyczek. Najczęściej stosowaną wtyczką jest Authentication Plugin, stworzony przez zespół CakePHP. Istnieją także inne rozwiązania obsługujące alternatywne metody uwierzytelniania, takie jak JWT, logowanie przez media społecznościowe, uwierzytelnianie dwuskładnikowe i inne. Każda z tych metod wymaga odpowiedniej konfiguracji przed rozpoczęciem skanowania podatności. W tym artykule skupię się na najpopularniejszym pluginie opracowanym przez twórców CakePHP.

CEO, Cybersecurity Expert
Jeśli chcesz przeprowadzić test penetracyjny typu white box swojej aplikacji webowej, zostaw swój adres e-mail, a skontaktuję się z Tobą.
Umów się na rozmowę ze mną
Skanowanie podatności uwierzytelnionych użytkowników przy użyciu Burp Suite Pro
Z perspektywy bezpieczeństwa uwierzytelnianie w aplikacjach CakePHP za pomocą loginu i hasła działa podobnie jak w innych systemach. Oznacza to, że możemy skonfigurować narzędzie do skanowania podatności tak, aby poprawnie uwierzytelniało się przed rozpoczęciem analizy.
W skanerze Burp Suite Pro proces ten można przeprowadzić podczas tworzenia nowego skanowania. Na początek należy kliknąć przycisk New Scan w zakładce Dashboard:

Następnie trzeba określić adresy URL do skanowania oraz wybrać typ skanowania, jak pokazano poniżej:


Po przejściu do sekcji Application Login należy utworzyć nowe dane logowania:

Po uzupełnieniu konfiguracji klikamy OK, aby rozpocząć skanowanie:

Po uruchomieniu skanowania można przejść do zakładki Logger, klikając View details:

W zakładce Logger zobaczymy, że skaner w pewnym momencie uwierzytelnia się w aplikacji, uzyskując dostęp do pozostałych funkcji.
Na poniższym zrzucie ekranu widoczne są dane logowania wprowadzone podczas konfiguracji skanera. Aplikacja poprawnie uwierzytelniła narzędzie skanujące:

Należy jednak pamiętać, że w niektórych przypadkach różne konfiguracje mogą wykorzystywać dane uwierzytelniające w odmienny sposób. Może to prowadzić do ograniczonego skanowania z powodu np. blokady konta po wielokrotnych nieudanych próbach logowania. W naszym przykładzie zastosowaliśmy konfigurację skanowania Light Only.
Jeśli skaner nie jest w stanie przejść procesu uwierzytelniania, można spróbować ominąć ten mechanizm, korzystając z alternatywnej metody opisanej w sekcji „Wyłączanie uwierzytelniania w CakePHP„.
Ograniczanie podatności aplikacji webowych poprzez autoryzację i kontrolę dostępu
Autoryzacja jest często mylona z uwierzytelnianiem. Celem autoryzacji nie jest weryfikacja tożsamości użytkownika, lecz sprawdzenie, jakie uprawnienia i przywileje ma już uwierzytelniony użytkownik w odniesieniu do danych i funkcjonalności aplikacji.
Najprostszym przykładem może być aplikacja e-commerce. Można sobie wyobrazić dwóch użytkowników, którzy uwierzytelniają się w aplikacji, składają zamówienia na różne produkty i otrzymują faktury za swoje zakupy. Oczywistym jest, że jeden użytkownik nie powinien mieć dostępu do faktury drugiego, mimo że obaj są uwierzytelnieni. Równie ważne, jeśli nie ważniejsze, jest to, że osoba niebędąca klientem nie powinna mieć dostępu do żadnej z tych faktur. Mechanizm, który to zapewnia, nazywany jest autoryzacją.
Autoryzacja i Kontrola Dostępu w CakePHP
Podczas analizy uprawnień i przywilejów użytkowników w aplikacji opartej na CakePHP kontrola dostępu jest synonimem autoryzacji.
Istnieją jednak sytuacje, w których tych pojęć nie można stosować zamiennie. W takich przypadkach autoryzacja odnosi się do procesu definiowania poziomów dostępu dla określonych użytkowników, typów użytkowników, ról, grup itp. Kontrola dostępu natomiast wymusza przestrzeganie tych definicji, czasem dodając dodatkowe polityki, takie jak ograniczenia geograficzne, restrykcje dotyczące typu urządzenia itd.
Bez względu na kontekst, oba te pojęcia są ze sobą ściśle powiązane.
W aplikacjach webowych opartych na CakePHP autoryzacja jest często realizowana za pomocą wtyczek. Najczęściej stosowanym rozwiązaniem jest oficjalna wtyczka „Authorization„ opracowana przez zespół CakePHP.
Sposób implementacji procesu autoryzacji może się różnić w zależności od aplikacji.
Na przykład Cerebrate definiuje, które zasoby mogą być dostępne dla określonych typów użytkowników, za pomocą dedykowanego ACLComponent.
Na poniższym zrzucie ekranu można zobaczyć, że niektóre pary kontroler-akcja są dostępne tylko dla użytkowników z rolą „perm_admin”, podczas gdy inne mogą być wykonywane przez każdego uwierzytelnionego użytkownika.

Z kolei w innych aplikacjach wymagane role lub uprawnienia są określane bezpośrednio w akcjach kontrolerów. Przykładem może być metoda addPost w kontrolerze UsersAdd w aplikacji PassBolt:

Jest to często stosowane rozwiązanie, gdy różne zachowanie akcji jest wyzwalane w zależności od roli użytkownika wykonującego daną operację.
Aplikacja może również oznaczyć kontrolery dostępne dla nieuwierzytelnionych użytkowników poprzez wywołanie metody skipAuthorization
komponentu Authorization. Warto przeanalizować kod źródłowy aplikacji w poszukiwaniu takich miejsc, ponieważ to właśnie one mogą być najbardziej narażone na ataki.
Komponent bezpieczeństwa w CakePHP
Komponent SecurityComponent
w CakePHP chroni przed wieloma rodzajami podatności aplikacji webowych. Można go zaimplementować w kontrolerach aplikacji, używając następującej instrukcji:
$this->loadComponent('Security');
Po załadowaniu tej klasy domyślnie aktywowana zostaje ochrona przed manipulacją formularzami.
Odkrywanie dodatkowych podatności poprzez ominięcie ochrony przed manipulacją formularzami
Domyślnie mechanizm ochrony przed manipulacją formularzami w CakePHP weryfikuje wszystkie żądania POST i zapewnia, że przekazywane są jedynie oczekiwane parametry. Blokuje on każde żądanie spełniające co najmniej jeden z poniższych warunków:
- Do żądania POST dodano nieoczekiwane pole.
- Usunięto wymagane pole z żądania POST.
- Zmieniono wartość pola ukrytego.
Jest to w zasadzie zaawansowany mechanizm whitelistingu dla parametrów w treści żądania POST.
Oznacza to, że jeśli przechwycisz żądanie POST i dodasz do niego nowy parametr, CakePHP je zablokuje.
Mechanizm ten działa dzięki temu, że SecurityComponent oblicza hash oczekiwanych parametrów i przesyła go w żądaniu POST. Implementacja tej funkcji znajduje się w pliku SecurityComponent.php, w metodzie _validatePost:
protected function _validatePost(Controller $controller): void { $token = $this->_validToken($controller); $hashParts = $this->_hashParts($controller); $check = hash_hmac('sha1', implode('', $hashParts), Security::getSalt()); if (hash_equals($check, $token)) { return; }
Linia 1 odpowiada za ekstrakcję tokena przesłanego w żądaniu HTTP w polu _Token[fields].
Linia 2 pobiera informacje z żądania, które zostaną później użyte do obliczenia hasha. $hashParts to tablica zawierająca następujące dane:
- Ścieżka URL, np.
/EncryptionKeys/edit/2
. - Nazwy parametrów POST, zserializowane i posortowane, związane z danym żądaniem. Przykładowo:
"a:3:{i:0;s:14:"encryption_key";i:1;s:7:"revoked";i:2;s:4:"type";}"
(nie obejmuje to ogólnych parametrów, takich jak _method, _csrfToken czy _Token, oraz wyklucza odblokowane parametry). - Wartość parametru _Token[unlocked].
- Identyfikator sesji.
Elementy tej tablicy są łączone w jeden ciąg znaków, a następnie w linii 3 obliczany jest hash SHA1 przy użyciu saltu aplikacji.
Jeśli obliczony hash zgadza się z hashem podanym w _Token[fields], żądanie przechodzi walidację i kierowane jest do dalszej weryfikacji.
Ominięcie ochrony przed manipulacją formularzami podczas testów penetracyjnych white box
Czy możliwe jest ominięcie tej ochrony?
Pierwszą rzeczą do sprawdzenia jest to, czy w danej aplikacji ochrona ta nie została wyłączona.
W kodzie źródłowym kontrolerów warto szukać linii podobnych do tej:
$this->Security->setConfig('unlockedActions', ['edit']);
Powyższa instrukcja dezaktywuje ochronę dla akcji edit.
Zdarza się, że ochrona jest wyłączona dla całego kontrolera, a nawet dla całej aplikacji. Przykładowo, poniższa linia kodu całkowicie dezaktywuje mechanizm walidacji żądań POST:
$this->Security->setConfig('validatePost', false);
Jeśli przeprowadzasz testy penetracyjne black-box, możesz wykryć tę lukę, dodając parametr do wszystkich żądań POST w różnych akcjach kontrolerów.
Czasami aplikacje dezaktywują ochronę przed manipulacją formularzami dla żądań API. W takiej sytuacji warto spróbować dodać nagłówek Accept z wartością JSON/XML lub nagłówek X-Requested-With.
W testach white-box, gdy masz dostęp do kodu źródłowego, możesz dodawać własne parametry, ale musisz wygenerować poprawny hash treści POST. Aby to zrobić, musisz zdobyć wartość saltu, który znajduje się w plikach konfiguracyjnych lub w zmiennej środowiskowej SECURITY_SALT.
Po uzyskaniu saltu, możesz użyć poniższego skryptu do wygenerowania tokena dla treści POST:
import argparse from urllib.parse import unquote import hmac def parse_arguments(): parser = argparse.ArgumentParser() parser.add_argument( "-s", "--salt", help="CakePHP application salt", required=True, ) parser.add_argument( "-p", "--path", help=f"URL Path", required=True, ) parser.add_argument( "-b", "--body", help=f"POST body", required=True, ) parser.add_argument( "--ssid", help=f"Session ID", required=True, ) args = parser.parse_args() return args def serialize(array): result = f"a:{len(array)}:{{" for i in range(len(array)): element = array[i] result += f"i:{i};s:{len(element)}:\"{element}\";" result += "}" return result def main(): args = parse_arguments() post_body = unquote(args.body) fields_flat = post_body.split("&") fields = [] skip = ["_method", "_csrfToken", "_Token"] for val in fields_flat: k, v = val.split("=", 1) if(k == "_Token[unlocked]"): unlocked = v if "[" in k: k = k[:k.find("[")] if k not in skip: fields.append(k) fields.sort() serialized = serialize(fields) hashParts = [args.path, serialized, unlocked, args.ssid] hmac1 = hmac.new(key=args.salt.encode(), msg="".join(hashParts).encode(), digestmod="sha1") digest = hmac1.hexdigest() print(digest) if __name__ == '__main__': main()
Ten skrypt nie zadziała, jeśli chcesz dodać tablicę w formacie: name[key1]=value. Jest to skrypt obsługujący jedynie proste parametry w formacie name=value.
Aby w pełni zautomatyzować ten proces, możesz stworzyć odwrotny proxy, który przeanalizuje Twoje żądania POST i automatycznie doda do nich obliczony hash.
Daj znać w komentarzach, jeśli chcesz zobaczyć, jak go stworzyć.
Pamiętaj, że jeśli odkryjesz podatność wymagającą dodania nowego parametru POST, musisz upewnić się, że mechanizm ochrony przed manipulacją formularzami został ominięty. W przeciwnym razie podatność nie może zostać wykorzystana i nie ma żadnego realnego wpływu.
Ochrona CSRF ogranicza skuteczność skanowania podatności
Cross-Site Request Forgery (CSRF) to podatność, która umożliwia atakującym nieświadome nakłonienie uprzywilejowanych użytkowników do wykonania określonych działań w aplikacji.
CakePHP posiada dedykowane middleware do ochrony przed tego typu atakami. Nazywa się CsrfProtectionMiddleware
.
Ochrona CSRF rozpoczyna się od wygenerowania tokena, który jest przechowywany w plikach cookie i wstawiany jako ukryte pole w każdym formularzu aplikacji webowej.
Gdy użytkownik wysyła żądanie zmieniające stan aplikacji (POST, PUT, DELETE i inne metody), odbywa się dwuetapowa weryfikacja:
Najpierw sprawdzane jest ciasteczko (cookie):
$decoded = base64_decode($token, true); // ... $key = substr($decoded, 0, static::TOKEN_VALUE_LENGTH); $hmac = substr($decoded, static::TOKEN_VALUE_LENGTH); $expectedHmac = hash_hmac('sha1', $key, Security::getSalt()); return hash_equals($hmac, $expectedHmac);
- W linii 1 token ciasteczka jest dekodowany z base64.
- Linie 3 i 4 dzielą token na dwie części – klucz (zazwyczaj 16 lub 32 bajty) oraz HMAC.
- W linii 6 aplikacja oblicza hash SHA1 klucza, używając salta. Ten proces jest podobny do mechanizmu zapobiegającego manipulacji formularzami.
- W linii 8 obliczony hash klucza jest porównywany z wartością HMAC zapisaną w ciasteczku.
- W praktyce ciasteczko wygląda następująco:
csrfToken=7Jn8bE1rg7NPJRcWp67GljAwM2RlMTk2MGViYTU5OTY5YzY4Mzg4NjBjYzQ5ZWI3ZTRiNGRhYjk=
Drugi etap polega na sprawdzeniu, czy token przesłany w treści żądania POST zgadza się z tokenem w ciasteczku.
Jeśli oba testy zostaną pomyślnie zakończone, middleware CSRF przekazuje żądanie do dalszego przetwarzania.
Blackholing w CakePHP
Blackholing to proces przekierowywania wszystkich potencjalnie złośliwych żądań bez faktycznego rozpoczęcia wykonywania logiki MVC. Jeśli jakiekolwiek sprawdzenie bezpieczeństwa przeprowadzane przez SecurityComponent
zakończy się niepowodzeniem, żądanie HTTP zostanie zablokowane i nie dotrze do żądanego kontrolera, modelu ani widoku.
Zamiast tego aplikacja wyświetli informację o odrzuconym żądaniu (black-holed request):

Przykład żądania zablokowanego z powodu ochrony CSRF:

Jest to rezultat uruchomienia opisanych powyżej mechanizmów zabezpieczeń.
Niektóre aplikacje mogą implementować własne strony błędów dla mechanizmu blackholing, więc komunikat o błędzie może wyglądać inaczej.
Omijanie zabezpieczeń poprzez modyfikację kodu CakePHP
Podczas testów penetracyjnych white box możliwe jest modyfikowanie kodu źródłowego CakePHP i wyłączanie określonych mechanizmów zabezpieczeń. Dzięki temu można przeprowadzać skanowanie podatności bez obawy, że CakePHP zablokuje niektóre żądania.
Wyłączanie uwierzytelniania w CakePHP
To disable the authentication implemented by the Authentication plugin, I created a patch that you can apply in the /vendor/cakephp/authentication/src directory:Aby wyłączyć uwierzytelnianie zaimplementowane przez Authentication Plugin, można zastosować poniższą poprawkę (patch) w katalogu:
patch AuthenticationService.php AuthenticationService.php.patch
Dodatkowo należy skopiować fałszywy plik identyfikatora do katalogu Identifier, jak przedstawiono na poniższym zrzucie ekranu:

Po zastosowaniu tej zmiany wszystkie przyszłe żądania HTTP będą traktowane jako uwierzytelnione i przypisane do pierwszego użytkownika w bazie danych:

Widać, że w odpowiedzi brakuje sesyjnego ciasteczka, a mimo to aplikacja zwraca kod 200 HTTP i listę użytkowników.
Poprawka i fałszywy identyfikator usuwają mechanizm uwierzytelniania w następujący sposób:
- Najpierw rejestrujemy fałszywy identyfikator w konstruktorze
AuthenticationService
(linia 16 patcha). - Następnie zastępujemy rzeczywisty mechanizm uwierzytelniania fałszywą metodą autoryzacji (linia 24 patcha).
- W metodzie fałszywego uwierzytelniania:
- Ładujemy fałszywy identyfikator (linia 45 patcha).
- Pobieramy dane pierwszego użytkownika z bazy danych (linia 47 patcha).
- Jeśli operacja zakończy się powodzeniem, wypełniamy obiekt Results danymi użytkownika (linia 52 patcha) i zwracamy wynik (linia 57 patcha).
Jeśli chcesz przywrócić pierwotny stan, w którym wszystkie żądania muszą być uwierzytelnione, cofnij poprawkę, wykonując polecenie:
patch --reverse AuthenticationService.php AuthenticationService.php.patch
Wyłączanie mechanizmu blackholingu i ochrony przed manipulacją formularzami
W niektórych przypadkach inne zabezpieczenia CakePHP mogą wywołać zdarzenie blackhole. Aby temu zapobiec, można zakomentować wykonanie metody blackHole
w pliku SecurityComponent.php
.
Wyłączanie ochrony CSRF
Ochronę CSRF można wyłączyć, dodając instrukcję return;
na początku poniższych metod:
KLASA | METODA | LINK |
---|---|---|
CsrfProtectionMiddleware | _validateToken | https://github.com/cakephp/cakephp/blob/4.x/src/Http/Middleware/CsrfProtectionMiddleware.php#L385 |
SessionCsrfProtectionMiddleware | validateToken | https://github.com/cakephp/cakephp/blob/4.x/src/Http/Middleware/SessionCsrfProtectionMiddleware.php#L243 |
Po wykonaniu tej modyfikacji kod powinien wyglądać podobnie do poniższego:
SessionCsrfProtectionMiddleware
:

CsrfProtectionMiddleware
:

Pamiętaj, że samo wyłączenie ochrony CSRF nie dezaktywuje zabezpieczenia przed manipulacją formularzami. Aby to zrobić, należy postępować zgodnie z instrukcją opisaną wcześniej.
!W następnym artykule przedstawimy przykład krytycznej podatności SQL injection w MISP, oprogramowaniu opartym na CakePHP. Ten typ podatności jest trudny do wykrycia, a jednocześnie może mieć bardzo poważne konsekwencje.
Usługa badań nad cyberbezpieczeństwem
Znalezienie specjalistów, którzy mogą przeprowadzić analizę podatności lub testy penetracyjne, nie jest łatwym zadaniem. Jeszcze trudniejsze jest znalezienie zespołu, którego odkrycia rzeczywiście odzwierciedlają głęboką wiedzę i zrozumienie technologii wykorzystywanych w badaniach nad cyberbezpieczeństwem.
Jeśli szukasz ekspertyzy technicznej na najwyższym poziomie, oferujemy usługę badań nad cyberbezpieczeństwem, w ramach której zajmujemy się zaawansowanymi problemami bezpieczeństwa i opracowujemy rozwiązania wykraczające poza standardowe usługi czy narzędzia.
👉 Odwiedź stronę usługi badań nad cyberbezpieczeństwem.

👉 Odwiedź stronę usługi badań nad cyberbezpieczeństwem.
Źródła:
- https://book.cakephp.org/4/en/tutorials-and-examples/cms/authorization.html
- https://book.cakephp.org/4/en/controllers/components/security.html

Czy artykuł jest pomocny? Podziel się nim ze swoimi znajomymi.