I’m not a cryptographer myself but I have always admired their work because literally they make the Internet a better place by creating technology that allows us our right to privacy and cybersecurity plus I enjoy playing basic crypto CTF challenges. At my current job I’m a weird mixture between Software developer and Information Security guy (finally the best of two worlds) that means I work a lot with security and crypto related matters and I’m also very fortunate for being able to work very close to a real cryptographer, so a couple months ago we were talking about security and I asked him if he could share some resources about cryptography but focusing on Software Engineers, meaning people without a heavy background in mathematics, this is what I learned.
If you are a Software Engineer curious about Information Security chances are you have crossed paths with a task that involves adding some kind of security mechanisms to protect data in your application, my friend explained me that in practice, cryptography is about choosing the right tool for the job and as a Security Software Engineer the most common tasks you will face are:
Encrypt a data blob or data stream
Exchange a secret key with a peer
Verify that some data blob or data stream is not modified
Verify that some data blob or data stream has been produced by someone specific.
Generate a secret key from another secret key
Generate a secret key from a (low-entropy) value – e.g. password
There are out there many cryptographic mechanisms that will make our lives easier when it comes to software engineering and we need to learn how to pick the right tool for the job
I’m not saying you should completely ignore the theory and jump directly into the practice, theory is important and you should learn it or at least be aware of the different types of cryptographic primitives, the most important classes/types are:
Modern cryptographic algorithms usually follow a more theory-based approach when it comes to achieve its goals and test its security, they usually do that by reducing the security relative to the primitives they use, it’s very common to read things like:
The scheme X achieves the security goals A, B and C if the underlying primitive Y is in-fact a K.
Primitives usually have a condition in the form of a mathematical proof or very hard problems to solve e.g. prime-factor representation for RSA asymmetric primitive or the discrete logarithm problem for the Diffie-Hellman key exchange algorithm, therefore If you want to break a cryptographic scheme you will first need to break the assumptions used by its primitives, if no one can do that then it’s safe to assume the cryptographic scheme is secure.
My point here is you need to understand what are the goals you want to achieve first, what is your requirement, that’s the only way you can pick the right cryptographic scheme based on the primitives that will solve your problem.
Let’s say you have an application that calculates the hmac-sha256 signature of a message using the password provided by a user as a key:
This works but there’s a problem with this approach, calculate hmac-sha256 signatures its trivial, with the help of a good dictionary an attacker can easily brute force the user password and if he succeed on obtaining the original secret he can impersonate the user in your application
Therefore, in order to make the job of the attacker more expensive in terms of time, computation and memory resources, the recommended approach is to use a Key-derivation function (KDF) or password-based key derivation function (PBKDF) when deriving a key from a password
When I learned this concept from my friend it was mind-blowing, In general you have to distinguish between deriving a secret key from a high-entropy source, like a cryptographic key, or from a low-entropy source, like a password. PBKDF usage is about trade-offs, try to hit a parameter such that the PBKDF is relatively cheap to compute for you in your scenario but expensive for the attacker that tries to brute-force the secret password.
Preserving data integrity is a crucial part when working with information, the easiest way to achieve data integrity is by encrypting the data, however sometimes you don’t want to do that because encrypting and decrypting data it’s an expensive operation and you only want to preserve data integrity, then the most straightforward solution is HMAC with a RO – like SHA-256.
Symmetric cryptographic schemes are better for encrypting a data blob or data stream vs asymmetric schemes due to performance advantages, the recommendation is to use Authenticated Encryption (AE) or Authenticated Encryption with Associated Data (AEAD). There are two main AEAD schemes used in practice: AES-GCM and ChaCha20-Poly1305. Both belong to the same class of cryptographic objects: AEAD.
Early this year I got one of those widescreen 5k monitors so I could work from home, the display is so cool but the sad thing is it only comes with 2 USB ports. I have a wired mouse and keyboard so when I wanted to connect an external hard drive for copying and backing up files it was always a pain in the neck.
I remembered I have an old Raspberry PI2 I brought with me from México so last weekend I decided to work on a small personal project for solving this issue once and for all, I finished it and it’s working very well so I thought on writing a blogpost about it so more people can build its own private cloud at home too.
The first thing was to install a fresh version of raspbian into the raspberry pi, I got it from https://www.raspberrypi.org/downloads/raspbian/, I wanted something minimal so I got the Raspbian Buster Lite image, this version of raspbian doesn’t come with a graphical interface but it’s fine because ssh it’s all what we need.
Insert the SD card into your machine, I’m using a macbook pro so I have to use an adapter, once the card is there you can verify using the df command, tip: you can easily identify your SD card by the size reported by df -h.
Optionally you can do all this process in a more friendly way by installing Raspberry Pi imager tool https://www.raspberrypi.org/downloads/, you need to insert your sd card, choose the os, choose the sd card and the click the write button.
Once you have your fresh version of Raspbian installed it’s time to verify the Raspberry is working, the easiest way to do that is to connect a monitor and keyboard to it, so I did it.
When you connect the raspberry to the power the green led should start flashing, if that doesn’t happen is probably a sign of a corrupted EEPROM and you should look at the Recovery section of https://www.raspberrypi.org/downloads/.
Access the Raspberry Pi remotely
Alright, if you get to this point means your raspberry is fine, next step is to connect it to your network, I connected mine to my switch using an ethernet cable, before ssh into the raspberry first we need to get its IP, there are multiple ways to get the IP address assigned to your raspberry, I used nmap https://nmap.org/ to quickly scan my local network for new devices.
nmap -sP 192.168.86.0/24
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-29 19:55 PDT
Nmap scan report for testwifi.here (192.168.86.1)
Nmap scan report for raspberrypi (192.168.86.84)
Host is up (0.0082s latency).
Nmap done: 256 IP addresses (10 hosts up) scanned in 2.55 seconds
Ok from now on I’m going to start referring to the raspberry as nstorage (network storage), on my local machine I added a new entry to /etc/hosts with this information.
# Minio running in raspberry pi in home network
I also added a new entry on ~/.ssh/config so it is easier to connect via ssh.
You can type on your terminal ssh nstorage, and login using the default credentials: pi / raspberry.
Linux raspberrypi 4.19.97-v7+ #1294 SMP Thu Jan 30 13:15:58 GMT 2020 armv7l
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Mar 30 03:27:49 2020 from 192.168.86.64
[email protected]:~ $
One thing I always like to do is to add the public ssh key of my machine (my macbook pro) to the list of authorized_keys on the remote server (nstorage), you can do this by copying your public key: cat ~/.ssh/id_rsa.pub | pbcopy and then in nstorage in the /home/pi/.ssh/authorized_keys (create the file if it doesn’t exist) file append the key to the end.
We are almost there, you have a minio server running in your raspberry pi, you can start uploading files and creating buckets if you want, but first let’s add some security.
Securing your Minio
Right now all the traffic between you and nstorage (your minio server) is unencrypted, let’s fix that quickly, I used mkcert https://github.com/FiloSottile/mkcert by Filippo Valsorda for quickly generate certificates signed by a custom certificate authority, sounds scary but is actually quite simple.
In the raspberry we are going to create the following folders to hold the certificates.
In your local machine we generate and push the certificates to the raspberry, dont forget to also push the public key of your local certificate authority created by mkert under /Users/$USER/Library/Application Support/mkcert/rootCA.pem.
$ mkcert nstorage
Using the local CA at "/Users/alevsk/Library/Application Support/mkcert" ✨
Created a new certificate valid for the following names 📜
The certificate is at "./nstorage.pem" and the key at "./nstorage-key.pem" ✅
$ ls nstorage*
$ scp ./nstorage* [email protected]:~/.minio/certs
$ scp ./rootCA.pem [email protected]:~/.minio/certs/CAs
$ scp ./rootCA.pem [email protected]:~/.mc/certs/CAs
That’s it, you have now a secure connection with your Minio, if you go to your browser you can HTTPS this time.
Nstorage certificate is valid and trusted by your system because was generated by your local certificate authority, every device that wants to access this server need to trust the CA as well, otherwise it will get a trust error.
Mount external drive
Alright, so far you have a secure Minio running on the raspberry pi, in my case I used a 16GB SD card, which was not enough for storing all my data and the whole point was to access my external drive files remotely, so let’s do that now. But first instead of start Minio manually let’s create a bash script and change the default credentials.
Create a new file using vim or your editor of choice: vim start.sh
Now connect your external hard drive to one of the USB ports, I had some issues while doing this, Raspbian was not listing the device under /dev so make sure to increase the USB ports power via configuration in /boot/config.txt, add max_usb_current=1 to the end of the file.
[email protected]:~ $ cat /boot/config.txt
# For more options and information see
# Some settings may impact device functionality. See link above for details
# Increase power available to USB ports
Reboot the raspberry and plug your drive again, if everything went right you should be able to see your external drive using fdisk.
$ sudo fdisk -l
Disk /dev/sda: 4.6 TiB, 5000981077504 bytes, 9767541167 sectors
Disk model: Expansion Desk
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 24A09C07-313E-43B6-A811-FAF09DAB962C
Device Start End Sectors Size Type
/dev/sda1 34 262177 262144 128M Microsoft reserved
/dev/sda2 264192 9767540735 9767276544 4.6T Microsoft basic data
You can download every file you want, upload files and also stream media. Go to your Minio browser and select any video you like, click on the “3 dots” icon on the right and click the share icon.
Minio will generate a pre-signed URL that you can use on VLC, click on File > Open Network and paste the video URL.
Click the open button and enjoy your videos.
Everything is great so far, you are able to access all your files from any device in your network but if your raspberry loses power and reboot you will need to mount the external drive and start the Minio server manually again so let’s automate that.
Mount the external drive with fstab
On linux by default every drive listed in /etc/fstab will be mounted on startup, there are many ways to mount drives but the recommended way is using UUID or PARTUUID instead of the name.
Locate the PARTUUID of your own drive, mine was 5206da84-ded1-43b6-abf2-14b5950c4d7c, and then add it at the end of your /etc/fstab file.
$ cat /etc/fstab
proc /proc proc defaults 0 0
PARTUUID=738a4d67-01 /boot vfat defaults 0 2
PARTUUID=738a4d67-02 / ext4 defaults,noatime 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
PARTUUID=5206da84-ded1-43b6-abf2-14b5950c4d7c /home/pi/data ntfs defaults,errors=remount-ro 0 1
Reboot your raspberry and verify your drive was mounted automatically under /home/pi/data.
Start the Minio server with systemctl
Finally, the last piece of the puzzle is to make minio to start automatically, again, there’s many ways to do this but in this tutorial we will do it with init system or systemctl, let’s create a file called minio.service with the following content.
ExecStart points to the start.sh bash script, After directive will tell the Minio server to wait until the network service is online and the /dev/sda2 drive is mounted by fstab, home-pi-data.mount is a systemd mount unit you can get using the systemctl list-units command.
Start minio as a systemd service using the start command and verify is running with the status command.
[email protected]:~ $ sudo systemctl start minio
[email protected]:~ $ sudo systemctl status minio
● minio.service - Minio Storage Service
Loaded: loaded (/etc/systemd/system/minio.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2020-03-30 10:12:22 BST; 4s ago
Main PID: 1453 (start.sh)
Tasks: 16 (limit: 2200)
├─1453 /bin/bash /home/pi/start.sh
└─1456 minio server /home/pi/data
Mar 30 10:12:22 raspberrypi systemd: Started Minio Storage Service.
If everything looks fine, enable the service, Minio will start automatically every time your Raspberry pi boot.
sudo systemctl enable minio
Reboot your raspberry pi one last time and verify everything is working as expected, if you are able to see the minio browser at https://nstorage:9000/minio without you having to do anything congratulations you now have your own private cloud at home powered by Minio :).
Using the flag obtained in the previous challenge, we go to the URL showed in the description and we will see the following screen.
It’s a simple web page with a basic input form, very similar to the previous one but they have added a character filter, we proceed to click the View sourcecode and we are redirected to index-source.html
This is supposed to be the backend code of the html form.
The preg_match(‘/[;|&]/’,$key) function will make sure to drop any search request that contains the ; or & characters so we cannot execute additional commands like we did on the previous level, but instead of trying to bypass this filter there is an easier way to solve this level, the grep command supports search for a pattern in multiple files so we are going to exploit that, the goal is to execute something like this:
Since ” /etc/natas_webpass/natas11 doesn’t contains any of the filtered characters we can just send this payload through the form.
The flag for the next level, natas11, is: U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
In this challenge we exploit a command injection vulnerability that essentially allow us to execute arbitrary commands on the server, this time there was a security mechanism in place but the fundamental problem was still there. Depending on the privileges of the user running the web server we might read, write or delete files.
The vulnerability in this code happens when calling the passthru function, we are reading user input directly from the needle request parameter, then saving it into the $key variable and using it without any kind of sanitization when calling the function, that’s essentially command injection. We are going to try to execute commands in the web server by exploiting this vulnerability.
Sending ;ls -la;
Results in all files on the current directory to be listed
I was a little bit lost at this point but then I remember the CTF instructions.
Each level has access to the password of the next level. Your job is to somehow obtain that next password and level up. All passwords are also stored in /etc/natas_webpass/. E.g. the password for natas5 is stored in the file /etc/natas_webpass/natas5 and only readable by natas4 and natas5.
So we do ;cat /etc/natas_webpass/natas10;
The flag for the next level, natas10, is: nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu
As mentioned before, this challenge we exploit a command injection vulnerability that essentially allow us to execute arbitrary commands on the server, depending on the privileges of the user running the web server we might read, write or delete files.
So we need to perform exactly the same operations but in reverse order to obtain the original secret, ie: the old bin2hex should be hex2bin, I don’t know if we should call this reverse engineering, anyway ¯\_(ツ)_/¯