Skip to content

Building a MagicMirror using VESA mount

There are a lot of MagicMirror building tutorials out there. So why another one? The tutorials I saw always dismantled the display in order to build the case around it. I did not want to do it this way. Actually, I wanted to be able to easily exchange the display if it breaks down. So I decided to use the VESA wall mount capability of the display in order to fixate it into the mirror.

Another thing I saw a lot in other MagicMirror tutorials was that the front part of the frame had screws in it or was not sawed in a straight line. This I found rather ugly because it is the part you see the most when you use your MagicMirror in your living space. Therefore, I decided to use a frame for pictures that I can buy. At this shop (German link) I bought the frame "Monaco" in black with a size of 60cm x 40cm. Now the only missing part was the mirror glass. This I bought at this shop (German link), again with a size of 60cm x 40cm. When I got both, the mirror glass fitted perfectly into the frame. Now it was time to build the rest of it.

The first thing I did, I crafted a casing that I can put under the bought frame. I used a height of 13cm, but afterwards I realized it could be smaller (perhaps 8cm).















Next thing was that I painted the casing black in order to make it fitting for the bought frame.









Next I used wood glue to glue both parts together.








Because the mirror glass is really heavy, I did not think the glue alone would hold. Therefore I also screwed everything together from the inside.







This was the first intermediate result.









Next I used the VESA 100x100 mounting feature of my display to connect it to the mirror casing. I used an old 24" LCD display I had at home. If you use a new LED display, it would be thinner and much lighter. Personally, I would recommend to use a new LED display.









The first test of the display.







I used normal angle brackets to build a mount for the wall. These I use to hook the mirror up to screws I put into the wall.









Next I build a small mount for my Raspberry Pi 3 casing.







A small test if the new Raspberry Pi works with the vertical video output option.





Next I just added all the cables for the power supply and hooked it up to the wall.







And here is a final picture of it running the MagicMirror framework.



The mirror shows the sate of the alertR monitoring and alarm system. I wrote two MagicMirror modules, one that displays the states of the sensors and one that displays all sensor alerts. Also in order to reduce the power consumption, the MagicMirror tests if the alarm system is activated (and therefore everyone is sleeping or not at home) and turns off the display if it is. So if you are not only interested in the MagicMirror itself but also in alertR, feel free to give it a try :-)

Security Issues in PrivateEyePi Home Alarm System: Why I would not use it!

Introduction

PrivateEyePi is a home automation and monitoring project for the RaspberryPi. I saw some articles about PrivateEyePi and saw that they even have their own store on their website. Since I am the author of alertR (another open-source alarm system), I thought I take a closer look at what they are doing. Before I started with alertR, I looked briefly at some open-source projects to see if some project is doing what I wanted to do. In most cases it was sufficient to only look at the website of the project. PrivateEyePi was quickly dismissed by me because they only work with one host. Hence, I never took a closer look into it. And I know that it looks a little bit pitiful that I am writing an article about "how insecure this project is". But after taking a closer look, I have to say that from a security perspective I strongly discourage anybody to use it. And the following will explain why ...


Installation

Let us start at the beginning. And in the beginning was ... the installation. As far as I can tell I analyzed version v12 of the PrivateEyePi software. For all versions, the project explains in a small tutorial how to install PrivateEyePi. They describe that you should download the install.sh file and execute it via sudo sh install.sh. The install.sh file looks like the following:


sudo rm -f pep.zip
sudo mkdir -p pep_backup
sudo mv alarm.py pep_backup 2>/dev/null
sudo mv restarter.py pep_backup 2>/dev/null
sudo mv alarmfunctionsr.py pep_backup 2>/dev/null
sudo mv dht22.py pep_backup 2>/dev/null
sudo mv dallas.py pep_backup 2>/dev/null
sudo mv rfsensor.py pep_backup 2>/dev/null
sudo mv globals.py pep_backup 2>/dev/null
sudo mv webcam.py pep_backup 2>/dev/null

sudo mv lcd_hd44780.py pep_backup 2>/dev/null
sudo mv lcd_nokia.py pep_backup 2>/dev/null
sudo mv lcdtest.py pep_backup 2>/dev/null
sudo mv publish.py pep_backup 2>/dev/null
sudo mv subscribe.py pep_backup 2>/dev/null

sudo wget www.privateeyepi.com/downloads/pep.zip
unzip -o pep.zip
sudo chmod 777 alarm.py
sudo chmod 777 dallas.py
sudo chmod 777 globals.py
sudo chmod 777 alarmfunctionsr.py
sudo chmod 777 dht22.py
sudo chmod 777 restarter.py
sudo chmod 777 pep_backup
sudo chmod 777 webcam.py

sudo chmod 777 lcd_hd44780.py
sudo chmod 777 lcd_nokia.py
sudo chmod 777 lcdtest.py
sudo chmod 777 publish.py
sudo chmod 777 subscribe.py

sudo apt-get install python-serial
 


Perhaps some of you saw my little Twitter rant (actually, I do not think so but everyone can hope, right? ;-) ). First of all the install.sh file is already executed with sudo. Therefore all the additional sudos are unnecessarily. Second, you should not execute wget or unzip with root permissions. You never know what nasty bug could be triggered. But what you certainly do not do is change the file permissions for a file owned by root (or in this matter for any other user) to 777 (world-read-exec-write)! To make this bug complete, in the next steps of the tutorial the alarm system is started via the command sudo python alarm.py, which means it is also run with root permissions.

Perhaps some of you ask now "Why shouldn't I have a file world-read-exec-writable? And why not as root?". Well, some other user on the same system can write into the file (it is writable by everyone, so it can be any user). And when the application is now executed with root permissions, this user can execute code with root privileges.

Well, this was the installation process. Let us switch to the next step in the installation tutorial, the registration at the central server of PrivateEyePi.


Central Server Webinterface

You have to register an account on the central server of PrivateEyePi in order to use your alarm system at home. Wait, what?! Yes, PrivateEyePi uses a central server which is owned by them to give user access to their home alarm system. Sounds suspicious you think? Well, we will come back to this later.

We go not into depth here, since I am not the owner of this server and probably have no permission to test the webinterface. But again, perhaps you saw my little rant on Twitter again :-) .






You can see that when I want to change my user account information, I can see my used password in the source code of the page. What does this mean? First of all this means that the password is stored in plaintext. This means anyone of the PrivateEyePi guys can read your password (or any attacker that compromised the server). If you have used your default password and your default eMail address that you use everywhere: Sucks to be you :-P ! Second, even if you have a magical reason to store the password in plaintext (there is none!), you certainly do not send it back to a web page. For example, if you are logged in to the webinterface and someone else uses your browser, this someone can see your password.

This is all I can say about the webinterface. But seeing the quality of the code so far I am pretty sure that you will find other security issues there like SQLi (which would probably allow you to get user informations like eMail addresses and passwords ... in plaintext).

What is next in the installation tutorial? The configuration of the alarm system.


Configuring the Alarm System

Now we come back to the central server part. The alarm system is mainly configured via the webinterface on the central PrivateEyePi server. Stuff like eMail addresses the alarms should be sent to, GPIOs of the sensors etc. are configured via the central server. The stuff that is configured locally can be found in the globals.py. This is rather uninteresting stuff like user credentials for the central PrivateEyePi server, or if the temperature is shown in Fahrenheit, SMTP server settings, or the GPIO for a connected siren (I do not know why this is actually configured locally when the sensors are configured on the central server).

The architecture of the system can be seen in the following figure:



As can be seen, all sensors and other hardware is connected to the RaspberryPi. The home alarm system collects the data and sends it to the central server. Additionally, the home alarm system polls the server for commands it should execute. The webinterface of the central server can be used by the user to see the information the sensors collect and give commands like turning off the alarm system (hopefully, some of you already see how problematic this design is ... if not, I will come to it in a few seconds).

I think this design was chosen to circumvent the need to configure port forwarding on the local router. This way, a user is able to reach his home alarm system from his mobile phone without changing any Internet settings at home or setting up a service that is reachable from the Internet. But this design is quite problematic and also naive. Why naive? Well, imagine you have a home alarm system. Would you tell a stranger that nobody is at your home? And while we are on it, would you also give this stranger the key to disarm your home alarm system? No? Well, me neither. But if you use PrivateEyePi you do.

Let me explain why before I show concrete attack scenarios. PrivateEyePi sends the collected sensor data to the central server. If you have motion detection sensors and sensors at your windows and doors, their states are send to the central server and stored there. Not only you, but also the PrivateEyePi guys and an attacker that compromised their server are able to see this information. Therefore, they know when no one is at your home. Since the central server is able to send commands to your alarm system, the PrivateEyePi guys and an attacker is also able to do it. Hence, these strangers are able to disarm your alarm system.

Now let us take a look at concrete attack scenarios.


We are secure. We used encryption!

First we take a look at the connection between the home alarm system and the central server. These connections can be found in the alarmfunctionsr.py and webcam.py file. Both are done in the same way. A https URL is visited with GET parameters that either update the data on the central server or request data. This URL also contains the username and password of your user account. Well, since they are using an encrypted connection to their central server, everything is fine and we can go to the next section? Not exactly. Yes, they are setting up an encrypted connection. But they are using urllib2 for it. And urllib2 does not validate the certificate offered by the server by default. This option has to be manually set. And yes, there is a proposal to activate this check by default. But I do not know if it is already implemented. I checked it with Python 2.7.6 and it does not verify the certificate. Hence, when an attacker is able to hijack the connection he can just offer any certificate and the home alarm system will accept it. Therefore, an attacker does not necessarily have to compromise the central server, he just needs to hijack the connection (although I guess the first option might be easier).


I spy with my little eye ... uff, why am I suddenly blind?

The home alarm system gets its sensor configuration from the central server. Therefore, the central server can just send an empty or false configuration to the home alarm system. And suddenly ... the home alarm system is blind. This way an attacker is able to disable the alarm system completely or just remove specific sensors (to be a little bit sneakier).

Why does this work? Well, in the file alarm.py the main() function enters an infinity loop which polls the GPIO states of the sensors. And this infinity loop polls also the current configuration from the central server and applies it locally any 600 seconds.


Look mum no hands!

One interesting command is the /PHOTO command. This attack only works if a webcam is connected to the home alarm system and the SMTP server is configured to send eMails. Well, what does it do? The command tells the home alarm system to send an eMail to the configured eMail addresses with a picture taken by the webcam. The fun part is, the eMail addresses this message is sent to are also configured via the central server. Before the home alarm system sends this message, it asks the central server for the eMail addresses. Therefore, the attacker can just send his eMail address to the home alarm system and gets a picture taken by the webcam. No one else is getting this message. So it is kind of sneaky ;-) .

If you want to see it for yourself, you can find it in the alarmfunctionsr.py file. ProcessActions() is called when a message is received from the central server. This calls SendEmailAlertFromRule() with all the necessary arguments to take a picture. A thread is started that executes SendEmailAlertThread(). This function gets the eMail addresses from the central server with GetDataFromHost() and the used arguments. Then it builds the message and sends it to the received eMail addresses.


Inoutput. What?!

This is a really cool attack, because it can actually damage the hardware. The command /RELAYON is responsible for it. With this command, a GPIO pin number and the option HIGH or LOW is also received. What does it do? Well, it sets the given GPIO pin number as output pin and sets it to either HIGH or LOW. In the case of RaspberryPi, HIGH means it sets up 3.3V. This can be used for two attacks. First, we can trigger a sensor that is configured on our home alarm system. This can be done by setting the GPIO pin to a HIGH state that is also used as an input GPIO pin of a sensor. Second, if the sensor (or other hardware) that is connected to a GPIO pin that is set to a HIGH output is not built well, it can be damaged (I asked an electronics guy because I was not sure, and he told me it can happen). Not so often that we see a software attack that can actually damage hardware :-) .

Again, this can be found in the alarmfunctionsr.py file. ProcessActions() is called when a message is received from the central server. This calls SwitchRelay() which sets the GPIO pin to an output port and to HIGH/LOW.


Miscellaneous Stuff

I am not a professional programmer. Therefore, I do not like to say stuff like "Uh, look at this shady code!". But there are some constructs in the PrivateEyePi code I wanted to show. Let us just look at the function ProcessActions():


def ProcessActions(ActionList):
    FalseInd=True
    for x in ActionList:
        if x[0]=="/EMAIL":
                SendEmailAlertFromRule(x[1], x[2],0)
                x.remove
        if x[0]=="/SEMAIL":
                SendEmailAlert(x[1])
                x.remove
        if x[0]=="/CHIME":
                StartChimeThread()
                x.remove
        if x[0]=="/rn588":
                exit()
        if x[0]=="/FALSE":
                FalseInd=False
        if x[0]=="/SIREN":
                StartSirenThread(x[2])
                FalseInd=3
                x.remove
        if x[0]=="/PHOTO":
                SendEmailAlertFromRule(x[1], x[2],1)
                x.remove
        if x[0]=="/RELAYON":
                SwitchRelay(1,x[2])
                x.remove
        if x[0]=="/RELAYOFF":
                SwitchRelay(0,x[2])
                x.remove
        if x[0]=="/WRELAYON":
                SwitchRFRelay(1)
                x.remove
        if x[0]=="/WRELAYOFF":
                SwitchRFRelay(0)
                x.remove
    return(FalseInd)
 


The argument ActionList has the type list. Well, what does this function do? It iterates over the ActionList elements and checks if they contain a specific known command (more specifically, if the first element of this list contains a specific command). In the end, the function returns FalseInd.

Let us take a closer look at FalseInd. Do you see it? In the beginning this variable is set to True. If the command /FALSE is received, it is set to False. When the command /SIREN is received, it is set to 3. Dafuq?! I know that Python allows you to do this. But this does not mean that you should do it (like goto in C). If you use a variable as a boolean, stick to it and do not change it to an integer.

Also, each list element x should be removed from the ActionList (at least, I think this is what it should do). Hence, the line x.remove. Well, x is a list and has therefore the function remove(). But first of all, it is not invoked by the line x.remove. This just returns you the address of the function. And second, remove() takes an argument. Therefore, this line does actually nothing and does not make any sense.

Another thing you often see in the code is something like the following:


[...]
def PollGPIO():
# Routine to continuously poll the IO ports on the Raspberry Pi
        global ciruit
        global GPIOList
        global numgpio
        global GPIO
        global AlarmActioned
[...]

def NotifyHostEvent(z, status):
        global GPIOList
        global Locations
[...]

def PollRoutine():
        global start_time
        global elapsed_time
[...]
 


I do not know why they are using global variables for everything. Hell, even the whole configuration is done with global variables. And the file is called globals.py. And because of the import globals in the beginning of each file, this has strange effects on the syntax highlighting of an editor. Because globals() is a built-in function in Python, the editor highlights any use of the configuration variables like globals.LCDAlarmActivity. Definitely another thing you do not do when programming in Python.


Conclusion

This was a non-exhaustive list of security issues I found in PrivateEyePi. Note that I did non take a detailed dive into any file. Only the parts that work directly with data from the central server I looked into (and I did not really track the complete data-flow ... there could be a lot more to find). Well, as you have seen these are the reasons I would not recommend using PrivateEyePi. In my opinion, it is totally broken by design. The complete alarm system can be controlled by the PrivateEyePi guys and if the server is compromised, an attacker can so too. Additionally, the design allows an attacker to actually damage the connected hardware.


Update 06-01-18

The PrivateEyePi authors contacted me and said that they fixed a lot of issues in their current version. The following is a summary of changes they send me. However, I like to stress that this is only a list of things the authors send to me. I did not check the code if these changes were actually made:

- User password encryption in database and password are no longer passed from server to client.
- Devices and sensors connecting to PrivateEyePi server now use a token to authenticate, not email and password. The token cannot be use used to login to the website. The token is only displayed to the user once and never transmitted from the server to the web page after the initial creation.
- Alarm activation/deactivation can only be done through the website.
- Remote control for GPIO, RF devices and web cam photo function configured off by default through a new setting AllowExternalControl.
- Installation script does not use chmod 777 anymore and removed sudo where it is not necessary.
- Python 2.7.9. now validates certificates by default.
- Cleaned up use of FalseInd Boolean variable to store status beyond True/False.
- Cleaned up remove function from ActionList.

alertR: Version 0.300 Released

alertR is a project of mine which I started in August 2014. It is an unified alerting system which is based on a client/server model. The main part is written in Python and is published as Free-Software. If you do not know this project yet, here are some interesting links:

* Github repository
* Github wiki for documentations
* Blog article: Introducing alertR: Open-Source alerting system (with video)
* Blog article: alertR: dbus and xbmc notification client (with video)
* Blog article: alertR: rule engine (with video)


What is new?

The alerting system can now distinguish between "triggered" and "normal" state sensor alerts. A "triggered" sensor alert happens, when the triggered state of the sensor is reached (for example a door is opened). The "normal" sensor alert happens (if configured to be considered), when the sensor goes back to the normal state (for example if the opened door is closed again).

The Mobile Manager was split into "alertR Web Mobile Manager" and "alertR Manger Client Database". The idea of the database manager is that it can be used to provide the data of the alerting system to other "not alertR" components. The database is the shared medium that have to be read by the components (for example a web page or an IRC bot) to get the information. In order to have a way for the components to communicate with the alerting system, the database manager has a local UNIX socket server. Additionally, the database manager is now able to store events in the database as an event log. Furthermore, the database manager can check the versions of all alertR clients against the available versions in the online repository.

Last but not least, an alertR survey was added to the alertR server. The server can now participate in this survey and will send information about the used versions, instances, and if the online update is activated or not once a week to the survey server. The participation in this survey is optional and can be completely disabled in the configuration file of the server. The survey was added to the alertR system, because of the install and update mechanism that uses the Github repository. The way these mechanisms work, no data can be derived of the used instances or whether alertR is used after all.


Mobile Web Page

The mobile web page was completely rewritten for the new version. It is now able to show all information about the alerting system that is available. Also, because the alertR Manger Client Database can store an event log of events happening in the alert system, the mobile web page can display you an event log. The following shows a screenshot of the overview site of the mobile web page:

alertR: rule engine

Foreword and interesting links

alertR is a project of mine which I started in August 2014. It is an unified alerting system which is based on a client/server model. The main part is written in Python and is published as Free-Software. If you do not know this project yet, here are some interesting links:

* Github repository
* Github wiki for documentations
* Blog article: Introducing alertR: Open-Source alerting system (with video)
* Blog article: alertR: dbus and xbmc notification client (with video)


Introduction and motivation

Since I implemented alertR inside my home, I still had motion sensors connected to a Raspberry Pi which were not managed by alertR. The reason of this was that first one of the two motion sensors had to trigger and then in a time frame of 5 seconds the next one has to trigger before an event should happen.

Because of this I started to implement a "rule engine" for alertR over the Christmas time. And finally it is finished.


Example

Before I tell you the details about the rule engine, I want to show you that the rule engine works via a short video. Please have the subtitles activated to get a description of what I am doing and what is happening.




How does it work?

As you could see/read in the video I used the two motion sensors to start the media center in my living room and to let it play a specific radio channel. This should only happen during the week (not on a weekend) and only at the time when I have to stand up to go to work. The media center has speakers in the living room, kitchen and bathroom. So I can hear the music inside my apartment while I prepare my self to leave for work.

Now with the rule engine alertR can manage this setting too. The rule engine is able to chain rules together so you can have a sequence of rules which have to be fulfilled in a specific order and in a specific time frame. One rule can consist of different rule elements that are bound together by a boolean operator.

Note at this point that this rule engine is event driven. This means that it is only checked if a sensor event is sent to the server (this also means that a rule must have at least one sensor in it). It does not work if you have a rule configured which just checks the time (if you want something like this, use cron as a sensor) or if you only have one sensor in this rule which state is negated by a NOT.

Here is a list of the elements that are supported (at the time of writing this) by the rule engine:

* sensor - this rule element represents a sensor of the alertR system and is evaluated if a sensor trigger event is sent to the server
* boolean - this is a boolean operator to form a complex rule with the given rule elements (supported operators are: AND, OR and NOT)
* weekday - this element represents the day of the week (Monday - Sunday)
* monthday - this element represents the day of the month (1-31)
* hour - this element represents the hour time frame in which this element is set to triggered
* minute - this element represents the minute time frame in which this element is set to triggered
* second - this element represents the second time frame in which this element is set to triggered

With this rule elements you can form complex rules with your sensors. For example you can combine the boolean element AND with hour, minute and sensor to only trigger this rule when a specific sensor triggers in a specific time window.

A practical example would be a sensor at your door and a motion sensor outside the door. Every time you come home the motion sensor is triggered first and then the door sensor (since you have to walk to the door before you can open it). When this rule triggers, you can for example start the media center with the music you like.

Additionally, the rules can have a counter if you want a specific rule only trigger once every 24 hours or something like that. This is also used by me with the two motion sensors to start the media center in the living room. I only want to trigger it once a day since I only stand up and go to work once a day ;-)


Final words

The rule engine is a powerful tool when you use sensors in your home. With it you can perform complex checks before an actual event should trigger. At the moment I only use it for the described scenario above. But I think it will also have a lot of other fields where it can be handy.

alertR: dbus and xbmc notification client

Foreword and interesting links

alertR is a project of mine which I started in August 2014. It is an unified alerting system which is based on a client/server model. The main part is written in Python and is published as Free-Software. If you do not know this project yet, here are some interesting links:

* Github repository
* Github wiki for documentations
* Blog article: Introducing alertR: Open-Source alerting system (with video)
* Blog article: alertR: rule engine (with video)


Introduction and motivation

Since I published this project, a lot has changed and a lot was added. Two things I added since the last post I wanted to introduce here. First of all, the dbus notification client. alertR was used during the hack.lu 2014 CTF (Capture-The-Flag) to monitor all services that we had provided. Since a push notification would be a great asset in maintaining the CTF, I wrote a client that sends notifications on the screen via dbus. It went so great, that if a service went down we noticed it shortly after. The feedback that was given to us after the CTF was astonishing. One point of the feedback was that it was hardly noticed when a service went down because it was up again almost immediately. I can not claim that all the work in monitoring was done by alertR (for example because some authors did not write a watchdog script for it), but it did it part in it.

The second thing is the xbmc notification client. Regularly I did not hear my door bell at home when I was in the living room watching a movie or hearing music via xbmc. So I thought to myself: "I want alertR to monitor the door bell". Most solutions I found were something like replacing the door bell by a Raspberry Pi. But I did not like this solution. First, the door bell does not work if the network or Raspberry Pi is down. Second, I do not own this apartment so I do not want to make major changes in it (because I will not live in here forever). So I made a circuit (with some help of a friend of mine and Google searching) that watches the door bell by connecting it to connect to the Raspberry Pi (this is the reason why I added the ability of monitoring GPIOs via interrupt to alertR). Now if someone rings the door bell, the video/music on my xbmc is paused and a notification is displayed. With this, I do not overhear the door bell :-)


Example

Before I tell you, how I did the circuit for the door bell I want to present the notification clients to you via a short video. Please have the subtitles activated to get a description of what I am doing and what is happening.




How does it work?

The problem on how to connect your door bell to the Raspberry Pi is that the door bell works usually with AC. In our case (and the usual case from what I can tell from Google searching) the door bell is powered by 8 VAC. The AC first have to be converted to DC before we can use it. The following schematic show you how I did it:



This circuit was copied from (german link) and slightly modified. The four diodes are used to convert the AC to DC. Because the Raspberry Pi GPIO is operating on 3,3 V DC, a photo-coupler is used to disconnect both circuits from each other. The GPIO of the Raspberry Pi is configured on interrupt and therefore every change on the GPIO will be noticed.

One problem arrives with this circuit which I first realized when I had it already finished. It is very sensitive. When I plugged in a vacuum cleaner, the interrupt was triggered. As a software bypass, I added a counter which counts the number of interrupts that occur in a short time frame. Because of the bouncing when you use the door bell normally, I get more interrupts (usually over 6) than from a vacuum cleaner (usually under 4). Therefore, I fixed this with a little workaround on the software side. Since then, I never had no false positive notification triggered again.


Final words

I finished the circuits and needed software a long time ago but did not find the time nor the motivation to make the video, create the circuit image and write this article. If you are interested in this project, you should watch the github repository. There I regularly add new features and fix found bugs.