Using Bandcamp as a backup solution

If you’re a musician or a music lover, you’ve probably heard of Bandcamp before. It’s used by many indie and DIY bands to upload their albums, sell merchandise, and display upcoming shows.

As a noise artist, I’ve uploaded a few of my own creations to the site as well. In doing so, I learned of their exceptionally relaxed size limitations for their album and track uploads:

Bandcamp track size limit via their FAQ (https://bandcamp.com/help/uploading#maxupload)

As a hacker, this immediately piqued my interest:
You’re telling me I can upload 291MBs of data as many times as I want? Not to mention, if I want to upgrade to 600MBs I just need to spend $20 on myself?

This spawned the idea for BandcampFS!


BandcampFS

(https://github.com/tuxxy/BandcampFS)

BandcampFS is a tool I wrote to accomplish the goal of using Bandcamp as a storage medium. One of the best things about it is that it uses the Python standard library for everything! No external dependencies!!

In a short hour, I wrote BandcampFS to convert any binary file to a WAV file. I selected the WAV format for two reasons:

  1. Bandcamp only allows WAV, AIFF, and FLAC uploads.
  2. The WAV format is simple and in the Python standard library.

Furthermore, WAV is a lossless format so any converted data will be exact to the original file. Meaning that if I have a 20MB photo and I convert that to a WAV file, the size will be 20MB + the header which should be less than 1MB anyway.

Let’s dig into Python’s wave module: (https://docs.python.org/3/library/wave.html)

Encoding

import wave
with open('test_photo.jpg', 'rb') as f:
data = f.read()
wav_file = wave.open('test.wav', 'wb')
wav_file.setnchannels(1)
wav_file.setsampwidth(2)
wav_file.setframerate(44100)
wav_file.writeframes(data)
wav_file.close()

The above code opens a photo called ‘test_photo.jpg’ and reads the data from it. Then it opens a new file called ‘test.wav’ and allows us to write data to it.

wav_file.setnchannels(1)

This is setting how many channels in the audio where 1 would be mono, and 2 would be stereo. We only need one channel for our use.

wav_file.setsampwidth(2)

In the WAV format, we have sound data encoded into frames. Here, we’re simply declaring that we will have two bytes per-frame. This matches with our number of channels (one). For PCM encoding with mono, it should be set to 2 or 16-bit.
I learned that if you don’t have this set properly, Bandcamp will think the file is invalid due to the faulty encoding.

wav_file.setframerate(44100)

This is simply the frame rate of the track which is how many frames we’re playing a second. Typically, this sample rate is set to 44100.

wav_file.writeframes(data)

This will write our photo data into the frames of the WAV file with the correct number of ‘nframes’. Compare this to the `writeframesraw` function in the same module.

Decoding

import wave
wav_file = wave.open('test.wav', 'wb')
num_frames = wav_file.getnframes()
data = wav_file.readframes(num_frames)
wav_file.close()
with open('new_test.jpg', 'wb') as f:
f.write(data)

This code decodes the ‘test.wav’ file from above. Remember this is a photo encoded as sound. We then open up a new file ‘new_test.jpg’ and put the raw data in it.

num_frames = wav_file.getnframes()

All this does is tell us how many frames there are in the file. If you want to sanity check this, it should be equal to half the original unencoded file size. If it was a 10 byte file, it should be 5 frames.
This is because we set the sample width when we encoded it to two bytes per-frame.

data = wav_file.readframes(num_frames)

This reads the data from the number of frames you provide. This is our raw data from the original unencoded file.


Usage

Let’s go through a practical example. We’re going to upload the newest Arch Linux build (as of the writing, 07–01) as a WAV file to Bandcamp and store it there.

Step 1: Split the file

Since Bandcamp has a limit of 291MB per track and Arch Linux is ~510MB, we’ll need to split it to be able to upload it.

$ split -b 260M archlinux-2017.07.01-x86_64.iso

This will split the file into two parts outputting two files named ‘xaa’ and ‘xab’. Let’s rename them:

$ mv xaa arch_1
$ mv xab arch_2

Check the file sizes to confirm:

$ du -hs arch*
260M arch_1
250M arch_2
510M archlinux-2017.07.01-x86_64.iso

Looks good!

Step 2: Convert to WAV

This is easy with the BandcampFS script!

$ ./bandcampfs.py --encode arch_1
Data encoded to: arch_1.wav!
$ ./bandcampfs.py --encode arch_2
Data encoded to: arch_2.wav!

Give the files a listen! I love finding out how various types of files sound. The beginning of arch_1.wav sounds particularly cool!

Step 3: Upload to Bandcamp!

Depending on your upload speed, this can take a bit and is certainly the most annoying part about this hack.

Step 4: Download Album and Decode

https://bullswillriot.bandcamp.com/album/arch-linux-07-01
We have to download the album as WAV, otherwise it won’t decode properly. This will contain three tracks: arch_1, arch_2, and a bonus track of a .mov of my dog! I’ve included the SHA1 checksum of the arch files in the track info, if you want to verify it.

Now we’re going to unzip the album and decode:

$ unzip bulls\ will\ riot\ -\ Arch\ Linux\ \(07-01\).zip
Archive: bulls will riot - Arch Linux (07-01).zip
extracting: bulls will riot - Arch Linux (07-01) - 01 arch_1.wav
extracting: bulls will riot - Arch Linux (07-01) - 02 arch_2.wav
extracting: bulls will riot - Arch Linux (07-01) - 03 cookie.mov.wav
extracting: bulls will riot - Arch Linux (07-01) - cover.png
$ ./bandcampfs.py -d bulls\ will\ riot\ -\ Arch\ Linux\ \(07-01\)\ -\ 01\ arch_1.wav
Data decoded to: bulls will riot - Arch Linux (07-01) - 01 arch_1!
$ ./bandcampfs.py -d bulls\ will\ riot\ -\ Arch\ Linux\ \(07-01\)\ -\ 02\ arch_2.wav
Data decoded to: bulls will riot - Arch Linux (07-01) - 02 arch_2!

Alright, this looks good! Let’s cat these two files together to create the original ISO and compare the checksums:

$ cat bulls\ will\ riot\ -\ Arch\ Linux\ \(07-01\)\ -\ 01\ arch_1 bulls\ will\ riot\ -\ Arch\ Linux\ \(07-01\)\ -\ 02\ arch_2 > arch_linux.iso

We’re using the cat utility to join the two files together. Now it’s time to compare checksums! The SHA1 checksum from this mirror is:

dd03d811211c332d29155069d8e4bb2306c70f33  archlinux-2017.07.01-x86_64.iso

Let’s see what our ‘arch_linux.iso’ file is…

$ shasum arch_linux.iso
dd03d811211c332d29155069d8e4bb2306c70f33 arch_linux.iso

Success!! Our file has retained integrity and we’re also storing it on Bandcamp for free!


Recommendations

Now, this is just a proof of concept that shows how one could use Bandcamp as a storage or backup service. I’m not trying to convince anyone to jump ship from their current solutions to this hacky method. I just wanted to see if I could do it.

If you were serious about it, you could create a private Bandcamp album so no one else can see your data. Before uploading, I would also use GPG to encrypt the data so that only you have access to the plaintext.

What’s next?

I don’t know. I’m interested in trying to see if I can use Bandcamp as a C2 (Command & Control) server. That would be super interesting!
It would also be interesting to attempt to automate this process. Maybe it could be used as a means for data exfiltration?

If you liked this, please feel free to follow me on Twitter!