Back to the NoNox main page

Files

nonox-1.17.jar -- the jar file containing NoNox
nonox.conf -- the configuration file
startup.sh -- an example of how to start NoNox from a script

Installation

These quick-start instructions assume NoNox will be installed in /usr/local/nonox... but that's not required.

1. Do you have Java 1.4 or later?
  java -version
if not, get it from Sun and install it. That work is well beyond the scope of this document.
 
2. Become root
   su
 
3. Create the directory /usr/local/nonox
   mkdir /usr/local/nonox
 
4. Place the files nonox-1.17.jar, nonox.conf and startup.sh there
 
5. If necessary, tweak your logrotate script:
You may have to adjust the logrotate configuration for files that NoNox is watching. If you don't, then NoNox can't figure out that the log file has been rotated out and may continue reading the old file (or nothing). That sucks. As a safety against this, Nonox closes and re-opens all the monitored files every 60 minutes, just to be sure it's reading the correct file, so that even if you don't make this change, the max time you'd be without Nonox coverage is 60 minutes every time the logs are rotated.
 
Add this to the logrotate configuration for all affected log files:
   copytruncate
 
Example logrotate file, /etc/logrotate.d/syslog:
 /var/log/messages /var/log/secure /var/log/maillog /var/log/spooler {
 sharedscripts
 copytruncate
 postrotate
 /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
 endscript
 }
 
6. Edit nonox.conf to reflect the patterns you want to match, and the actions you want to execute.
See the reference section below for guidance, as well as the provided nonox.conf file that already contains one pattern and one action.
 
7. Test NoNox
  java -cp /usr/local/nonox/nonox-1.17.jar com.challengeandresponse.nonox.NoNox -t
Try some failed logins... confirm that they're logged to the file, and that NoNox is seeing them (it'll write to standard output whenever it has a match).
 
8. Run NoNox
  /usr/local/nonox/start.sh
 
9. Monitor NoNox
  tail /var/log/nonox.log



REFERENCE

SIMPLE nonox.conf TO DETECT AND BLOCK SSHD LOGIN ATTACKS
# SSHD failure in /var/log/secure on a box that writes an IPV6 header as well as the address (::ffff:)
# Nov 27 07:31:05 localhost sshd[31585]: Failed password for invalid user adam from ::ffff:211.114.82.252 port 55889 ssh2
pattern sshd_login_fail /var/log/secure (^.*?:\d\d:\d\d)\D.*Failed password.*?from\s::ffff:(\d+?\.\d+?\.\d+?\.\d+).*
# Block an IP address if there are 4 failed sshd logins within half an hour from it
action sshd_login_fail 4 1800 /sbin/iptables -A INPUT --source %s -j DROP

Command Line Parameters

NoNox can accept some command line parameters.
Each parameter must be written by itself (e.g. -t -d -f *NOT* -tdf). The parser is dumb. My bad.

-t TEST MODE -- run normally but DO NOT execute the actions. Useful when debugging patterns to see if they're detecting the right stuff.
-d DEBUG MODE -- print lots of info about what the program is doing, including echoing all lines as they are processed
-f FULL FILE MODE -- don't tail the file, but read the entire file from the beginning and process as if those entries were just coming in. Use this to "catch up" against a log file if Nonox has been offline, or when testing your patterns against logged attack entries.
-c /path/to/config.file CONFIG FILE -- use this config file instead of the default /usr/local/nonox/nonox.conf

Configuration File

- The NoNox configuration file contains PATTERN and ACTION descriptors.
- The file is processed from top to bottom, so declare all patterns first, then declare all actions.
- For safety, the file should only be writeable by the userid under which NoNox runs (rw-r--r--)... Future versions of NoNox will test for this and won't run if the file is open to writing by others.

Patterns

Patterns are regular expressions, bound to files, that detect matching lines in those files and return information (an IP address primarily) that could be used in a defensive action (for example, blocking that IP address at a firewall). Pattern descriptors are stored in the NoNox configuration file.

The format of a pattern descriptor is:
 
     pattern pattern_name filename regex_pattern
 
Parameters are separated by white space (a blank space or a tab)
 
pattern -- the literal word "pattern" introduces a pattern
pattern_name -- you can name the pattern anything you'd like. Alphanumerics only. No spaces. Actions are bound to patterns through this name. Pattern names are not case-sensitive. More than one pattern may have the same name. If more than one pattern with the same name matches an event, the counter will be incremented once for each pattern's match... so take care not to have multiple patterns matching against the same event occurrences, or the counter will run up faster than you intended.
filename -- the full absolute path to the file to watch for this pattern
regex pattern -- the regular expression that will match the pattern
 
regex_pattern is a Java compatible regular expression with these restrictions:
The pattern may return zero, one, or two GROUPS:
First group: The date in standard logfile date/timestamp, e.g.: Aug 15 11:03:56
Second group: The IP address to hand to the action(s)
If no IP address is provided (i.e. there is no Match.group(2)), then the text constant "NONE" is used instead. Careful! if your action needs an IP address, be sure your pattern always returns one.
 
Example patterns (preceded by comment-lines that begin with "#"):
# Detect dictionary attacks against sshd by monitoring /var/log/secure
# SSHD failure in /var/log/secure on a box that writes an IPV6 header as well as the address (::ffff:)
# Nov 27 07:31:05 localhost sshd[31585]: Failed password for invalid user adam from ::ffff:211.114.82.252 port 55889 ssh2
pattern sshd_login_fail /var/log/secure (^.*?:\d\d:\d\d)\D.*Failed password.*?from\s::ffff:(\d+?\.\d+?\.\d+?\.\d+).*
 
# Detect dictionary attacks against sshd by monitoring /var/log/messages
# Nov 27 10:01:10 localhost sshd(pam_unix)[8822]: authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.123.103 user=bert
pattern sshd_login_fail /var/log/messages (^.*?:\d\d:\d\d)\D.*authentication failure.*?rhost=(.*\d).*

Actions

Actions connect patterns with the conditions for triggering commands, and also provide the commands to run when they're triggered. Action descriptors are stored in the NoNox configuration file. The file is processed from top to bottom, so declare all patterns first, then declare all actions.

NoNox actions are one-shots. Once an action is triggered for an (action,sourceIP) pair, it won't trigger again for that pair -- otherwise, continued attacks would result in multiple executions of the same command, for example, sending a flood of notices to an operator about an event once the threshold has been reached and more instances of the same event occur.

The format of an action descriptor is:
 
     action pattern_name threshold_count timelimit_seconds command
 
Parameters are separated by white space (a blank space or a tab)
 
action -- the literal word "action" introduces an action
pattern_name -- the pattern_name to count occurrences of, matching an already-declared pattern as described above.
threshold_count -- the number of times a pattern should match within timelimit_seconds in order to trigger execution of the command associated with this action.
timelimit_seconds -- the maximum number of seconds between the oldest and most recent threshold_count pattern matches, in order to execute the command, for example, "4 matches in 30 minutes"
command -- the command to execute when threshold_count matches occur within timelimit_seconds seconds.
command may contain embedded spaces. The config file reader will capture everything from the start of command to the end of the line.
 
In the command, the token %s is a placeholder for the IP address that triggered the action, provided one was captured as match group 2 (see Patterns above).

A Note About Iptables

I use iptables to respond to in-progress password scans by dropping packets from the attacking host. I created a chain called "loganddrop" that logs any further packets received from that host (I was curious about how many more attempts they would make) and then drops the packet.
 
To create a "loganddrop" chain in iptables, that LOGS a packet and the DROPs it (doh), do this:
  /sbin/iptables -N loganddrop
  /sbin/iptables -A loganddrop -j LOG --log-level info
  /sbin/iptables -A loganddrop -j DROP
  # this line saves the current iptables state (including the new chain) to make it persist after restart
  /sbin/iptables-save
 
If you just want to DROP the packets and not log new activity from blocked sources, don't bother with the above. Just make the ACTION end with "-j DROP" (note all upper case) rather than "-j loganddrop"
 
Example action (preceded by a one-line comment):
# Block an IP address if there are 4 failed sshd logins within half an hour from it
action sshd_login_fail 4 1800 /sbin/iptables -A INPUT --source %s -j loganddrop

NoNox Memory Usage and Actions

NoNox creates one object per (action,sourceIP) and keeps these active until either they are triggered, or all records have completely aged out. A reaper thread runs occasionally to purge objects referencing events that are too old to trigger any actions.

When an action is triggered, the object for that (action,sourceIP) is *not* purged. It is kept in memory indefinitely, to support the one-shot-per-trigger rule. If you have a massive number of actions firing, this could consume a nontrivial amount of memory. But on most ordinary systems, this isn't going to be an issue. The objects are small, consisting of one Long object per discrete event (so if your trigger is "10" events, there will be at most 10 Longs stored for a given source), and a few management fields... nothing big.

For version 1.17, this was the data structure:
  Stack timestamps; (Longs, 16 bytes per entry)
  int howmany; (4 bytes)
  long maxAgeMsec; (8 bytes)
  boolean fired; (1 byte)

So, considering that the counter object itself, and the Stack inside it, each have overhead of 8 bytes, memory usage is on the order of 8+8+8+4+1+(16 * threshold_count), or 29 + (16 * threshold_count) bytes. So, if you've got an action that triggers after 10 pattern matches from a single IP address, that action's counter will use about 189 bytes for each IP address that triggers it. So again, in case it wasn't clear, the counters for sources that trigger an action are retained as long as NoNox is running. The counters for sources that disappear without triggering an action are gradually purged.

Saving/Recovering State Between Invocations

NoNox does NOT save or recover state between invocations... so when you stop NoNox and restart it, all records of previously triggered actions are cleared and they will in fact be triggered again if the pattern matching rules are tripped again. Not too huge a deal in some cases (for example, if NoNox has previously created a firewall rule to block a host, then that host isn't going to get through later and trigger NoNox again) but something to be aware of. The importance or irrelevance of this "feature" depends on the commands you're executing. As Frosty the Snowman once said upon donning a magic hat, "Hap-py Birth-day"

Samples of log output

startup
Sun Nov 27 12:22:29 EST 2005 NoNox version 1.17 of 2005-11-26 started. Read loop will pause:5 msec between read cycles (hardcoded, sorry!)
Sun Nov 27 12:22:29 EST 2005 configuration parameters: testMode=false; tailMode=true; debugMode=false
Sun Nov 27 12:22:29 EST 2005 Using config file:/usr/local/nonox/nonox.conf
Sun Nov 27 12:22:30 EST 2005 Opening file:/var/log/secure
Sun Nov 27 12:22:30 EST 2005 In tail mode. Skipping to EOF of:/var/log/secure size:6522
Sun Nov 27 12:22:30 EST 2005 loaded pattern:Pattern:sshd_login_fail bound to file:/var/log/secure with regexp:(^.*?:\d\d: \d\d)\D.*Failed password.*?from\s::ffff:(\d+?\.\d+?\.\d+?\.\d+).*
Sun Nov 27 12:22:35 EST 2005 loaded action:Action bound to pattern:sshd_login_fail threshold:4 time limit in seconds:1800 Command:/sbin/iptables -A INPUT --source %s -j DROP
Sun Nov 27 12:22:35 EST 2005 Files will be closed and reopened every 3600000 msec (60 minutes)
Sun Nov 27 12:22:35 EST 2005 Starting reaper thread
Sun Nov 27 12:22:35 EST 2005 Reaper thread running. Reaper will run every 1800000 msec (30 minutes)
Sun Nov 27 12:22:35 EST 2005 Starting monitor loop
 
periodic entries, while it's running
Mon Nov 28 06:22:31 EST 2005 Opening file:/var/log/messages
Mon Nov 28 06:22:31 EST 2005 In tail mode. Skipping to EOF of:/var/log/messages size:11283
Mon Nov 28 06:22:36 EST 2005 Reaper thread running. Reaper will run every 1800000 msec (30 minutes)
 
attack in progress, leading to triggering an action
Mon Nov 28 06:46:23 EST 2005 MATCH pattern:sshd_login_fail count:1 action:0 address:210.245.189.235 source:Nov 28 06:46:23 localhost sshd[22158]: Failed password for root from ::ffff:210.245.189.235 port 53435 ssh2
Mon Nov 28 06:46:31 EST 2005 MATCH pattern:sshd_login_fail count:2 action:0 address:210.245.189.235 source:Nov 28 06:46:31 localhost sshd[22171]: Failed password for root from ::ffff:210.245.189.235 port 53586 ssh2
Mon Nov 28 06:46:40 EST 2005 MATCH pattern:sshd_login_fail count:3 action:0 address:210.245.189.235 source:Nov 28 06:46:40 localhost sshd[22179]: Failed password for root from ::ffff:210.245.189.235 port 53703 ssh2
Mon Nov 28 06:46:50 EST 2005 MATCH pattern:sshd_login_fail count:4 action:0 address:210.245.189.235 source:Nov 28 06:46:50 localhost sshd[22187]: Failed password for root from ::ffff:210.245.189.235 port 53835 ssh2
oldest timestamp: 1133178383645 msec 1133178383 seconds 18886306 minutes
AGE of oldest timestamp in seconds:27
Current system time: 1133178410673
Mon Nov 28 06:46:50 EST 2005 ACTION running command:/sbin/iptables -A INPUT --source 210.245.189.235 -j DROP
Mon Nov 28 06:46:51 EST 2005 Command executed. Exit value:0

Contact Information

The author of NoNox is Jim Youll, jim@cr-labs.com
Challenge/Response, LLC creates security and privacy software to support safe, private e-ecommerce transactions and to detect and reduce online fraud.