diff --git a/pkg/evaluate/evaluate.go b/pkg/evaluate/evaluate.go index b2dd022..f33b5d4 100644 --- a/pkg/evaluate/evaluate.go +++ b/pkg/evaluate/evaluate.go @@ -17,8 +17,8 @@ limitations under the License. package evaluate import ( - "github.com/cdk-team/CDK/pkg/util" "github.com/cdk-team/CDK/conf" + "github.com/cdk-team/CDK/pkg/util" ) // CallBasics is a function to call basic functions @@ -51,6 +51,7 @@ func CallBasics() { CheckK8sAnonymousLogin() util.PrintH2("Discovery - K8s Service Account") + CheckPrivilegedK8sServiceAccount(conf.K8sSATokenDefaultPath) util.PrintH2("Discovery - Cloud Provider Metadata API") diff --git a/pkg/evaluate/k8s_anonymous_login.go b/pkg/evaluate/k8s_anonymous_login.go index 9c19839..e8c6d94 100644 --- a/pkg/evaluate/k8s_anonymous_login.go +++ b/pkg/evaluate/k8s_anonymous_login.go @@ -1,4 +1,3 @@ - /* Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . @@ -18,8 +17,10 @@ limitations under the License. package evaluate import ( + "bufio" "fmt" "log" + "os" "strings" "github.com/cdk-team/CDK/pkg/tool/kubectl" @@ -30,9 +31,30 @@ func CheckK8sAnonymousLogin() bool { // check if api-server allows system:anonymous request log.Println("checking if api-server allows system:anonymous request.") + // fetch mount info + file, err := os.Open("/proc/self/mountinfo") + if err != nil { + fmt.Printf("error opening /proc/self/mountinfo: %v\n", err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "serviceaccount") { + fmt.Println("find serviceaccount successfully") + k8sAccountInfoPath = line + } + } + + if err := scanner.Err(); err != nil { + fmt.Printf("error reading /proc/self/mountinfo: %v\n", err) + } + resp, err := kubectl.ServerAccountRequest( kubectl.K8sRequestOption{ - TokenPath: "", + TokenPath: k8sAccountInfoPath, Server: "", // default Api: "/", Method: "get", diff --git a/pkg/evaluate/k8s_service_account.go b/pkg/evaluate/k8s_service_account.go index b8b68cf..49bb88b 100644 --- a/pkg/evaluate/k8s_service_account.go +++ b/pkg/evaluate/k8s_service_account.go @@ -1,4 +1,3 @@ - /* Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . @@ -18,16 +17,45 @@ limitations under the License. package evaluate import ( + "bufio" "fmt" "github.com/cdk-team/CDK/pkg/tool/kubectl" "log" + "os" "strings" ) +var ( + k8sAccountInfoPath string + kubernetesAddress string +) + func CheckPrivilegedK8sServiceAccount(tokenPath string) bool { + + // fetch mount info + file, err := os.Open("/proc/self/mountinfo") + if err != nil { + fmt.Printf("error opening /proc/self/mountinfo: %v\n", err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "serviceaccount") { + fmt.Println("find serviceaccount successfully") + k8sAccountInfoPath = line + } + } + + if err := scanner.Err(); err != nil { + fmt.Printf("error reading /proc/self/mountinfo: %v\n", err) + } + resp, err := kubectl.ServerAccountRequest( kubectl.K8sRequestOption{ - TokenPath: "", + TokenPath: k8sAccountInfoPath, Server: "", Api: "/apis", Method: "get", @@ -45,7 +73,7 @@ func CheckPrivilegedK8sServiceAccount(tokenPath string) bool { log.Println("trying to list namespaces") resp, err := kubectl.ServerAccountRequest( kubectl.K8sRequestOption{ - TokenPath: "", + TokenPath: k8sAccountInfoPath, Server: "", Api: "/api/v1/namespaces", Method: "get", diff --git a/pkg/task/auto_escape.go b/pkg/task/auto_escape.go index 947c7a8..016c077 100644 --- a/pkg/task/auto_escape.go +++ b/pkg/task/auto_escape.go @@ -25,7 +25,6 @@ import ( "github.com/cdk-team/CDK/pkg/exploit/persistence" "log" - "github.com/cdk-team/CDK/conf" "github.com/cdk-team/CDK/pkg/cli" "github.com/cdk-team/CDK/pkg/evaluate" "github.com/cdk-team/CDK/pkg/plugin" @@ -110,6 +109,7 @@ func autoEscape(shellCommand string) bool { fmt.Printf("\n[Auto Escape - K8s API Server]\n") anonymousLogin := evaluate.CheckK8sAnonymousLogin() privServiceAccount := evaluate.CheckPrivilegedK8sServiceAccount(conf.K8sSATokenDefaultPath) + k8sExploit = privServiceAccount || anonymousLogin if !k8sExploit { diff --git a/pkg/tool/kubectl/common.go b/pkg/tool/kubectl/common.go index e694cf1..7d7b5d6 100644 --- a/pkg/tool/kubectl/common.go +++ b/pkg/tool/kubectl/common.go @@ -92,7 +92,7 @@ func SecretToken(tokenPath string) (string, error) { var token string if tokenPath != "" { - token, tokenErr = GetServiceAccountToken(tokenPath) + token, tokenErr = GetServiceAccountToken(tokenPath + "/token") } else if token == "" { token, tokenErr = GetServiceAccountToken(conf.K8sSATokenDefaultPath) }