rascals - find and blacklist rascally twerps
rascals --exclude=231.58.192.122 --period=1h --limit=30 --expire=1d auth.log
rascals reads auth.log looking for ssh dictionary attackers (``rascals'') and adds the offending host to a blacklist. This list may be used by the ``tcp wrappers'' subsystem (via /etc/hosts.allow) to block or tarpit attacking hosts.
rascals automatically removes older entries in the rascals blacklist each time it runs, based on the expiration date when the entries were added.
rascals is designed to run with no maintenance: install and forget.
rascals may be run from the command-line as root, or from a root crontab (see INSTALLATION and EXAMPLES, especially the Author's usage below).
Nearly all of the default behavior of rascals can be changed (see OPTIONS below).
To make use of the rascals blacklist using tcp wrappers, add the following line to the top of your /etc/hosts.allow file:
sshd : /var/log/rascals : deny
See EXAMPLES below for some other interesting /etc/hosts.allow options.
For the impatient, here is the checklist of things that must be done for rascals to maintain its blacklist automatically:
chmod 0755 /usr/local/sbin/rascals
sshd : /var/log/rascals : deny
*/30 * * * * root /usr/local/sbin/rascals /var/log/auth.log
The author runs rascals every 2 minutes, with a period of 2m so no evil-doers miss an opportunity to be trounced:
*/2 * * * * root /usr/local/sbin/rascals --period=2m /var/log/auth.log
That's it--no fuss, no muss.
In a nutshell, rascals works like this:
Rascals goes through the last 5 minutes (``period'') of the given log looking for 5 entries (``limit'') matching sshd (``service'') requests for ``Illegal user'' (``pattern'') and adds the offending IP to the rascals log (``rascals'') for a period of 2 hours (``expire'').
All options are configurable: you can change the period (how much of the log to examine), the limit (how many times an offense must occur before they're blacklisted), the service (defaults to sshd, but could be any service, such as 'sm-mta' or 'ipop3d'), the pattern (what an offense looks like in the log), and the expiration (how long the offending IP will be on the blacklist).
This section describes in some detail your options.
If 'new' is specified, new rascals added to the blacklist will be returned (if no output appears, no new entries were added to the blacklist at this time).
If 'old' is specified, expiring rascals will be listed (if no output appears, no expiring rascals were removed from the blacklist at this time).
'all' prints both new additions and expirations.
If no report type is specified, rascals runs silently.
These options determine how rascals finds hosts that are attacking your server.
Please be aware that rascals only understands log files in standard syslog format:
Jan 10 12:02:38 myhostname someservice[8888]: message from someservice
This includes auth.log, maillog, messages, and other common logs written to by syslog.
rascals --exclude=123.45.67.89 --exclude=132.41.33.12
The exclude option is a safety valve: put your own IP address here, as well as any addresses from valid clients who might regularly mistype their own password.
Default: (empty)
Only exact string matches will work here. To match multiple services you'll need to run rascals multiple times. This may change in a future release.
Default: sshd
Default: 5m
Default: 5
Default: '^(?:Failed password for root|(?:Invalid|Illegal) user \S+) from (\S+)'
A pattern that might work for some ipop3d dictionary attacks:
'Login failed .*\[(\S+)\]$'
See also <Log Message Patterns> in the CAVEATS section below for more pattern help.
These options determine how rascals behaves once it has found rascally hosts.
Default: 2h
Default: /var/log/rascals
Times specified in the period and expire options follow this format:
(integer)(unit)
'integer' may be any positive whole number (e.g., 1, 2, 3, 4, etc.).
'unit' may be one of the following:
For example, to specify an expiration of 2 weeks:
--expire=14d
To specify an expiration of 8 minutes:
--expire=8m
To find entries in the past 12 hours:
--period=12h
Here are some examples of how to run rascals. Further below are examples on how to configure /etc/hosts.allow, and a sample crontab entry.
Basic usage:
rascals /var/log/auth.log
This will scan /var/log/auth.log for failed sshd attempts. When it find 5 entries in the last 5 minutes, it will add the attacking host to /var/log/rascals for 2 hours (these are all defaults).
Author's usage:
Here is how your author uses rascals on one of his servers:
*/5 * * * * root rascals --exclude=12.34.56.78 --report=all /var/log/auth.log
with the following entry in /etc/hosts.allow:
ALL : /var/log/rascals : spawn /bin/sleep 60 ALL : ALL : allow
We scan every 5 minutes for attackers. Some attacks can do several login attempts per second, but for this server 5 minutes is often enough. I add my own IP address via the --exclude option to make sure I don't lock myself out of the server.
On another server, the author runs rascals every two minutes, and sets the --period to '2m' also so there are no gaps in the log processing (no chance for an attacker to guess the scanning pattern and bypass detection).
The --report option will cause rascals to write output, which in turn causes cron to send an email, effectively notifying the system administrator that this server is under attack.
Processing compressed logs:
If your auth.log rotates frequently, you can use zcat and a pipe to rascals:
zcat -f /var/log/auth.log.[012].gz /var/log/auth.log | rascals
which will process these logs:
/var/log/auth.log
/var/log/auth.log.0.gz
/var/log/auth.log.1.gz
/var/log/auth.log.2.gz
You might want to try some of these interesting options in your /etc/hosts.allow file. Here's how to just block sshd attacks using rascals:
sshd : /var/log/rascals : deny
Here's one way to make a tarpit that allows a login attempt but only after waiting 30 seconds:
sshd : /var/log/rascals : spawn /bin/sleep 30
Here's another tarpit, but which closes the connection after the tarpit:
sshd : /var/log/rascals : spawn /bin/sleep 30 : deny
You can replace 'sshd' with any service to block that service, or try 'ALL' to disallow any connection attempts to any service that tcp wrappers protects.
You can easily automate the maintenance of rascals' log file using cron. An entry like this in your /etc/crontab file will check for attacks every half-hour:
*/30 * * * * root /usr/local/sbin/rascals /var/log/auth.log --report=all
Q. The attacks keep coming! What can I do?
A. You probably need a stronger disincentive. Try:
sshd : /var/log/rascals : spawn /bin/sleep 600
The trade-off here is that I'm assuming you have plenty of sockets to handle the incoming connection attempts. You may find that an attack with many simultaneous connections from the attacking IP can quickly overwhelm you. If that's the case, just start closing them down immediately:
sshd : /var/log/rascals : deny
Yes, you'll still get connection attempts, but this will shut them down fast enough that the following will likely occur:
1) you'll have enough sockets for legitimate connections
2) the attacker will probably give up after a while anyway--you
have no control over the attackers response.
Q. I watch my logs and notice that an attack will go on for several minutes before rascals detects it and shuts it down. How can I make rascals scan more frequently?
A. Change the cron entry to scan more frequently. rascals is light enough to run every minute, even on very large logs:
* * * * * root /usr/local/sbin/rascals /var/log/auth.log
(Note that this is BSD-Vixie /etc/crontab syntax, with a username specified in the 6th field.)
rascals will likely do what you want without any command-line options set or changes. However, due to the myriad configurations and services running on various flavors of Unix out there, these defaults may not all work for you.
For example, your sshd agent may register itself with syslog as 'sshd2' or some other such name, in which case you'll need to specify the service option to override the default. Luckily, rascals is highly configurable.
Below are some of the things you'll want to consider if you need to set any command-line options for one reason or another.
rascals creates a temporary file to which the new rascals are written and the old rascals are appended. This temporary file is based on the --rascals option (default: /var/log/rascals).
This file should be written to a safe location (i.e., a location where normal users do not have write privileges) as should all log files.
This temporary file is renamed when it is complete, and overwrites the old rascals file. A race condition exists when multiple instances of rascals are running, so try not to do that.
If your auth.log is rotated between rascals runs, you won't see those last entries in the rotated log, unless you figure out some way to include those compressed logs. You might try this:
zcat -f /var/log/auth.log.0.gz /var/log/auth.log | rascals
which will make sure you always have the last auth.log rotation period being processed.
The expiration time (set via --expire) will only be precise when it is a multiple of the frequency of how often you run rascals.
That is, if you run rascals every hour, and your expiration is set to 90 minutes, the expired rascals will be removed on the next rascals run after the 90 minutes has gone by, which could add half an hour to the actual expiration time.
It's best to make the expire time a multiple of the run frequency (e.g., if rascals runs every half hour, set the expire time to a multiple of a half hour: 30m, 60m, 90m, 120m, etc.) if you want to make sure that the blacklist expires precisely (more or less) when you intend it to.
Most people run rascals at a very short frequency (e.g., 2-5 minutes) in which case the worst expiration lag would be 2-5 minutes, which probably isn't very important anyway.
The author is not aware of a size limit on the blacklist, but assumes that tcp wrapper performace would begin to degrade after a few hundred hosts. Setting a reasonable expiration time will ensure that your blacklist doesn't become too large for too long.
If the /etc/hosts.allow doesn't seem to be blocking, you might want to make sure it's actually installed (beyond the scope of this document). Try adding yourself to it:
ALL : my.hostname.tld : deny
Always keep a shell open so you can remove this entry!
Always keep a shell open so you can remove this entry!
Always keep a shell open so you can remove this entry!
(What I tell you three times is true).
If this works, make sure that your rascals entry is above the first 'ALL : ALL : allow' line in /etc/hosts.allow. Remember: tcp wrappers uses a simple 'first-match' algorithm to decide whether to allow or deny a host.
If you specify a pattern, it must have at least one ``capture'', and the first capture must capture the hostname or IP address of the rascal. For example, to look for dictionary attacks via ftp, you might do something like this:
rascal --service=proftpd --pattern='USER \S+: no such user found from (\S+)'
If your scanning frequency is more often than the period specification you have set, you will possibly get duplicate entries from one scan to the next. To illustrate:
+------ start of auth.log |1 |2 |3 <--- scanning starts here, based on 'period' setting |4 |5 |6 |7 |8 |9 +------ end of log
If we scan again before 'period' time has elapsed, this will occur:
+------ start of auth.log |1 |2 |3 |4 |5 |6 <--- scanning starts here, based on 'period' setting |7 * duplicated |8 * duplicated |9 * duplicated |10 |11 |12 |13 |14 +------ end of log
This isn't necessarily bad, but is something to be aware of.
You can lock yourself out of your server! Don't do this. And don't call me if you do--I can't help you. Messing with /etc/hosts.allow can be tricky business if you don't know what you're doing (so read the manpages listed below and experiement, but always leave a shell open to your server).
The following brief list are good practices for newbies (and everyone else):
You can run rascals every minute of every day if you are under serious attack every minute of every day or just can't stomach the thought of someone knocking on your door all of the time. rascals runs very fast (just over a second to process an 18M logfile on my Powerbook, about 2 seconds for a 20M logfile on a dual proc Pentium 4).
Scott Wiersdorf, <scott@perlcode.org>
Copyright (c) 2005 Scott Wiersdorf. All rights reserved.
rascals is released under the the same terms as Perl itself.
hosts_options(5), hosts_access(5), /etc/hosts.allow