So I received a broken Coinmine One and decided it would be a good project to try to reverse engineer how it works. Opening it up, everything was surprisingly standardized with very little proprietary. I don’t have images of my own, so here is one from cryptobrief.com.
As you can see, it’s just a small normal PC in a fancy case.
Investigating
Using a SATA <-> USB adapter, I connected the hard drive, and to my surprise it was unencrypted. It consisted of 4 partitions as seen with fdisk
Disk /dev/sdd: 931.53 GiB, 1000204886016 bytes, 1953525168 sectors
Disk model: 048-2E7172
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 9F944706-4C90-43CC-A5BD-F1AFEE12D9C7
Device Start End Sectors Size Type
/dev/sdd1 2048 22527 20480 10M BIOS boot
/dev/sdd2 22528 1046527 1024000 500M EFI System
/dev/sdd3 1046528 27353087 26306560 12.6G Linux filesystem
/dev/sdd4 27353088 81233919 53880832 25.7G Linux filesystem
Mounting the 2 ext4
partitions we can what the contents are.
The first one consists of your normal linux install with the exception of the coinmine
directory which is empty, we’ll get to that later.
$ ls
bin boot coinmine dev etc home lib lib64 lost+found mnt opt proc root run sbin srv sys systemd tmp usr var
The second one consisted of just 2 folders
$ ls
Docker_Volumes lost+found
Using tree
in Docker_Volumes
revealed what it was for, holding data about the blockchain.
$ tree . -d
.
└── Lightning
├── Mainnet
│ └── bitcoind-mainnet-data
│ ├── blocks
│ ├── chainstate
│ ├── database
│ └── indexes
│ └── txindex
└── Simnet
This isn’t too important for me, and it just takes a bunch of storage, so I won’t be saving this partition to the disk image I’ll be creating later.
Now, about the /coinmine
directory, checking the fstab
reveals that the 4th partition just gets mounted to that directory. Mystery solved.
# <file system> <dir> <type> <options> <dump> <pass>
# UUID=b743e635-a3ef-4935-a1ba-bb84f90b16b1
UUID=b743e635-a3ef-4935-a1ba-bb84f90b16b1 / ext4 rw,relatime 0 1
# UUID=6276-E51F
UUID=6276-E51F /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 2
# UUID=86a03524-90b1-47d2-8759-57316eccf473
UUID=86a03524-90b1-47d2-8759-57316eccf473 /coinmine ext4 rw,relatime 0 2
Going back to the main partition, I decided to check on the home
folder.
$ ls /home
builduser satoshi
builduser
is a user I assume is used to build something needed for the OS to work. I don’t know exactly what it’s for, it seems to build yay
.
satoshi
is more interesting:
$ ls /home/satoshi/
config.yaml docker-compose.prod.yml docker-compose.yml programs
Looking at the compose files, it’s used to run their software, including mining, as the gpu gets passed into the container. It consists of 2 services miner_updater
and minary_api_server
. They also seem to use ngrok for debugging, but this is the production docker-compose, weird. Looking at the docker-compose
docs the prod
file is used to say what changes should be made from the original compose file. This makes a lot more sense. Bellow are the 2 compose files linked as a github gist (they are pretty long):
Next I wanted to investigate what’s inside the containers, but I found no easy way to do so, so I instead decided to just use a virtual machine and boot from a hard drive image.
Creating disk image
The hard drive itself is 1TB in size so creating a disk image directly would be waste of space. What I decided to do, was to create images of the first 3 partitions and the combine them together to create a disk image. I did not include the last partition since it was large and just contained blockchain data. In addition to save space, I shrunk the partitions to make it easier to work with.
To start I used gnome disk utility, which allowed to me to create partition images easily from the gui. With that done, I was left with 3 images:
coinmine_part_1.img
coinmine_part_2.img
coinmine_part_3.img
Now I needed to combine those into one image. I found this StackExchange post which was exactly what I needed.
To start I created a sparse image with the appropriate size:
dd if=/dev/zero of=coinmine.img bs=1 count=0 seek=16G
Next, created partitions using fdisk
, with the appropriate size of partitions corresponding to the partition images we created with gnome disk utility, which resulted in:
Disk coinmine.img: 16 GiB, 17179869184 bytes, 33554432 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 66406CAA-4B3D-764B-92BA-48BAE3A83022
Device Start End Sectors Size Type
coinmine.img1 2048 24575 22528 11M Linux filesystem
coinmine.img2 24576 1099775 1075200 525M Linux filesystem
coinmine.img3 1099776 30459903 29360128 14G Linux filesystem
Now, this is the magic part. Using kpartx
we can create devices from the partitions, to which we can write to with dd
.
kpartx -av coinmine.img
dd if=coinmine_part_1.img of=/dev/mapper/loop0p1 bs=1M
dd if=coinmine_part_2.img of=/dev/mapper/loop0p2 bs=1M
dd if=coinmine_part_3.img of=/dev/mapper/loop0p3 bs=1M
kpartx -dv coinmine.img
And that’s it. The disk image is created.
Changing root password
With the disk image, there comes another issue. I don’t know what the root password is on the image, so it needs to be changed. This can be done relatively easily however.
Using kpartx
again, I can easily mount the 3rd partition. Next chroot
can be used to change the root password:
$ sudo chroot ./
# passwd
New password:
Retype new password:
passwd: password updated successfully
The reasoning behind how this works is a little complicated, but basically what it does is change what the apparent root location is. In the terminal now instead of /
aka root being the root of my OS, instead it’s changed to the image. Then the passwd
command, it’s referencing the image’s passwd
program, not my computer’s, if that makes any sense.
Make virtual machine
For the VM I’m using Virt Manager, a GUI frontend to QEMU/KVM. Setup is just like normal, it needs 4GB of memory and be in UEFI mode not legacy BIOS mode. When the VM starts though, we’ll run into a bit of an issue. Because we never moved over the 4th partition, it’s trying to mount it and failing. Therefore it drops us in emergency mode, where we can login as root and make the edits needed to fstab
. All that’s needed is adding nofail
to the mount, so now it looks like this:
# <file system> <dir> <type> <options> <dump> <pass>
# UUID=b743e635-a3ef-4935-a1ba-bb84f90b16b1
UUID=b743e635-a3ef-4935-a1ba-bb84f90b16b1 / ext4 rw,relatime 0 1
# UUID=6276-E51F
UUID=6276-E51F /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 2
# UUID=86a03524-90b1-47d2-8759-57316eccf473
UUID=86a03524-90b1-47d2-8759-57316eccf473 /coinmine ext4 rw,relatime,nofail 0 2
And that’s it for part 1. I’ll go into a deeper dive into seeing how the software works in part 2. Thanks for reading.