And here are some shots.
PiAlert in action
Turned off device, front view
Disabled device, side view
I must say that what I got, at best, can be called an alpha version of the device. I shared theproject code and model for 3D-printing the case in the public domain in the hope that if someone is interested in my project, they will help me improve it for the common good.
Project overview
After a recent incident with one of my servers, I realized that I really like to rummage through the logs and figure out what happened. I usually use the following commands:
tail -n 80 -f /var/log/apache2/error.log
tail -n 80 -f /var/log/apache2/access.log
tail -n 80 -f /var/log/auth.log
It is interesting to see which pages the bots are trying to access from nowhere, or which accounts they are trying to log into via SSH. It also looks like hacker movies. Then I thought I could create something that looks much more attractive than a terminal window. At this moment, the project, which I am talking about here, was born.
The results of monitoring login attempts have changed recently. This happened after I implemented a stricter login procedure. Namely, the number of attempts to log in to the system dropped dramatically. This became apparent after the server monitoring system I created ran for 24 hours. Below I will talk about this.
This material is divided into three sections. The first is about hardware, the second is about setting up servers, and the third is about programs for the Raspberry Pi.
Hardware
My device is assembled from the following components:
- Raspberry Pi Zero W board .
- Pimoroni Blinkt LED panel ! ...
- Cheap 7-segment 4-digit display (white) from AliExpress.
Here is the connection diagram.
Diagram of connecting components to the board
To connect the Blinkt LED panel to the Raspberry Pi! DuPont connecting wires were used. On the one hand, I cut them and soldered them to the corresponding pins of the 40-pin GPIO port of the panel. I could not connect it directly to the board as I still needed to connect a display to it.
It took me a long time to get the panel to work. At first I thought that my instance was suffering from bad connections in the connector. And to figure this out, I had to go through trial and error, spend much more time than I would like to spend on it. After I reached out to Pimoroni via Twitter, it turned out that early versions of Blinkt! use pin # 2 for 5V, not pin # 4 as shown on pinout.xyz . I, however, until I figured it out, in a hurry ordered another Blinkt! LED panel in case mine was not working. And now, after I managed to launch the first one, I need to think about a new project in which I could use the second one.
I placed all these components in a case that I designed in Tinkercad... The body was printed on my Ender 3 Pro 3D printer. I got the case, but I still could not think of how to make its parts so that they would either fit tightly into each other, or would be fastened to each other with latches. As a result, I formed a pair of posts on one of the body parts, designed for M5 screws, which I used to assemble the finished device. These posts are placed along the edges so that there is enough room in the case for the Raspberry Pi.
To print the case, I used PLA from an unknown manufacturer (printing temperature - 217 ° C, fill rate - 10%). I applied the usual settings are picked up after watching various videos on the YouTube .
Results of several attempts to print a corpus
Assembling the case
I only managed to create a decent looking front panel on my ninth try. Every time I typed it, it turned out that something needed to be moved slightly, or that somewhere, albeit a little, something needed to be corrected. I only used Tinkercad a few times while editing the model, and I had to start working on it almost from the beginning. I wanted to fix the Blinkt LED bar! using snaps, but after a few unsuccessful attempts gave up this idea and solved the issue with a glue gun (I love this thing!). As a result, I fixed both the display and the Raspberry Pi board with it. Finishing work on the case, I was solving the issue of placing the board in it. At first, I did not fix the board in the case in any way, but because of this, connecting a USB cable to it turned into a real adventure.In the final version of the case (if at all we can say that some of its versions will be “final”) I would like to get rid of the screws, from the holes for them and from the posts inside the case, and find a way to connect the parts of the case, for example, with using latches. If someone wants to take part in the work on the corpus and change everything in it - you are welcome! And I also want to cover the front panel of the case with something like translucent glass or a piece of acrylic. This would give the device a finished look, hiding too "technical" details.If someone wants to take part in the work on the corpus and change everything in it - you are welcome! And I also want to close the front panel of the case with something like translucent glass or a piece of acrylic. This would give the device a finished look, hiding too "technical" details.If someone wants to take part in the work on the corpus and change everything in it - you are welcome! And I also want to close the front panel of the case with something like translucent glass or a piece of acrylic. This would give the device a finished look, hiding too "technical" details.
The Raspberry Pi board on which this project is based has already been used in another project that needed a 40-pin GPIO port to be mounted on the back of the board. It turned out to be a plus. The board is firmly fixed in the case, I probably will not use it in other projects. Therefore, I bent some of the pins in order to better place everything in the case.
Everything fit!
In the end, I had another idea, which is that I should equip the device with at least a couple of buttons. Maybe not even bring them out, but simply hide them somewhere in the case. One is needed to switch between different types of fixed attacks and to display their number. And the second should, with a short press, turn off the display, and with a long press, gently shut down the Raspberry Pi. If I need to, I can always connect to my device via SSH, and if I really need it, I can create a URL route that invokes the command
sudo halt
.
Server configuration
When, after the aforementioned incident, I was strengthening the protection of servers and setting up monitoring, I checked that the fail2ban program was installed on them . This is wonderful FOSS-project. Fail2ban monitors the logs on the server and records information about something that, under normal conditions, shouldn't happen, like multiple failed SSH login attempts. Next, the program bans the IP address from which suspicious requests originate, doing this in the event that it is a potentially serious problem, or if certain events are repeated within a predetermined period of time. By default, fail2ban monitors SSH traffic, but the program can also be configured to keep an eye on something else, such as the number of 404 errors or the number of unsuccessful attempts to log into the admin panel of a WordPress project.
Fail2ban allows you to create your own actions that are called when various events occur. It turned out to be more complicated than doing something like a simple curl request, so I ended up turning to GitHub for help. No matter what I did, I couldn't get the system to work the way it should. In order to make it easier for you to solve a similar problem, I will tell you about how I, in the end, managed to set everything up. Namely, we are talking about using fail2ban on a Debian based server.
Let's create a file
jail.local
and add the following to it:
[sshd]
enabled = true
port = ssh
banaction = pinotifyred[myhost="SCRIPTHOSTSERVER"]
Here
SCRIPTHOSTSERVER
you need to replace it with a suitable URL (for example - on dev.testing:8080
) Note that there is no protocol information at the beginning of this URL, there is no path at the end, and the address must not end with a slash.
As a result, it turns out that we will have the usual actions related to SSHD, the program will continue to ban suspicious IP addresses, but we will also be able to create additional actions. Unfortunately, you cannot simply describe the command that will be executed here (this was my problem). Instead, you need to tell the system exactly what action to take. The action is called from a file stored in a folder
action.d
. The names of the .conf files in this folder correspond to the names of the actions (in our case, this pinotifyred.conf
). This is what these files look like:
[Definition]
# get- "http://example.com/red"
actionban = curl --fail "http://<my-host>/red" >> /dev/null
[Init]
# jail- :
my-host = SCRIPTHOSTSERVER
Here, again, you need to change
SCRIPTHOSTSERVER
to a suitable URL (sort of dev.testing:8080
), adhering to the same rules that were discussed above in the file description jail.local
.
The code calls the action and changes the variable
my-host
. I couldn't get it all to work without such a variable.
This code executes the required command. It declares some variables that are needed for fail2ban to work. In addition, the way this is configured means that we have the ability to send curl or wget requests with different parameters. Among these parameters, for example, there may be information about which IP was banned, and when exactly it happened. Therefore, if you want to receive more detailed information about attacks than, as in my case, only data on their number, you can use this. Namely, to do this, you can place a
action.d
file with the following content in the folder :
[Definition]
# get- "http://example.com/ban.php?jail=sshd&ip=192.0.2.100":
actionban = curl -G --data-urlencode "jail=%(name)s" --data-urlencode "ip=" --fail "http://<my-host>/ban.php"
[Init]
# jail- :
my-host = SCRIPTHOSTSERVER
I would like to point out that there is probably a bug here, since the action is called twice - when the IP is blocked and when it is unblocked. I plan to tackle this later, perhaps this leads to a doubling of the number of attacks.
Raspberry Pi software
To be honest, my code is a complete mess. It was written in Python 3 by a person (me) who does not know Python, but is able to search for answers to questions on the Internet. This, coupled with general programming knowledge, allowed me to write a program in Python.
I will not talk here about preparing the Raspberry Pi for SSH work, since many people have already talked about this . The code in question is hosted on GitHub . It is represented by a couple of files. The first file is this
pialert.py
, it starts at system boot. The second file, tm1637.py
is a library that I took from this material from the RaspberryTips site .
My Python program acts as an HTTP server (I know it's not for production, but it's still a simple home project) listening for all requests. This is a single threaded program, so if there are a lot of requests, it will most likely fail. The program waits for the URL to arrive, and if it is registered with it, it performs the action. The action is to turn on the LED on Blinkt !, in the Larson Scanner style , and increase the counter. The choice of LED color depends on the URL.
I am using 4 colors:
- Blue - Indicates an attack was made on my WordPress site .
- Red - SSH attack on server A.
- Purple - SSH attack on server B.
- Green - URL attack on server C.
Perhaps, over time, I will expand the set of attacks recorded by the device. But even what is now allows you to keep abreast of events without connecting to the servers.
In my code, errors are not handled, and possible counter overflows are not monitored. The program, among other things, shows me that even my home network is constantly being attacked in the form of requests for special URLs. The attackers try to gain access to the network through any vulnerability they discover (this throws exceptions, but this does not stop the program).
One of the last tasks I had to solve during the work on the project was setting up the Raspberry Pi. Namely, I needed the board to launch the script immediately after loading, and then everything would just work. This problem is solved by editing the file
/etc/rc.loca
l. I used the vi editor to add a command to the file that is usually used to start programs:
python3 /home/pi/PiAlert/pialert.py &
After that, there was only one problem left for me to solve. It was to provide uninterrupted access for my VPS to the Raspberry Pi, which was on the home network, behind a firewall, and had a dynamic IP address. I could use Dynamic DNS, or any of the myriad of services out there. However, someone from the selfhosted Reddit community created a free service freemyip.com, which solves exactly the problem that I needed to solve. And he solves it well. The service is not yet very popular, and I am sure that it will not remain the way it is for a long time due to its free cost. But given how easy it is to work with it, I would gladly pay for it. I found another interesting service in the same community, sliceport.com . I'll try it someday too.
Outcome
The
PiAlert Demonstration is a device that cannot be compared to some of the coolest hacking thing in the movies. Its purpose is to remind you that every day thousands of bots are trying to access something that they shouldn't have access to. The device I created simply transfers information about such attempts to the real world, reminding us of them. It also came out pretty cute.
What other good things can I say about PiAlert? The device looks neutral and is very flexible. If I decide that I no longer need it as it stands, I can rewrite the code and turn it into a clock. Or I can turn it into a counter of visits to the pages of my site. In fact - there are tons of options for using RGB LEDs and a 4-digit display. In addition, my device turned out to be compact. It stands in front of me on my desk when I write code and reminds me that there are people in the world who are doing bad things. The PiAlert requires very little power to operate, so it can run on batteries. It can be placed anywhere in the house as long as it can connect to a WiFi network. There it will simply do its job.And if I need another network, it will be enough to connect to the Raspberry Pi via SSH or create a new file
wpa_supplicant.conf
in /boot
.
As a result, I want to note that my code, of course, does not look very good. It can and should be refactored. If I ever learn Python, I’ll do it right there. The case can also be improved and I, again, if I master some kind of 3D modeling program, I will work on the case. But, if you do not take this into account, I can say that I am happy with what I did.
Are you planning to make a PiAlert-like device?