CIBot: CounterIntelligence Bot

Author: Carmelo C.
Published: May 26, 2023 (updated)
linux brute force security

A cheap (but useful, IMHO) approach at keeping your home network under control

I know shouldn’t have been but I was genuinely surprised when, upon login onto my tiny home server, I was greeted by:

There have been 400-something unauthorized accesses since your last visit.

400-something?!? Shouldn’t a siren have gone off, red lights flashing in my lab? Of course no. Not unless I’d set up something like that… who thought anyone would be interested in my minuscule “server”? No data, nothing to steal apparently. Nothing interesting but CPU cycles and RAM… which is precisely what botnets and black-hat hackers are after. Confronted with the question, “should I shut down access or do something else?” I opted for something else. I had nothing to lose, no precious data, a lot to learni on the other hand. What did I learn then? Firstly, I learned that I had done my homework right <put big smile here>. Seemingly, nobody had been able to gain access to the box. For various reasons. To help focus on details, here’s an example of the log:

<timestamp> <hostname> sshd[6690]: Invalid user miguel from 62.234.92.111 port 46484 
<timestamp> <hostname> sshd[6690]: pam_unix(sshd:auth): check pass; user unknown
<timestamp> <hostname> sshd[6690]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=62.234.92.111
<timestamp> <hostname> sshd[6690]: Failed password for invalid user miguel from 62.234.92.111 port 46484 ssh2
<timestamp> <hostname> sshd[6690]: Received disconnect from 62.234.92.111 port 46484:11: Bye Bye [preauth]
<timestamp> <hostname> sshd[6690]: Disconnected from invalid user miguel 62.234.92.111 port 46484 [preauth]
<timestamp> <hostname> unix_chkpwd[6694]: password check failed for user (root)

An initial analysis showed an interesting picture. Multiple IPs, from different geographical locations: my server wasn’t being targeted by a single hacker. Possibly, it was being probed by a botnet so that it could join the force to build up some super-DDoS-weapon perhaps. Luckily, something had gone wrong for the hackers. Here’s a non-exhaustive list:

YMMV, but there are many best practices around that may fit your use case. Hardening SSH isn’t difficult and automating it, through Ansible for instance, is easy. Still something was missing, namely my ability to detect the attempts and, possibly, do something about them. Enter Telegram Bot API. Wait, didn’t you just say that bots are bad? Well, no, not exactly, some can be bad, others can be useful. Telegram Bots are special accounts that do not require an additional phone number to set up. These accounts serve as an interface for code running somewhere on your server. Which code? Well, that’s easy, I’ve put a simple but fully operational example on GitHub: CIBot. Feel free to use it and provide comments if any. How does the good bot operate? Fundamentally, it’s composed of three parts:

cibot.py is the Python script. Its role is to parse auth.log and gather info on unauthorized access attempts. The aggregated info is passed onto a function that consumes Telegram API’s sendMessage endpoint. The overall result is that, ping!, if necessary a message will pop up on the operator’s mobile phone. cibot.json contains the configuration information. Mainly, Telegram API’s token which is the key to get access to the service. cibot.log is an auto-generated log file recording what’s been going on when the script has been triggered. The recommended way is to run the script through cron. Bonus points are granted if the Docker image is used, for a cloud-native approach.