Raspberry Pi controlled mousetrap

Having had a few spare moments this holiday, I’ve been contemplating how to monitor a mousetrap or two in the attic. By doing that I wouldn’t have to go up to the cold attic in vain, but empty and reset the mousetraps only when needed. It occurred to me that since I’ve already got a Raspberry Pi in the attic for other purposes, why not check the mousetrap from that device? And so, from the combination of an almost justifiable purpose, the testing of the RPi’s GPIO capabilities, and the “this could be fun” factor, a small evening project was born.

Cjmr-SHEbvCD2GdvPOsJfWhBU3mIIdbbajHSU0TUIh4

The micro switch is positioned so that the trap arm pushes the button when set.

I’ve got a few mousetraps from Clas Ohlson that turned out to be the perfect starting point for my project. Locating a small micro switch, I fastened it to the mousetrap’s side with both glue and screws (glue alone might not be sufficient when the trap springs, and/or if it should bounce into something hard). I mounted the switch in a position so that when the mousetrap is in the loaded position, the micro switch button is pressed; when the mousetrap has sprung the button is released.

Following instructions from eLinux, getting the soldering job done was very easy. I connected the mousetrap to a soldering board with the recommended resistor setup, and connectors for the RPi was soldered onto the board as well. After some basic testing with a Python script, the mousetrap was production ready.

LED connectors from an old chassis were recycled.

The LED connectors from an old computer chassis never knew they would be recycled for pest control purposes.

I first considered the idea of configuring the mousetrap alarm as a passive Icinga check, but I opted for an active check through the NRPE server instead. This is the Python code that tests the GPIO status, running on the attic RPi:

#!/usr/bin/env python

import sys
import RPi.GPIO as GPIO

# tell the GPIO module that we want to use the 
# chip's pin numbering scheme
GPIO.setmode (GPIO.BCM)

# setup pin 24 for input
GPIO.setup (24,GPIO.IN)

myexit = 0

if GPIO.input (24):
 print "OK: Trap is set"
else:
 print "CRITICAL: Mouse in trap!"
 myexit = 2

GPIO.cleanup ()
sys.exit (myexit)

 

Then the NRPE configuration, for which the /etc/sudoers file was modified to allow the "nagios" user to run the script with sudo permissions:

command[check_mousetrap]=sudo /usr/local/bin/mousetrap.py

 

Icinga is ready, willing and able.

Finally, on the Icinga2 server, the configuration for the active check of the mousetrap's state. Icinga can be configured to handle an alarm any way you want. Given the non-urgency of emptying a mousetrap, an email alert (my default) was considered sufficient.

object Service "check_mousetrap" {
   import "generic-service"
   display_name = "Mousetrap"
   host_name = "attic_pi"
   check_command = "nrpe"
   vars.nrpe_command = "check_mousetrap"
}

 

With proper monitoring configured, now I just have to wait for the first unlucky tester to come along...

u1Eaq4h8w5x1JH62pGwejo7W6FI7CT8oBB-eFDilk60

The trap is set, rigged with cheese under the yellow lid.

Localized SSH bruteforce attempts

Lately, my honeypot has seen an upsurge in SSH bruteforce login attempts. Among quite a few attackers, one particular IP address in Italy – 79.0.43.89 – is seen more often than the others. I’m seeing login attempts from this IP on other systems as well, so this is a busy one.

What’s funny about this round is that the attackers seem to use localized name lists, as I’ve registered a lot of Norwegian-looking names. The attacker/botnet script tests SSH logins with login name and the number 1 appended to it as a password (e.g. adam / adam1), so if your password is your login name + 1 you should change it ASAP 🙂

It’s also worth noting that there are only boys’ names on the list…

This is the most recent extract:

adam
aleksander
anders
andre
andreas
arne
aslak
bendik
bjorn
christian
daniel
eirik
erik
feliks
gabriel
geir
gunnar
henrik
henry
inge
isak
jacob
jason
jo
johan
jonas
junior
knut
konrad
kristian
lars
lasse
magnus
marius
markus
martin
ole
pal
peter
philip
runar
sander
sigve
simen
sindre
snorre
stian
sveinung
thor
thorbjorn
tom

Malware detection with DNS RPZ and OSSEC

Building upon a sysadvent article I wrote at work, I’ve set up a dedicated Response Policy Zone using the freely available data files from the Malware Domain Blocklist. There are different ways to do this, but for this particular purpose I’ve imported the text file and generated a single zone file locally. BIND supports up to 32 RPZs, so in my config I’ve set this up as a separate zone, referenced as “malware”.

Below is the zone definition:

zone "malware" {
  type master;
  file "/etc/bind/db.malwaredomains";
};

 
Defining the “malware” zone as an RPZ (I have two response policy zones, one simply named rpz and now this one named malware):

options {
  response-policy { zone "rpz"; zone "malware"; };
};

 
Configure logging. The zones defined in the above response-policy {} setting fall under the rpz logging category.

logging {
  channel named-rpz {
    file "/var/log/bind/rpz.log" versions 3 size 250k;
    severity info;
  };
  category rpz {
  named-rpz;
  };
};

 
In the BIND log files, requests for domains in the malware zone are logged in the RPZ log file, suffixed with the zone reference, namely “malware”.

client 127.0.0.1#53547 (czgtgj.com): rpz QNAME Local-Data rewrite czgtgj.com via czgtgj.com.malware

 
After testing that attempts to reach malware sites are indeed logged by the DNS server, I configured OSSEC to tail BIND’s malware query log. For this I had to write a decoder and define logging rules in OSSEC, shown below. These could probably be drastically improved.

The end result is exactly as I wanted: If someone (or something) on my network is trying to reach a resource within a domain registered as affiliated with malware, OSSEC will react and alert by email, raise an alarm in your SIEM, or whatever else you want OSSEC to do.

From /var/ossec/etc/local_decoder.xml:

<decoder name="malware-dns">
  <prematch>^client </prematch>
</decoder>
<decoder name="malware-dns-lookup">
  <parent>malware-dns</parent>
  <regex offset="after_parent">^(\.+)#\d+ \((\.+)\): \.+.malware$</regex>
  <order>srcip, extra_data</order>
</decoder>

 
From /var/ossec/rules/malware_dns_rules.xml:

<group name="syslog,bind">
  <rule id="110201" level="0">
    <decoded_as>malware-dns</decoded_as>
    <description>Malware DNS group</description>
  </rule>
  
  <rule id="110202" level="8">
    <if_sid>110201</if_sid>
    <match>malware$</match>
    <description>Malware DNS lookup</description>
  </rule>
</group>

 
From /var/ossec/etc/ossec.conf:

<rules>
  [...]
  <include>malware_dns_rules.xml</include>
</rules>

 
Now, if something should reach out to a malware domain, I will get an email from my OSSEC server:

Received From: server->/var/log/bind/rpz.log
Rule: 110202 fired (level 8) -> "Malware DNS lookup"
Portion of the log(s):

client 127.0.0.1#52162 (czgtgj.com):
rpz QNAME Local-Data rewrite czgtgj.com via czgtgj.com.malware

 

Installing Bro, the network security monitor, on a Raspberry Pi

In the continuing quest to install security software on Raspberry Pis, testing their capacity to be used as small nodes that can be placed here and there on demand, the time has come for installing Bro.

The hardware/OS in question is a Raspberry Pi 2, with 1G RAM and 4 CPU cores. It’s running the Jessie version of Raspbian.

The Bro project kindly provides precompiled Debian packages, but only for the i386 and amd64 architectures. Luckily they also provide the source files and build instructions for Debian!

So I followed the instructions listed here but instead of adding the regular repo (starting with “deb“) to /etc/apt/sources.list.d/bro.list, I changed it to deb-src. After that I added the Bro repo key. Commands shown below:

# echo 'deb-src http://download.opensuse.org/repositories/network:/bro/Debian_8.0/ /' \
  >> /etc/apt/sources.list.d/bro.list
# wget http://download.opensuse.org/repositories/network:bro/Debian_8.0/Release.key \
  -O - | apt-key add -

 

Time to update the repo status and then install the dependencies required for the build:

# apt-get update
# apt-get build-dep bro

 

Depending on what you already have running on your RPi, this could be a short or long list of packages. On mine, running Raspbian Jessie, this is what had to be installed:

bison cmake cmake-data libarchive13 libbison-dev libpcap-dev libpython-dev
libpython2.7-dev libssl-dev python-dev python2.7-dev swig swig2.0

 

When that’s done, it’s time for the real job: Build Bro from source with Debian build instructions. This will take some time, on my RPi2 it took ~100 minutes. Below is the command required:

# apt-get source --compile bro

 

When that job has completed, you will find some .deb packages in your current directory. You will need to install them all (except for the dev package), like this:

# dpkg -i bro_2.4.1-0_armhf.deb bro-core_2.4.1-0_armhf.deb \
broctl_2.4.1-0_armhf.deb libbroccoli_2.4.1-0_armhf.deb

 

The Bro software will have been installed under /opt/bro, so that’s where you need to go to start using it. Other people write better Bro documentation than I do so I will leave that to them. A quickstart probably won’t hurt, so after making your local changes to /opt/bro/etc/node.conf you can start Bro as shown below. Logs will appear in /opt/bro/logs/current/.

# /opt/bro/bin/broctl 
Hint: Run the broctl "deploy" command to get started.
Welcome to BroControl 1.4
Type "help" for help.
[BroControl] > deploy
checking configurations ...
installing ...
removing old policies in /opt/bro/spool/installed-scripts-do-not-touch/site ...
removing old policies in /opt/bro/spool/installed-scripts-do-not-touch/auto ...
creating policy directories ...
installing site policies ...
generating standalone-layout.bro ...
generating local-networks.bro ...
generating broctl-config.bro ...
generating broctl-config.sh ...
updating nodes ...
stopping ...
stopping bro ...
starting ...
starting bro ...
[BroControl] > status
Getting process status ...
Getting peer status ...
Name Type Host Status Pid Peers Started
bro standalone localhost running 16514 ??? 01 Nov 22:19:57
[BroControl] >

 

Honeypot password attempts

After running a small SSH-only honeypot for a week or so, I’m a bit surprised with the complexity of some of the attempted passwords. The passwords that are most frequently attempted are quite simple, as shown in the top 5 passwords for the root account:

root
[no password]
123456
synopass
!Q@W#E

These are less obvious:

dmiwoqewq4561e3wq
get_remote_ipaddr
(yes, really!)
IF1AT9v6VaYmBkMneylI
NJglWpmSQ60etyio
sheiph7cus1ieChi
SmartGen!VDI2013
VodaHoriALeBlbe45*
WSX831102edc3831rfv
zxczxczxczcxzxcxzczxc
zxczxczxczxczcxzxczxc
zxczxczxczxczxczcxzxc

Some of these seem to be used by the same botnets, as they follow similar curves in Dshield‘s observations. The three last ones (zxc...) have not yet been listed by Dshield.

Geomapping network traffic

Did you ever wonder where your network traffic goes (and originates from)? With the SiLK suite and optionally some JavaScript map classes it’s quite easy to find out.

SiLK is a tool quite equal to Cisco‘s NetFlow, and SiLK does indeed accept NetFlow output from a router. Just like NetFlow tools, SiLK stores network traffic metadata (like “when” and “where”, but not “what”), so as opposed to capturing the complete network traffic SiLK can store a lot of information over a long time without eating too much disk space. In my setup I’ve configured my Mikrotik router to transmit traffic flow data to a Linux server running SiLK.

With GeoIP mapping, SiLK can identify the country of source and destination IP addresses. Combined with a “top 20” construct, it turned out easier than expected to create a world map like this:

Network traffic world map

For the map I’ve been using the very useful JavaScript interactive Highchart maps (Highmaps) from the Norwegian company Highsoft. To feed the map with data I wrote a small piece of code that converts the output from SiLK’s rwfilter/rwstats output to JSON, which makes the map dynamically update itself upon refresh.

World map percentage from SwitzerlandAs shown on the screenshot to the left, when hovering the mouse over each bubble the JavaScript map code will show the percentage value of the traffic associated with the different countries. When identifying traffic from unexpected sources you can use the command line based SiLK tools to drill down in order to find out what’s really going on, like in this case when I was wondering what was being transferred from Switzerland (it turned out to be some Flash movies the kids were watching). In addition to the command line tools there are also GUI and web based interfaces for querying SiLK data. The command used to find the source IP and port for the traffic originating from Switzerland (.ch) is shown below:

# rwfilter --start-date=2015/10/09 --end-date=2015/10/09 \
 --proto=0-255 --type=all --pass=stdout --scc='ch' | rwstats --top \
 --count=5 --fields=sip,sport --value=bytes
INPUT: 327 Records for 19 Bins and 39783096 Total Bytes
OUTPUT: Top 5 Bins by Bytes
          sIP|sPort|               Bytes|    %Bytes|   cumul_%|
80.239.148.37| 1935|            38839614| 97.628435| 97.628435|
  62.48.3.112|   80|              476083|  1.196697| 98.825132|
80.239.148.47| 1935|              402414|  1.011520| 99.836652|
80.239.148.44|   80|               15276|  0.038398| 99.875050|
80.239.148.45|  443|                9328|  0.023447| 99.898497|

 

There’s a few snags with my setup, but with some tweaking it gives a general idea and I think I’ve handled the corner cases. These are the knows issues – so far:

  • This setup is a NATed IPv4 network environment. In order to detect inbound traffic I have to enter my router’s outside address as the destination. This address might change now and again, breaking historical data.
  • I’m also running an IPv6 network provided by HE.net (tunnelbroker.net). My allocated IPv6 ranges are consequently registered as physically located in the US, so SiLK will register any internal-only IPv6 network traffic as based in the US, increasing that percentage.

VIsualizing firewall activity

Inspired by the efforts of a previous Redpill Linpro colleague, Espen Grøndahl, I’ve revived (or rather re-invented) his project “Fireplot”. By analyzing and filtering firewall logs, Fireplot graphs attempts to access blocked firewall ports, visualizing unexpected and unwanted activity towards my network.

Fireplot

Firewall activity visualization – click image for original size

The Y axis is logarithmic, since activity towards lower ports is often more interesting. Over 24 hours, one graph per day, TCP activity is plotted in green and UDP activity in light blue. Note the horizontal line showing SSH (TCP port 22) and telnet (TCP port 23) probes. The graph also shows a very regular probing for UDP port 7.

I’m currently parsing logs from a Mikrotik firewall/router, but since the data gathering is merely a matter of an appropriate regular expression it shouldn’t be difficult to make it graph iptables logs or other firewall-ish log data.

The Perl code is very much in beta state at the moment, so I won’t publish any code just yet. Stay tuned for updates. Meanwhile, visit Lars Strand’s inspiring article on the original project!

Streaming pcap to a dummy interface

In an earlier article, I described how to stream captured network traffic to a remote host for IDS analysis with Snort. Mikrotik units can stream captured traffic elsewhere using the TaZmen Sniffer Protocol (TZSP). tcpdump and Wireshark natively decode this protocol, but unfortunately it doesn’t seem to be supported by any other of the large amount of useful network analysis tool.

The main usage for streaming the network capture is feeding it to the Snort IDS, and for this single purpose (and since Snort can read from STDIN) piping the traffic directly from tzsp2pcap to Snort works very well. However, now and again I need to look at the network traffic without having to detach Snort from the live stream.

This was solved by making the network traffic stream available over a dummy interface with the brilliant tool tcpreplay, to which I can attach any tool that understands pcap. These are the required incantations:

/sbin/modprobe dummy
/sbin/ip link set name eth10 dev dummy0
/sbin/ifconfig eth10 192.168.42.42
/usr/bin/screen -dm -S tzsp2pcap \
bash -c "/usr/local/sbin/tzsp2pcap -f | \
/usr/bin/tcpreplay --topspeed -i eth10 -"
/etc/init.d/snort start # configured to listen to eth10

The tzsp2pcap process must be run in a screen. Involving bash is required because of the pipe. With tcpreplay --topspeed is useful to avoid delays in the feed.

At this stage, I can point any network tool at eth10 without disrupting Snort.

Mobile entertainment center

Our three kids very seldom agree which TV program or movie to watch. Allowing for less discussion when screen time is granted, I’ve set up a mobile entertainment center where each kid may watch the movie of their choice – this may be used during long drives, on trains or buses, and everywhere else where there’s low or no voltage and a need to grant the kids some screen time.

The setup is simple, using a Raspberry Pi B+ running Raspbian and a Mikrotik mAP2n. The RPi is directly connected to the mAP2n with an Ethernet cable. Both are/can be powered by microUSB voltage and cable. The RPi is also equipped with a USB WiFi adapter, configured as a WiFi client, so when the unit is within range of the wireless network at home I can update it and transfer media files to it.

DSC_1377_resized

The two units tied together with velcro. When finalizing the project I will need to find a better case.

Packages installed on the RPi

After having slimmed down the RPi by removing any package not needed, I installed minidlna. While the minidlna project was recently renamed to ReadyMedia, in Debian/Raspbian it still goes by its former name. To administer the mAP2n from the RPi I also installed mactelnet, and to make sure both units logged with useful timestamps I added an ntp server. Finally, it seems the mAP2n does not support running a DHCP server, so I left that to the RPi (isc-dhcp-server). The DHCP server listens only on eth0, to which the mAP2n is connected.

Configuring the tablets

On each kid’s tablet, I installed a DLNA controller (I chose the Ginkgo DLNA player, but I assume any kind of DLNA/UPnP controller will do). Note that the Ginkgo DLNA player is simply streaming from the media center to the device, but not rendering the content – you will need something else for that. I’m very fond of VLC for Android and it works excellent in this use case.

Setting up the mAP2n

Configuring the mAP2n as an AP/bridge, a separate SSID was configured. The mAP2n synchronizes its clock to the RPi. The interfaces wlan1 and ether2 are bridged, and the bridge holds the unit’s IP address.

TL;DR

In essence:

  1. Install Raspbian on a Raspberry Pi.
  2. Install minidlna and isc-dhcp-server.
  3. Configure wlan0, supplying SSID and credentials, for being a WiFi client.
  4. Make sure you can SSH to the RPi over the wlan0 interface. When successful, configure static IP on eth0.
  5. Connect ether2 on mAP2n to eth0 on the RPi.
  6. Configure the mAP2n as an AP/bridge. Set up SSID and credentials for the AP.
  7. Set up the tablets for DNLA streaming.
Note the USB WiFi adapter, providing wireless update of the RPi unit when within range of the home network.

Note the USB WiFi adapter, providing wireless update of the RPi unit when within range of the home network.

Configuration snippets

Configuration for RPi network /etc/network/interfaces:

auto lo
iface lo inet loopback
auto wlan0
iface wlan0 inet dhcp
    wpa-ssid YourSSID
    wpa-psk SomeSecretPassword
auto eth0
iface eth0 inet static
    address 10.1.0.1
    netmask 255.255.255.0
    network 10.1.0.0

 

DHCP server configuration file /etc/dhcp/dhcpd.conf:

ddns-update-style none;
default-lease-time 600;
max-lease-time 7200;
authoritative;
subnet 10.1.0.0 netmask 255.255.255.0 {
    range 10.1.0.100 10.1.0.200;
}

 

DHCP server configuration file /etc/default/isc-dhcp-server:

INTERFACES="eth0"

 

Minidlna configuration file /etc/minidlna/minidlna.conf:

# These are all defaults
media_dir=/var/lib/minidlna
port=8200
serial=12345678
model_number=1

 

mAP2n configuration (sensitive data removed):

[admin@YourAP] > /export
/interface bridge
add name=bridge
/interface wireless security-profiles
set [ find default=yes ] authentication-types=wpa2-psk \
    mode=dynamic-keys supplicant-identity=MikroTik \
    wpa2-pre-shared-key=SecretPassword
add authentication-types=wpa2-psk mode=dynamic-keys \
    name=YourAP supplicant-identity=YourAP \
    wpa-pre-shared-key=SecretPassword \
    wpa2-pre-shared-key=SecretPassword
/interface wireless
set [ find default-name=wlan1 ] band=2ghz-b/g/n \
    country=norway disabled=no frequency=auto \
    l2mtu=1600 mode=ap-bridge security-profile=YourAP \
    wireless-protocol=802.11
/interface bridge port
add bridge=bridge interface=ether2
add bridge=bridge interface=wlan1
/ip address
add address=10.1.0.2/24 interface=bridge network=10.1.0.0
/system clock
set time-zone-name=Europe/Oslo
/system identity
set name=YourAP
/system leds
set 3 interface=wlan1
/system ntp client
set enabled=yes primary-ntp=10.1.0.1

 

Performance

Throughput with three concurrent players showing .mkv movies (720×576 px, 25fps, H264 MPEG-4 AVC, MPEG AAC) sometimes peaks at around 22 Mb/s, and the RPi doesn’t break a sweat when serving at that speed. Obviously different formats would affect the RPi load and WiFi throughput.

Attaching a 4 x AA portable battery pack as shown below, the two units (mAP2n USB powered from the RPi) were running for more than three and a half hour, and during this period they streamed movies to one tablet for two and a half hour.

Exibel battery pack bought from Clas Ohlson.

Exibel battery pack bought from Clas Ohlson.

And for those who might ask: Yes, a Raspberry Pi could simply be equipped with two WiFi adapters, one for client access and for for AP. There are lots of different approaches to this. In my case, I had a spare mAP2n just lying there…

CRS serial console with kermit

For those still inclined to use kermit for serial console access, these are the commands for connecting to a MikroTik CRS125 with default settings:

# kermit
C-Kermit 8.0.211, 10 Apr 2004, for Linux
Copyright (C) 1985, 2004,
Trustees of Columbia University in the City of New York.
Type ? or HELP for help.
(/root/) C-Kermit>set line /dev/ttyUSB0
(/root/) C-Kermit>set speed 115200
/dev/ttyUSB0, 115200 bps
(/root/) C-Kermit>set carrier-watch off
(/root/) C-Kermit>connect