Omówienie LDAP oraz ataku LDAP Injection

Jest bardzo prawdopodobne, że idąc na pierwszą rozmowę o pracę na stanowisku bezpiecznika spotkasz się z pytaniem o protokół LDAP. Jest to jedno z podstawowych pojęć i należy do najczęściej poruszanych tematów z osobami stawiającymi swoje pierwsze kroki w branży. W niniejszym artykule przyjrzymy się LDAP, poznamy podatność LDAP Injection oraz to, jak się przed nim bronić.

Lightweight Directory Access Protocol

Zarejestrowani użytkownicy w systemach Linux przetrzymywani są w pliku /etc/passwd.

file: /etc/passwd
root:x:0:0:root:/root:/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

W przypadku kiedy obsługiwanych przez nas maszyn i ich użytkowników jest niewiele, zarządzanie nimi nie powinno sprawiać większego problemu. Z kolei kiedy jest wysoka ilość użytkowników, zmiana ich haseł, usuwanie kont itd. może stać się problematyczne. Wtedy z pomocą przychodzą scentralizowane systemy do zarządzania kontami użytkowników. Do ich implementacji używany jest najczęściej protokół LDAP.

Lightweight Directory Access Protocol wykokrzystuje do wymiany informacji protokół TCP/IP. LDAP docelowo pozwala na dostęp do katalogów adresowych, które można porównać do standardowej, relacyjnej bazy danych. OpenLDAP opisuje komunikację z protokołem w sposób następujący:

Usługa katalogowa LDAP jest oparta na modelu klient-serwer. Jeden lub więcej serwerów LDAP zawiera dane tworzące drzewo informacji katalogowej (DIT). Klient łączy się z serwerami i zadaje im pytanie. Serwer odpowiada odpowiedzią i/lub wskazaniem miejsca, w którym klient może uzyskać dodatkowe informacje (zazwyczaj jest to inny serwer LDAP). Niezależnie od tego, z którym serwerem LDAP łączy się klient, widzi on ten sam widok katalogu; nazwa przedstawiona jednemu serwerowi LDAP odwołuje się do tego samego wpisu, który znalazłby się na innym serwerze LDAP. Jest to ważna cecha globalnej usługi katalogowej, takiej jak LDAP.

https://www.openldap.org/doc/admin21/intro.html

LDAP wykorzystywany jest między innymi w takich oprogramowaniach jak Active Directory od firmy Microsoft oraz SSSD na systemy Linux.

LDAP Injection

Tak jak w przypadku ataku SQL Injection, LDAP Injection polega na nadużyciu danych wprowadzanych przez użytkownika. Na ich podstawie aplikacja konstruująca deklaracje LDAP, które nie są w żaden sposób filtrowane, mogą doprowadzić do wykonywania dowolnych poleceń na serwerze takich jak nadawanie uprawnień nieautoryzowanym zapytaniom oraz modyfikacje zawartości drzewa LDAP.

Przykłady

Access Controll Bypass

Pierwszym przykładem, który będziemy omawiać służy do obejścia kontroli dostepu (Access Controll Bypass). Wyobraźmy sobie sytuację, w której istnieje standardowa strona logowania, na której to trzeba wprowadzić login i hasło aby się zalogować. Aby potwierdzić istnienie użytkownika w bazie danych aplikacji, LDAP konstruuje filtry wyszukiwania i przesyła je na serwer LDAP, który przetwarza jedynie pierwszy filtr (USER). Przesłana konstrukcja wygląda w sposób następujący:

(&(USER=ENTERED_USERNAME_FROM_FORM)(PASSWORD=ENTERED_PASSWORD_FROM_FORM))

Zakładając, że użytkownik prześle jako wartość USER poprawną nazwę użytkownika z dołączonym dodatkowym ciągiem znaków, nasza konstrukcja będzie wyglądała następująco:

(&(USER=John)(&))(PASSWORD=ENTERED_PASSWORD_FROM_FORM))

Jak widać, dodatkowym ciągiem znaków, który został dołączony jest )(&)). Dzięki niemu możliwe jest zamknięcie przesyłanej konstrukcji w kontrolowanym przez nas miejscu. Ponadto, serwer LDAP odczyta jako hasło wartość &, która sama w sobie oznacza prawdę absolutną. Skutkuje to odczytaniem żądania przez serwer jako prawidłowe, a my zostaniemy zalogowani. Dalsza część konstrukcji, tj. ((PASSWORD=ENTERED_PASSWORD_FROM_FORM)) nie ma znaczenia.

Information Disclosure

W niektórych systemach LDAP stosuje się zapytania OR. Jego postać może wyglądać w sposób następujący:

(|(type=MY_TYPE_01)(type=MY_TYPE_02))

Powyższe konstrukcje stosuje się w momencie, kiedy chcemy przefiltrować bazę w poszukiwaniu kilku typów danego źródła. Jako przykład może być wyszukiwanie wszystkich postów blogowych, którego kategoria to programming lub linux. Zakładając, że serwer obsługuje taką możliwość filtrowania, możemy ustawić wartość category na linux)(uid=*)). W ten sposób skonstruowana konstrukcja prezentuje się następująco:

(|(category=linux)(uid=*))(category=programming))

Znak gwiazdki na serwerach LDAP jest interpretowany jako „wszystko”. Oznacza to, że w odpowiedzi moglibyśmy (jeśli serwer byłby podatny) dostać wszystkie posty blogowe o kategorii linux oraz wszystkich użytkowników. Dzieje się tak dlatego, że uid odnosi się do id wspomnianych użytkowników.

Blind LDAP Injection

Ostatnim ze sposobów na exploitowanie podatnych serwerów LDAP jest blind LDAP Injection. Polega on na wpisywaniu niefiltrowanych przez serwer wartości przez użytkownika do zapytania LDAP. Na podstawie odpowiedzi (true of false) jesteśmy w stanie stwierdzić, czy podana zapytanie było prawidłowe. Jeśli było, oznacza to, że wpisana przez nas wartość też jest prawidlowa.

Jako przykład załóżmy, że posiadamy bazę danych użytkowników. Jedna z funkcjonalności aplikacji polega na wyświetlaniu niewrażliwych danych użytkownika po wejściu na jego konto. Załóżmy, że w bazie danych przetrzymywane są także ich numery telefonu. Zapytanie kierowane do serwera LDAP po wejściu na profil użytkownika wygląda następująco:

(&(uid=12))

Podobnie jak w poprzednich przykładach, dołączmy do wartości id dodatkowy ciąg znaków 12)(phonenumber=*. W ten sposób nasze utworzone zapytanie to:

(&(uid=12)(phonenumber=*))

Ponieważ pole phonenumber może przyjmować jakąkolwiek wartość, serwer zwróci nam prawdę. Załóżmy, że numer telefonu użytkownika o id równym 12 to 000-000-000.

(&(uid=12)(phonenumber=0*))

Metodą prób i błędów jesteśmy w stanie odgadnąć (na podstawie odpowiedzi serwera), jaki użytkownik ma numer telefonu. Podobny atak został opisany w jednym z naszych poprzednich postów.

Jak się bronić?

Sposobów na ochronę jest kilka. Należy do nich:

  • Filtrowanie przyjmowanych oraz zwracanych użytkownikowi danych (najprostsze wydaje się utworzenie białej listy oraz filtrowanie danych w oparciu o wyrażenia regularne),
  • Używanie frameworków sprawdzonych, automatycznie broniących przed atakami LDAP Injection,
  • Ograniczenie uprawnienia aplikacji do koniecznych (zasada least privilege).

Źródła

https://en.wikipedia.org/wiki/List_of_LDAP_software
https://www.openldap.org/doc/admin21/intro.html
https://bugspace.pl/phonebook-hack-the-box/
https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.