Analysts identified several actions that the same threat actor carried out in different venues.
One was the use of Weave Scope, a legitimate tool by Weaveworks used to monitor/control deployed containers.
Weave Scope is a visualization and monitoring tool for Docker and Kubernetes. System administrators can use this to monitor and control their deployed containers/pods/workloads.
One can manage running containers by executing, rebooting, pausing, stopping or even deleting containers, all of which can be controlled from a web console (either local or in the cloud).
In this attack scenario, the compromised underlying host was made a node of the threat actor-controlled Weave Scope Cloud instance, from where they could execute various commands.
The administration features make Weave Scope an interesting target. This is how attackers targeted this recently:
1. The attacker spins up a new privileged container based on an image from a compromised account. In the arguments, the attacker attempts to mount the root file system of the underlying host to the ‘/host’ mount point and executes a bash script fetched from the attacker’s infrastructure.
2. The script ‘scope2.sh’ is downloaded and piped to ‘bash’ to be executed. The script initially checks if the hostname’s value is ‘HaXXoRsMoPPeD’ halting the execution if true. This looks like a flag to check if a system has already been compromised.
3. Environment variables are set, which overrides localization settings, prevents command history logging, and exports a new path.
4. A variable ‘SCOPE_TOKEN’ is populated from a controlled endpoint, which contains the Weave Scope service token. ‘SCOPESHFILE’ contains the Weave Scope script, which is encoded in base64.
5. The path to ‘docker’ binary is fetched using ‘type docker’. To evade any TTY events, they’re redirected to ‘/dev/null’. Based on this, the execution proceeds.
6. The file ‘/tmp/.ws’ is checked:
a. If the file doesn’t exist, the following commands are executed:
i. The ‘/tmp/’ path is remounted with read-write permissions using the ‘mount’ utility.
ii. The base64 encoded string of the ‘SCOPESHFILE’ variable is decoded and the output is redirected to ‘/tmp/.ws’. This is the Weaveworks’ script and is hidden by default since the file name begins with a ‘.
iii. The permissions of the newly created script are changed to executable using ‘chmod’
b. If the file ‘/tmp/.ws’ exists, then execution proceeds as follows:
i. The ‘/tmp/’ path is remounted as read-write using ‘mount’ utility.
ii. The Weaveworks utility Weave Scope at /tmp/.ws is stopped and launched with the service token fetched on step 4.
Based on the research, the attackers also used a well-known technique to escape from a compromised container to the host. They did this by using bind mounts and fetching the Docker Hub credentials from the following paths:
/root/.docker/config.json
/home/*/.docker/config.json
When someone logs into their Docker Hub account using the Docker command line and there are no credential stores specified, the username, password and registry server link are populated as a JSON that looks like this:
By default, the registry used is of Docker Inc. The value of ‘auths.auth’ field is the base64-encoded string that contains the credentials in the format ‘username:password’. If these credentials are compromised, one can gain access to the victims’ information:
– Email ID used to create the account
– Private Images
– Access tokens
– Slack Webhooks
– Content Subscriptions
– Upgraded features
Enumeration Of Exposed Kubelets
This attack abused the Docker REST API to create a container from an image that had a script at the filesystem path ‘/root/init.sh’, which contains the following:
1. They initially update the alpine-based container and add the packages they need in later operations, like compiling zgrab from source, using masscan, etc.
2. Once the above steps are executed, they begin the execution of their malicious function using a kill switch, which is based on the contents of a certain endpoint on the attacker’s infrastructure to be equal to ‘RUN’.
3. Once the kill switch is confirmed to be equal to ‘RUN’, the malicious PWN function is executed.
This script fetches a scan range from a malicious server endpoint. If the results fetched contain ‘ENDE’, that signals the exit of the malicious script.
The results returned by the endpoint is stored in the variable ‘SCAN_RANGE’, which is later appended to ‘.0.0.0/8’. For example, if the value returned from the endpoint is 10, then the value of ‘SCAN_RANGE’ will be ‘10.0.0.0/8’
The variable ‘rndstr’ is a six-letter random alphabetical string that accumulates a list of IP addresses of running pods with the kubelet API TCP port 10250 exposed that have been found using masscan and zgrab. Once this subnet is completed, the results are sent back to the threat actor using a for loop, which iterates over the results acquired via a website.
Once the results are sent, the kill switch loop loops back for a new subnet from the infrastructure unless all the subnets are enumerated.
The threat actor seems to do this as preparation to later target exposed kubelets.