Obchodzenie zapór pośrednicząco-filtrujących strony web #5
Napisał: Patryk Krawaczyński
01/06/2021 w Pen Test Brak komentarzy. (artykuł nr 787, ilość słów: 1443)
W
ypożyczanie domen (ang. domain borrowing) jest ulepszoną techniką domain fronting. Tą ostatnią można łatwo wykryć jeśli w sieci znajduje się urządzenie deszyfrujące ruch HTTPS i porównuje wartości nagłówków SNI i HOST. Jednak wypożyczanie domen pozwala na ukrywanie ruchu C2 i innej komunikacji za pomocą CDN w celu obejścia zapór sieciowych i systemów IDS. Jak wygląda normalny, niepodejrzany ruch sieciowy, który się monitoruje, ale nie blokuje? Na pewno jest szyfrowany (HTTPS); odnosi się do domen z poprawnymi certyfikatami TLS, które są znane i mają dobrą reputację w sieci; nawet rozszyfrowany wygląda jak poprawny (SNI == HOST
); nie jest blokowany ze względu na możliwość utraty generycznego ruchu od dużego gracza w internecie.
Jak działa CDN z SSL:
CDNy (ang. Content Delivery Network) działają jak człowiek pośrodku (ang. Man-in-the-Middle / MitM ) tylko tutaj systemy CDN są umieszczane pomiędzy klientem (przeglądarką), a docelowym serwerem WWW. Jeśli chcemy dodać wybraną domenę np. cdn.nfsec.pl do sieci CDN – dodajemy ją w panelu wybranego usługodawcy – wskazujemy adres końcowego serwera, który będzie ją obsługiwał i przekierowujemy domenę cdn.nfsec.pl
na poziomie DNS (najczęściej rekord CNAME
) na globalny punkt końcowy CDN. Jeśli chcemy obsługiwać ruch HTTPS musimy wrzucić na serwery CDN klucz oraz certyfikat dla danej domeny (mogą być samopodpisane). Od teraz komunikacja z naszą domeną będzie wyglądać następująco:
[Klient] --> Podaj IP dla: cdn.nfsec.pl --> [Serwer DNS] [Klient] <-- Adres IP to: IP serwera CDN <- [Serwer DNS] [Klient] --> HTTPS Hello: cdn.nfsec.pl --> [CDN] -- |: Szukam TLS: cdn.nfsec.pl [Klient] <-- HTTPS Hello: cdn.nfsec.pl <-- [CDN] -- |: Znalazłem TLS: cdn.nfsec.pl [Klient] --> Ruch HTTPS: cdn.nfsec.pl ---> [CDN] --> Ruch HTTP(S) --> [cdn.nfsec.pl] [Klient] <-- Ruch HTTPS: cdn.nfsec.pl <--- [CDN] <-- Ruch HTTP(S) <-- [cdn.nfsec.pl]
Jak działa wypożyczanie domen:
Po pierwsze, aby nawiązać połączenie HTTPS z danym serwerem nie potrzebujemy wykonywać zapytania DNS skoro znamy adresy IP serwerów CDN, które obsługują naszą domenę. Możemy ustawić SNI na naszą domenę i nawiązać łączność z konkretnym adresem końcowym CDN:
curl -v --resolve cdn.nfsec.pl:443:15X.10X.1.16X https://cdn.nfsec.pl
* Hostname cnd.nfsec.pl was found in DNS cache * Trying 15X.10X.1.16X... * TCP_NODELAY set * Connected to cnd.nfsec.pl (15X.10X.1.16X) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: CN=cdn.nfsec.pl * start date: Apr 16 15:39:35 2021 GMT * expire date: Jul 15 15:39:35 2021 GMT * subjectAltName: host "cdn.nfsec.pl" matched cert's "cdn.nfsec.pl" * issuer: C=US; O=Let's Encrypt; CN=R3 * SSL certificate verify ok.
Po drugie, jeśli chcemy jednak oprzeć naszą komunikację o DNS, aby nie utrzymywać aktualnej listy adresów IP - możemy w pierwszym kroku wykorzystać zapytanie o jakąś inną, dobrze znaną domenę, która również jest obsługiwana przez ten sam CDN:
host -t a gr***ub.com gr***ub.com has address 15X.10X.1.16X curl -v --resolve cdn.nfsec.pl:443:15X.10X.1.16X https://cdn.nfsec.pl
Odpytujemy serwer DNS o adres domeny będącej przykrywką. Pobieramy zwrócony dla niej adres IP i wykonujemy komunikację z pierwszej metody. Po trzecie: u dużej ilości dostawców CDN ( np. Fastly, StackPath, KeyCDN, CDN77, CDNSun ) możemy zarejestrować dowolną domenę, która nie została jeszcze wskazana przez innego klienta. Prawo do domeny nie jest weryfikowane - widocznie istnieje założenie, że jeśli ktoś nie jest w stanie skierować danej domeny za pomocą wpisów DNS to nie jest w stanie wyrządzić żadnej szkody. Właściciel domeny może się lekko zdziwić, że jego domena jest już tam, gdzie on dopiero zamierzał ją umieścić. Na przykład możemy zarejestrować w usłudze CDN domenę związaną z serwerami obrazków jakiegoś serwisu społecznościowego - fbimg.com itd. OK, ale co z certyfikatem TLS? Otóż okazuje się, że większość CDNów, jeśli nie wgramy im certyfikatu oraz klucza dla naszej domeny odpowie nam swoim standardowym certyfikatem:
curl -v --resolve cdn.nfsec.pl:443:16X.8X.9X.18X https://cdn.nfsec.pl
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 * ALPN, server accepted to use h2 * Server certificate: * subject: C=US; ST=California; L=San Francisco; O=Fastly, Inc.; CN=default.ssl.fastly.net * start date: Nov 12 16:01:03 2019 GMT * expire date: Jan 8 17:01:02 2022 GMT * subjectAltName does not match cdn.nfsec.pl * SSL: no alternative certificate subject name matches target host name 'cdn.nfsec.pl' * Closing connection 0 * TLSv1.2 (OUT), TLS alert, close notify (256): curl: (60) SSL: no alternative certificate subject name matches target host name 'cdn.nfsec.pl'
Dochodzimy tutaj do sytuacji gdzie SNI === HOST
. Pozostaje jeszcze rozwiązanie kwestii konieczności użycia samopodpisanego certyfikatu lub standardowego certyfikatu, który podsuwa nam dostawca CDN w przypadku, gdy nie znajdzie naszego. Jednym z sposobów jest pozyskanie certyfikatu i klucza poprzez błędy znajdujące się w interesującej nas domenie np. RCE webaplikacji, przejęcie subdomeny, możliwość wgrania dowolnego pliku itd. Jak wiemy znalezienie takich błędów wymaga dużo czasu oraz energii i nie zawsze jest możliwe. Jak więc pozyskać ważny certyfikat dla jakieś "zaufanej" domeny bez udziału polowania na błędy? To proste. Niektórzy dostawcy usługi CDN niepoprawnie implementują dystrybucję certyfikatów HTTPS typu wildcard. Na przykład pierwszy użytkownik na podatnej platformie CDN wgrywa certyfikat i klucz dla domeny: *.nfsec.pl. Inny użytkownik na tej samej platformie rejestruje domenę: null.nfsec.pl
(z zupełnie innym serwerem końcowym), ale nie wgrywa dla niej certyfikatu. Mimo braku tego ostatniego to i tak odwołując się do serwerów CDN domeną null.nfsec.pl
uznają one, że poprawnym certyfikatem dla tej domeny nie jest już ich standardowy certyfikat, a certyfikat wildcard pochodzący z innego konta, ale pokrywający się z nazwą domeny:
[Klient] --> Podaj IP dla: null.nfsec.pl --> [Serwer DNS] [Klient] <-- Adres IP to: IP serwera CDN <-- [Serwer DNS] [Klient] --> HTTPS Hello: null.nfsec.pl --> [CDN] -- |: Szukam TLS: null.nfsec.pl [Klient] <-- HTTPS Hello: null.nfsec.pl <-- [CDN] -- |: Znalazłem TLS: *.nfsec.pl (należy do użytkownika #1) [Klient] -> Ruch HTTPS: null.nfsec.pl -> [CDN] -> Ruch HTTP(S) -> [serwer użytkownika #2] [Klient] <- Ruch HTTPS: null.nfsec.pl <- [CDN] <- Ruch HTTP(S) <- [serwer użytkownika #2]
O przypadki z życia wzięte nie jest trudno:
curl -v --resolve nfsec.xxxxxxxx.net:443:XX.XXX.XXX.XXX https://nfsec.xxxxxxxx.net
* Added nfsec.xxxxxxxx.net:443:XX.XXX.XXX.XXX to DNS cache * Hostname nfsec.xxxxxxxx.net was found in DNS cache * Trying XX.XXX.XXX.XXX... * TCP_NODELAY set * Connected to nfsec.xxxxxxxx.net (XX.XXX.XXX.XXX) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: OU=Domain Control Validated; OU=PositiveSSL Wildcard; CN=*.xxxxxxxx.net * start date: Sep 23 00:00:00 2019 GMT * expire date: Oct 6 23:59:59 2021 GMT * subjectAltName: host "nfsec.xxxxxxxx.net" matched cert's "*.xxxxxxxx.net" * issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA * SSL certificate verify ok.
Czyli doszliśmy do równania: SNI == HOST == TLS
, czyli normalnego, niepodejrzanego ruchu sieciowego, który się monitoruje, ale nie blokuje.
Więcej informacji: Domain Borrowing: Catch My C2 Traffic If You Can