NFsec Logo

Skracarki i wklejarki URL cz.II – Legere librum Necronomicon

12/01/2019 (tydzień temu) w Bezpieczeństwo, Pen Test Brak komentarzy.  (artykuł nr 673, ilość słów: 3411)

W

poprzedniej części zebraliśmy i przygotowaliśmy do wstępnej obróbki zbiór danych pochodzący z skracarek URL. W tej części zajmiemy się jego umieszczeniem w silniku wyszukiwania, który umożliwi nam bardzo szybkie pozyskiwanie interesujących nas informacji. Jak wcześniej wspomnieliśmy na naszej maszynie wirtualnej uruchomiony jest system Ubuntu 18.04 LTS. Sama maszyna ma 2 CPU / 4 GB RAM oraz 100 GB dysku z czego 57 GB jest już zajęte przez ściągnięte, skompresowane dane. W tej części artykułu interesuje nas stworzenie następnego przepływu danych:

[/data/archive/*/*/*.txt] --> [logstash] --> [elasticsearch] --> [kibana]


Źródłem danych będą rozpakowane pliki .txt – za ich pozyskiwanie, modyfikację i dalszą wysyłkę będzie odpowiadał logstash; sercem naszego OSINT będzie elasticsearch. Jego zadaniem jest indeksowanie danych w określony przez nas sposób. Po tej czynności będziemy w stanie je przeszukiwać za pomocą prostych, jak i tych bardziej zaawansowanych zapytań. Wszystko to zostanie przykryte GUI, za które będzie odpowiedzialna kibana. Na potrzeby demonstracji będziemy używać wersji 6.1.4, ale prezentowane rzeczy i konfiguracje bez problemu powinny działać na każdej wersji z gałęzi 6.x. Instalację zaczynamy od Java SE Runtime Environment 8:

sudo add-apt-repository ppa:webupd8team/java
sudo apt update
sudo apt install oracle-java8-set-default

Następnie zainstalujemy wszystkie trzy komponenty stosu ELK, ale jeszcze nie będziemy uruchamiać jako serwisu żadnego z nich:

wget https://artifacts.elastic.co/downloads/logstash/logstash-6.1.4.deb
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.1.4.deb
wget 'https://artifacts.elastic.co/downloads/kibana/kibana-6.1.4-amd64.deb'
dpkg -i logstash-6.1.4.deb
dpkg -i elasticsearch-6.1.4.deb
dpkg -i kibana-6.1.4-amd64.deb

Modelowanie danych:

Przed umieszczeniem danych w E)elastic S)earch musimy je odpowiednio przygotować. Określić jaką mają mieć strukturę, schemat, format itd. Typowy, reprezentatywny i najczęściej pojawiający się przykład z naszego zbioru danych to:

100AQo|http://subdomena.domena.tld/ścieżka/index.cfm?parametry&zapytania

W celu ułatwienia i przyśpieszenia przeszukiwania informacji po konkretnych obszarach rozbijemy powyższą linię na następujące komponenty:

  • uri_short100AQo – hash pochodzący z oryginalnego serwisu do skracania. Na podstawie ścieżki pliku, która również będzie przesyłana do naszego systemu w polu source będziemy w stanie określić pochodzenie oryginalnego URL, który został złamany np. /data/archive/urlteam_2017-02-01-19-17-07/bitly_6 = http://bit.ly/100AQo.
  • uri_fullhttp://subdomena.domena.tld/ścieżka/index.cfm?parametry&zapytania, czyli cała reszta, która znajduje się za znakiem potoku "|". W tej części znajduje się najwięcej interesujących nas informacji. Dlatego ten komponent rozbijemy sobie jeszcze na kilka mniejszych.
  • uri_protocolhttp – protokół, jaki został użyty w komunikacji (znaki od potoku „|” do „://”).
  • uri_domainsubdomena.domena.tld – czyli serwis / aplikacja internetowa, do której odwołuje się adres URL. Nie będziemy tutaj rozbijać go na wszystkie czynniki pierwsze: subdomena, domena, tld (zrobi to za nas elasticsearch, ale o tym później) tylko wyciągniemy sobie z niego domenę najwyższego poziomu (pole: uri_topdomain). Pozwoli nam to filtrować konkretne organizację, kraje, komercyjne serwisy itd.
  • uri_path/ścieżka/index.cfm – tutaj wyodrębnimy sobie ścieżki dostępu do zasobów.
  • uri_params?parametry&zapytaniaciąg zapytania, który przekazuje dodatkowe dane do strony docelowej. Zapytania mają format nazwa=wartość, a pierwszy ciąg zapytania w adresie URL poprzedzony jest znakiem „?” (znakiem zapytania). Przed kolejnymi ciągami zapytania umieszczone są znaki „&” (ampersand). Ciągi zapytania są często nazywane parametrami, bo służą do umieszczania parametrów w kodzie uruchamianym na stronie docelowej. To ta część najczęściej jest testowana pod względem różnych ataków.

Skoro posiadamy już plan rozłożenia naszych danych na różne pola i ich wartości – czas skonfigurować program logstash, aby wykonał wszystkie nasze w/w założenia. Pierwszym krokiem będzie stworzenie pliku z wzorami dla filtra grok. Grok jest świetnym filtrem do parsowania niestrukturalnych danych w coś uporządkowanego i możliwego do uruchamiania kwerend.

mkdir /etc/logstash/patterns
chmod 755 /etc/logstash/patterns
touch /etc/logstash/patterns/nfpatterns
chmod 644 /etc/logstash/patterns/nfpatterns

Plik nfpatterns powinien posiadać następującą zawartość:

NFPROTO [A-Za-z]([A-Za-z0-9+\-.]+)+
NFDOMAIN \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b)
NFPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%&_\-]*)+
NFPARAMS \?[A-Z a-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]<>]*
NFALL %{NFPROTO:uri_protocol}://%{NFDOMAIN:uri_domain}(?:%{NFPATH:uri_path})?(?:%{NFPARAMS:uri_params})?

Mimo, że logstash posiada już około 120 gotowych wzorów do obsługi różnych formatów logów to my na ich podstawie stworzyliśmy własne i dostosowaliśmy je do swoich potrzeb. Na przykład NFPARAMS jest poprawioną wersją URIPARAM, która uwzględnia możliwość występowania „czystej spacji” (nie jako kod URI: %20) w parametrach. Posiadając już niezbędne wzory do permutacji danych musimy teraz zdefiniować plik konfiguracyjny, który je wykorzysta:

# Dane wejściowe będą pobierane z plików .txt.
input {
  file {
    # Ścieżka do wszystkich plików.
    path => "/data/archive/*/*/*.txt"
    # Zawsze czytaj od początku plików.
    start_position => "beginning"
    # Zapisuj metadane przetwarzania plików.
    sincedb_path => "/var/lib/logstash/sincedb"
    # Wg mnie najlepszy kodek dla tych plików.
    codec => plain {
      charset => "US-ASCII"
    }
  }
}

# Każda odczytana linia z pliku będzie filtrowana.
filter {
  # Nie przesyłaj linii zaczynających się od komentarzy.
  if [message] =~ /^#/ { drop {} }
  # Nie przesyłaj pustych linii.
  if [message] == "" { drop {} }
  # Rozdziel linię na część przed i po potoku.
  # Bedą nazywać się "uri_short" oraz "uri_full".
  grok {
    match => { "message" => "%{DATA:uri_short}\|%{GREEDYDATA:uri_full}" }
  }
  # Dopasuj wcześniej zdefiniowane wzory do pola "uri_full".
  grok {
    patterns_dir => ["/etc/logstash/patterns"]
    match => { "uri_full" => "%{NFALL}" }
  }
  # Z pola "uri_domain" - stwórz nowe pole "uri_topdomain" z tld.
  grok {
    match => { "uri_domain" => "(?<uri_topdomain>([^.]*)$)" }
  }
  # Usuń zbędne metadane, aby zaoszczędzić miejsce w ES.
  mutate {
    remove_field => [ "@version", "host", "message" ]
    rename => [ "path", "source" ]
  }
  # Z pola "source" wydobądź datę w postaci YYYY-MM
  # i zapisz ją jako nowe pole "archive_date".
  grok {
    match => { "source" => "(?<archive_date>(?>\d\d){1,2}-(?:0?[1-9]|1[0-2]))" }
  }
}

# Wszystkie przetworzone dane wyślij do elasticsearch.
output {
  # Jeśli nie było błędów dopasowania wzorów:
  if ("_grokparsefailure" not in [tags]) {
    # to wysyłaj dane na localhost port 9200.
    elasticsearch {
      hosts => ["localhost:9200"]
      # Nazwa indeksu = shortcodes-YYYY-MM. 
      index => "shortcodes-%{archive_date}"
      # Nie zarządzaj szablonem bo sami go zdefiniujemy.
      manage_template => false
    }
  }
}

Plik w takiej postaci powinniśmy zapisać w ścieżce: /etc/logstash/conf.d/harvester.conf. Reszty ustawień nie musimy dotykać – fabryczne są na tyle dobre, że nie powinniśmy mieć problemu z uruchomieniem programu. Ewentualnie, jeśli chcemy jak najszybciej przetwarzać dane (bo np. posiadamy serwer(y) o dużej mocy) – wówczas należy zapoznać się z sekcją dokumentacji pt. „Tuning and Profiling Logstash Performance„.

Gromadzenie danych:

Czytanie danych, modyfikacja i ich wysyłanie to jedna sprawa, a ich gromadzenie i możliwość przeszukiwania to druga. Z samym elasticsearch spotkaliśmy się już wcześniej. Nie będziemy omawiać tutaj jego podstaw, ponieważ w internecie istnieje wiele bardzo dobrych opracowań – choćby „Elasticsearch: The Definitive Guide„. Ze względów dyskowych przed uruchomieniem elasticsearch zmienimy tylko jego ścieżkę zapisu danych oraz wyprofilujemy ilość RAM, jaką może sobie zarezerwować w systemie (zazwyczaj jest to 50% posiadanej pamięci):

mkdir /data/elasticsearch
chown elasticsearch:elasticsearch /data/elasticsearch

W pliku /etc/elasticsearch/elasticsearch.yml możemy teraz ustawić:

network.host: 0.0.0.0
path.data: /data/elasticsearch

Wybraliśmy nasłuch na wszystkich interfejsach, ponieważ będziemy się z nim za pomocą eshell oraz curl z poziomu maszyny gospodarza. Limit pamięci RAM ustawiamy w pliku /etc/elasticsearch/jvm.options ( -Xms2g / -Xmx2g ). Po wystartowaniu usługi (service elasticsearch start) curl na port 9200 powinien otrzymać odpowiedź:

curl -XGET localhost:9200/_cluster/health?pretty
{
  "cluster_name" : "elasticsearch",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 0,
  "active_shards" : 0,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}

W tym momencie jesteśmy gotowi do wgrania szablonu, który powie elasticsearch w jaki sposób ma zapisywać / indeksować dane byśmy mogli je później przeszukiwać za pomocą odpowiednich zapytań. Poniższy szablon możemy zapisać jako plik o nazwie template:

{
  "index_patterns": "shortcodes*",
  "order": 1,
  "aliases": {},
  "settings": {
    "index.analysis.analyzer.dot_separator.type": "custom",
    "index.analysis.analyzer.dot_separator.tokenizer": "by_dot",
    "index.analysis.analyzer.dot_separator.filter": ["lowercase"],
    "index.analysis.analyzer.slash_separator.type": "custom",
    "index.analysis.analyzer.slash_separator.tokenizer": "by_slash",
    "index.analysis.analyzer.slash_separator.filter": ["lowercase"],
    "index.analysis.tokenizer.by_dot.type": "pattern",
    "index.analysis.tokenizer.by_dot.pattern": "\\.",
    "index.analysis.tokenizer.by_slash.type": "pattern",
    "index.analysis.tokenizer.by_slash.pattern": "\\/",
    "index.number_of_shards": "1",
    "index.number_of_replicas": "0",
    "index.refresh_interval": "30s",
    "index.query.default_field": "uri_full",
    "index.translog.durability": "async",
    "index.translog.flush_threshold_size": "1gb",
    "index.codec": "best_compression"
  },
  "mappings": {
    "doc": {
      "_source": {
        "excludes": [
          "archive_date"
        ]
      },
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "archive_date": {
          "type": "date",
          "index": false
        },
        "uri_full": {
          "type": "text"
        },
        "uri_path": {
          "type": "keyword"
        },
        "uri_params": {
          "type": "keyword"
        },
        "uri_topdomain": {
          "type": "keyword"
        },
        "uri_protocol": {
          "type": "keyword"
        },
        "uri_short": {
          "type": "keyword"
        },
        "uri_domain": {
          "type": "text",
          "analyzer": "dot_separator",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "source": {
          "type": "text",
          "analyzer": "slash_separator",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

Jak widzimy niektóre pola chcemy mieć jako text (przepuszczane przez analizatory), a niektóre jako keyword (zapisywany bez żadnej zmiany). Wszystko po to, aby mieć większą elastyczność przy wyszukiwaniu. W dodatku dla pola uri_domain oraz source stworzyliśmy własne analizatory, które będą dzielić nam tekst na frazy używając do tego jako separatora odpowiednio: kropkę ("."dot_separator) oraz slash ("/"slash_separator). Szablon do elasticsearch wgrywamy poleceniem:

curl -H 'Content-Type: application/json' -XPUT \
localhost:9200/_template/shortcodes -d @template

Po tak przygotowanym silniku wyszukiwania możemy uruchomić w końcu program logstash (service logstash start), który powinien zacząć zasilać danymi elasticsearch. Potwierdzeniem tego powinno być pojawienie się indeksów o nazwie shortcodes-YYYY-MM:

curl -XGET localhost:9200/_cat/indices?v

health status index              pri rep docs.count store.size pri.store.size
green  open   shortcodes-2018-02   1   0   49555694     16.6gb         16.6gb
green  open   shortcodes-2017-02   1   0   88967792     22.1gb         22.1gb
green  open   shortcodes-2017-01   1   0   45410076       15gb           15gb
green  open   shortcodes-2018-01   1   0   59046383     19.5gb         19.5gb

Na potrzeby demonstracji tego artykułu indeksacji zostały poddane pierwsze dwa miesiące z roku 2017 i 2018, co sumarycznie dało 72GB danych. Ze względu na ograniczone miejsce – każdy miesiąc był rozpakowywany, indeksowany i usuwany z plików .txt. Po zaindeksowaniu każdy index dodatkowo został skompaktowany do jednego segmentu, aby zaoszczędzić miejsce i przyśpieszyć wyszukiwanie:

curl -X POST "localhost:9200/shortcodes-2017-01/_forcemerge?max_num_segments=1"

Prezentacja danych:

Ostatnim krokiem jest uruchomienie interfejsu graficznego dla naszej wyszukiwarki skaranych URL, czyli kibany. W pliku konfiguracyjnym /etc/kibana/kibana.yaml ustawiamy następujące parametry:

server.port: 8080
server.host: "0.0.0.0"
elasticsearch.url: "http://localhost:9200"
kibana.index: ".kibana"
elasticsearch.requestTimeout: 60000
logging.dest: /tmp/kibana.log

Pierwsze uruchomienie może trwać chwilę czasu, ponieważ nodejs musi skompilować parę rzeczy na podstawie dostarczonej konfiguracji. Moment wystartowania interfejsu najlepiej obserwować w pliku logu (tail -f /tmp/kibana.log). Powinna pojawić się w nim wiadomość:

{"type":"log","@timestamp":"2019-01-09T22:00:12Z", "tags":["listening","info"],
"pid":10054, "message":"Server running at http://0.0.0.0:8080"}

Po uruchomieniu kibany możemy wywołać ją w naszej przeglądarce (np. http://192.168.56.101:8080/). Kibana narazie nie jest świadoma, jakie dane ma wyświetlać oraz przeszukiwać – dlatego musimy zdefiniować jej źródło danych pod postacią nazw indeksów. W tym celu przechodzimy do zakładki: Management i następnie klikamy w: Index Patterns. W pierwszym kroku kreatora: Step 1 of 2: Define index pattern w polu Index pattern wpisujemy: shortcodes-* i klikamy Next step. W drugim kroku: Step 2 of 2: Configure settings przez rozwijane menu Time Filter field name wybieramy: I don’t want to use Time Filter i potwierdzamy operację przyciskiem: Create index pattern. Po zakończeniu tej operacji sukcesem możemy przejść do zakładki Discover, gdzie będziemy wykonywać nasze zapytania.

Wyszukiwanie danych:

Rzućmy okiem na kilka wrażliwych i interesujących informacji, które możemy znaleźć w danych dotyczących skracania URL. Poniżej znajduje się kilka przykładów rzeczy, które można znaleźć wzorując się na Google Dorks. Wyniki wyszukiwania nie zostały specjalnie opublikowane, aby chronić firmy podatne na ataki. Pamiętajmy, że jeśli znajdziemy jeszcze aktualne podatności – zgłośmy je w duchu odpowiedzialnego ujawnienia zainteresowanym osobom / firmom. Wszystkie zapytania zostały wpisywane w Query Bar – zakładki Discovery.

Wykonane ataki:

Pierwszą kategorią, są przykłady prób ataków. Możemy zgadywać, że skryptowe dzieciaki, cyberprzestępcy, a być może także inni używają skracarek, by dzielić się swoją pracą z „kolegami po fachu”. Niektóre z zidentyfikowanych adresów URL wyglądają jak proste dowody koncepcji (ang. Proof of Concept) tutoriali, podczas gdy inne są przeznaczone do eksfiltracji danych. Poniżej znajdują się przykłady ataków próbujących wykorzystać LFI (ang. Local File Inclusion) oraz Directory Traversal wraz z techniką osadzania NULL bajtów, które nie zawsze są poprawnie obsługiwane przez różnego rodzaju aplikacje. No i oczywiście wstrzykiwanie SQL:

Pytanie: Rodzaj: Ilość trafień:
     
uri_full: \/proc\/self\/envirion   lucene w query bar 134,466
uri_full: \/etc\/passwd lucene w query bar 178,203
uri_params: *%00 lucene w query bar 2,325
uri_params: *%0a lucene w query bar 411
uri_params: *%0d lucene w query bar 12
uri_full: union all select lucene w query bar 1,063,635
uri_full: „or 1=1” lucene w query bar 479
uri_full: select AND where AND limit NOT union   lucene w query bar 1,292

Głębokie ukrycie:

Kolejnym przykładem są kopie zapasowe danych. Wielu programistów i administratorów udostępnia tymczasowo kopie zapasowe online np. aby je ściągnąć do innego systemu. Udostępniając je widocznie niektórzy z nich używali skracarek URL, aby uczynić sobie ten proces bardziej wygodnym. Luki te są klasyfikowane jako wyciek informacji.

Pytanie: Rodzaj: Ilość trafień:
     
uri_full: *\.sql lucene w query bar 340
uri_path: *\.bak   lucene w query bar 256
uri_path: *\.tar\.gz lucene w query bar 909
uri_path: *\.sql.gz lucene w query bar 29

Prywatne pliki:

Innym powszechnym odkryciem jest udostępnianie prywatnych plików bez ochrony hasłem. Użytkownicy zakładają, że losowe identyfikatory skracarek (te magiczne algorytmy, które można prosto złamać) zapewnią bezpieczeństwo ich dokumentom. W poniższym przypadku można samemu ocenić ile poufnych dokumentów krąży po różnych usługach udostępniania plików:

Pytanie: Rodzaj: Ilość trafień:
     
uri_domain: docs.google.com lucene w query bar 167,245,267
uri_domain: dropbox.com lucene w query bar 167,016,085
uri_domain: mega.nz lucene w query bar 303,465
uri_domain: 1drv.ms lucene w query bar 21,287
uri_domain: icloud.com AND uri_full: photostream   lucene w query bar 8,328

Rezerwacje hoteli, lotów:

Serwisy do przechowywania plików w chmurze to nie jedyne linki bez haseł, które są udostępniane online. Systemy rezerwacji hotelowych i biura podróży często wysyłają e-maile z linkami bez haseł, co zapewnia łatwy dostęp do szczegółów takich rezerwacji:

Pytanie: Rodzaj: Ilość trafień:
     
uri_domain: click.mail.hotels.com   lucene w query bar 167,135,288

Loginy, hasła, tokeny:

Tokeny sesji w adresach URL od lat są uważane za złą praktykę, głównie dlatego, że serwery proxy i ataki przez ramię mogą zagrozić obecnej sesji użytkownika. W poniższym zestawieniu trochę przykładów adresów URL zawierających poufne informacje:

Pytanie: Rodzaj: Ilość trafień:
     
uri_params: *password\=* lucene w query bar 24,462
uri_params: *email\=* lucene w query bar 1,430,704
uri_params: *sessionid\=* lucene w query bar 6,101

Środowiska developerskie:

Istnieje również wiele systemów, które są wdrażane na różne środowiska przed produkcją – a wyniki z ich błędów, eksperymentów oraz testów często są współdzielone pomiędzy programistami. Wyszukiwanie środowisk developerskich oraz testowych bardzo często również ujawnia interesujące wyniki:

Pytanie: Rodzaj: Ilość trafień:
     
uri_domain.keyword: dev\.* lucene w query bar 79,054
uri_domain.keyword: test\.* lucene w query bar 118,830
uri_domain.keyword: staging\.* lucene w query bar 20,185
uri_domain.keyword: beta\.* lucene w query bar 128,461

Podsumowanie:

Patrząc na dane pozyskane przez archiveteam.org tylko z czterech miesięcy wyraźnie widać, że użytkownicy bez skrupułów skracają wrażliwe dane w tego typu serwisach. Usługi te są używane bez głębszego zastanowienia się nad faktem, że osoby trzecie mogą uzyskać dostęp do tych samych adresów URL, co jest klastycznym przykładem zabezpieczenia przez zaciemnienie. Dane te mogą być wykorzystywane przez ludzi o złych intencjach, pragnących nadużywać ich na swoją korzyść. Lecz analogicznie działy bezpieczeństwa w organizacjach i firmach mogą wykorzystać je w dobrej wierze np. poprzez monitoring, czy nie doszło do wycieku ich własnych danych. Co więcej – pentesterzy oraz konsultanci bezpieczeństwa mogą korzystać z tego rodzaju technik w celu wyszukiwania danych swoich klientów dostarczając im cenne informacje o próbach potencjalnych ataków i zagrożeniach, nad którymi mogliby wspólnie popracować.
Wersja z terminalem:

Wyniki z elasticsearch zwracane są w formacie JSON. Ułatwia to pisanie narzędzi do interakcji z danymi, które przechowuje. Możemy przetwarzać je także w terminalu Linuksa. Powiedzmy, że chcemy uzyskać wszystkie domeny, związane z zapytaniem: uri_domain.keyword: dev\.*. Aby to zrobić, możemy po prostu przesłać zapytanie do serwera elasticsearch za pomocą curl i przekierować dane wyjściowe do pliku. Na przykład:

curl -s -X POST -H "Content-Type: application/json" \
'http://localhost:9200/shortcodes-*/_search?scroll=1m&size=5000' \
-d '{ "query": { "wildcard": { "uri_domain.keyword": "dev.*" } } }' > results

Na wyjściu otrzymamy ogromny blok tekstu zapakowany w JSON, więc możemy przesłać go do jq i wyciągnąć tylko te informacje, których potrzebujemy:

cat results | jq .hits.hits[]._source.uri_domain > results.domains

Na koniec przywołujemy moc standardowych narzędzi Linuksa do przetwarzania danych:

cat results.domains | cut -d"\"" -f2 | sort | uniq | wc -l
991

Oczywiście mogliśmy to zrobić za pomocą jednego polecenia, bez przechowywania żadnych plików. Jednak jest to prosty przykład mający na celu ukazanie, że możemy łatwo przetwarzać te dane w dowolny sposób, jaki chcemy. Teraz, gdy mamy domeny możemy poszukać w nich te, które biorą udział w programach Bug Bounty!.

Więcej informacji: The Secrets in URL Shortening Services

Kategorie K a t e g o r i e : Bezpieczeństwo, Pen Test

Tagi T a g i : , , , , , , , ,

Komentowanie tego wpisu jest zablokowane.