[syslog-ng] Firewalling with syslog-ng, a working prototype

Valentijn Sessink valentyn at blub.net
Sun Feb 20 23:06:54 CET 2011


Hi list,

For a week or so, I'm gathering the building blocks for a sort of 
low-tech intrusion detection/prevention system.

My "itch": having a system that acts "real time" on the log messages 
that various daemons produce; having it low profile; easy to get it to 
act (i.e. no scripts that call scripts that call other scripts). For 
example, if sshd says "invalid user", I'd like the firewall to act on 
this, with as little steps in between as possible. Luckily, syslog-ng is 
able to find patterns all by itself, so I'm able to "skip the middle 
man", i.e. I can use syslog-ng directly on the firewalling rules. And 
what is better: I'm not even using the program() call!

I'm currently running such a system in pre-production and I'm delighted. 
It's really easy to build. It works like a charm. Here's how:

0) Install syslog-ng.

1) To get started, get the sshd pattern from the Balabit git web 
frontend: 
http://git.balabit.hu/?p=bazsi/syslog-ng-patterndb.git;a=blob;f=access/sshd.pdb;hb=HEAD 
and put it in /etc/syslog-ng/patterndb.d/, run
pdbtool merge -D . -p /var/lib/syslog-ng/patterndb.xml

2) Setup your syslog-ng.conf file. Add, in the appropriate sections:

# a destination; we have a dual destination here, a file to see the
# blocked hosts, and an iptables-destination in /proc to block them.
destination d_syslogblock { file("/proc/net/xt_recent/syslogblock"
    template("+${usracct.device}\n")); file("/var/log/syslogblock"); };
# a parser for the pattern-DB we made in step 1
parser pattern_db {
    db_parser( file("/var/lib/syslog-ng/patterndb.xml")); };
# a filter to filter the parser results
filter f_syslogblock { tags("secevt") and match("REJECT"
    value("secevt.verdict")); };
# and finally, the log itself:
log { source(s_src); parser(pattern_db); filter(f_syslogblock); 
destination(d_syslogblock); };

3) Now set up your firewalling. A minimalistic firewall would look like:

ip6tables -N block
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A INPUT -m state --state INVALID -j DROP
ip6tables -A INPUT -m recent --rcheck --name block \
    --seconds 3600 -j DROP   # see note (1) below
ip6tables -A INPUT -m recent --rcheck --name syslogblock \
    --seconds 900 --hitcount 15 -j block
ip6tables -A block -m recent --rcheck --name block --set

4) Repeat step 3, but with "iptables" instead of "ip6tables". (I used 
ip6tables on purpose, because it's time you get ready for IPv6 if you 
aren't).

Ready. Not too hard, isn't it? It works as follows. syslog-ng will put 
the IP-address of any wrong password or username into the 
/proc/net/xt_recent/syslogblock file, with a "+" in front of the 
address. This is the iptables way of telling the "recent" module it 
should add a certain address.

Now the IPtables rules tell, that if someone is seen in this 
"syslogblock" list more that 15 times within 15 minutes, then (s)he will 
be added to the "block" list. And if someone is in the "block" list, 
(s)he will be blocked for an hour.

Note (1): if you replace the "--rcheck" here with an "--update" 
statement, the block will last even longer: "--rcheck" says: were you 
blocked less than an hour ago? Then we can't let you in. While 
"--update" says: were you blocked less than an hour ago, but you're here 
*again*? We'll block you for *another* hour, starting now. So the latter 
means that you actually need to be quiet for 60 minutes to be able to 
log in again.

There is only one caveat in this whole setup: if you (or syslog-ng) 
inadvertedly send garbage to the /proc/net/xt_recent/syslogblock file, 
then this file will be closed. Syslog-ng will reopen it after the 
"reopen" timeout, so your message will probably come through; but should 
something change in the working of syslog-ng, like should syslog-ng try 
to *re-send* such a broken message, then this will, effectively, block 
the rest of the blocking messages. (I don't think this will happen, 
because "fprintf" is not a reliable transport, so to say, but you'll 
never know).

I'll be implementing this solution for a couple of other servers in the 
next weeks or so, and I'll report if there is more to say about it.

Oh, BTW: I think that these two lines:
ip6tables -A INPUT -m recent --rcheck --name syslogblock --seconds 900 
--hitcount 15 -j block
ip6tables -A block -m recent --rcheck --name block --set
can be concatenated so that you don't need a separate "block" chain 
anymore, as follows:
ip6tables -A INPUT -m recent --rcheck --name syslogblock --seconds 900 
--hitcount 15 -m recent --rcheck --name block --set
But I'm not sure, I'll have to check.

Best regards,

Valentijn
-- 
http://www.openoffice.nl/   Open Office - Linux Office Solutions
Valentijn Sessink  v.sessink#openoffice.nl  +31(0)20-4214059


More information about the syslog-ng mailing list