Thursday, December 25, 2008

OSSEC and Pf on FreeBSD to Limit SSH Brute Forcing

Disclaimer: This post is neither original nor particularly illuminating. It does, however, document how I configured software on systems I administer. Therefore, I post it here mainly for my own future reference, but know it might be useful to someone else.

If you run OpenSSH on any Internet-facing server, you're likely to see entries like these every day:

r200a:/root# bzcat /var/log/auth.log.0.bz2 | head -n 5 | grep -v turned
Dec 23 20:00:02 r200a sshd[33320]: Invalid user httpd from 87.106.142.217
Dec 23 20:00:03 r200a sshd[33322]: Invalid user dima from 87.106.142.217
Dec 23 20:00:04 r200a sshd[33324]: Invalid user bane from 87.106.142.217
Dec 23 20:00:05 r200a sshd[33326]: Invalid user juan from 87.106.142.217

I like to run OSSEC on servers as a means to monitor and analyze log files. OSSEC would report that activity as follows.

2008 Dec 23 20:00:44 Rule Id: 5712 level: 10
Location: (r200a) 172.16.2.1->/var/log/auth.log
Src IP: 87.106.142.217
SSHD brute force trying to get access to the system.
...edited...
Dec 23 20:00:02 r200a sshd[33320]: Invalid user httpd from 87.106.142.217

In the setup for this post I am running an OSSEC agent on an Internet-facing gateway with an internal IP of 172.16.2.1 (r200a). My OSSEC server is 192.168.2.13 (macmini). My simulated attack box is 192.168.2.101 (debian40r0).

The first thing I need is a program to brute force SSH on 172.16.2.1. I wanted something simple so I installed sshbrute.py by d3hydr8.

tws@debian40r0:~$ wget http://www.darkc0de.com/bruteforce/sshbrute.py
...edited...
tws@debian40r0:~$ su -
Password:
debian40r0:~# apt-get install python-pexpect
...edited...
debian40r0:~# logout
tws@debian40r0:~$ python sshbrute.py

d3hydr8:darkc0de.com sshBrute v1.0
----------------------------------------

Usage : ./sshbrute.py
Eg: ./sshbrute.py 198.162.1.1 root words.txt

I decided to use /etc/dictionaries-common/words for my wordlist because this is only a test and I don't really care if I can brute force my own user accounts in this scenario. I just want to be sure I can configure OSSEC to tell Pf to block the offending source IP for a period of time.

Now I need to configure Pf on the FreeBSD gateway to ensure OSSEC can work with it. I make certain OSSEC changes to /etc/pf.conf.

ext_if = "bge0"
int_if = "bge1"
localnet = $int_if:network
# needed by OSSEC
table <ossec_fwtable> persist
...now come some rules...
# needed by OSSEC
block in quick from <ossec_fwtable> to any
block out quick from any to <ossec_fwtable>

To verify the OSSEC firewall table is currently blank I run this:

r200a:/root# pfctl -t ossec_fwtable -T show
No ALTQ support in kernel
ALTQ related functions disabled

The next step is to configure my OSSEC server to take an action when an offending IP address takes a sufficiently hostile step against a host running an OSSEC agent. This took a second thought, because I am configuring the OSSEC server to tell the OSSEC agent to take a blocking action using the firewall-deny.sh script on the host running the OSSEC agent reporting the SSH brute forcing. That isn't the only way to configure this option, but it works for me. The block will persist for 600 seconds or 10 minutes.

<command>
<name>firewall-drop</name>
<executable>firewall-drop.sh</executable>
<expect>srcip</expect>
<timeout_allowed>yes</timeout_allowed>
</command>

<!-- Active Response Config -->

<active-response>
<!-- Firewall Drop response. Block the IP for
- 600 seconds on the firewall (iptables,
- ipfilter, etc).
-->
<command>firewall-drop</command>
<location>local</location>
<level>10</level>
<timeout>600</timeout>
</active-response>
</ossec_config>

I restart OSSEC on both client and server using /var/ossec/bin/ossec-control restart.

Now it's show time; I run the brute force from the attack box.

tws@debian40r0:~$ python sshbrute.py 172.16.2.1 root /etc/dictionaries-common/words

d3hydr8:darkc0de.com sshBrute v1.0
----------------------------------------
[+] Loaded: 98569 words
[+] Server: 172.16.2.1
[+] User: root
[+] BruteForcing...
Trying:
Trying: A
Trying: A's
Trying: AOL
Trying: AOL's
Trying: Aachen
Trying: Aachen's
Trying: Aaliyah
Trying: Aaliyah's
...stalled...

Checking /var/ossec/logs/alerts/alerts.log on the OSSEC server shows messages like this:

** Alert 1230260722.392334: - syslog,sshd,authentication_failed,
2008 Dec 25 22:05:22 (r200a) 172.16.2.1->/var/log/messages
Rule: 5716 (level 5) -> 'SSHD authentication failed.'
Src IP: 192.168.2.101
User: root
Dec 25 22:05:19 r200a sshd[49425]: error: PAM: authentication error
for root from 192.168.2.101

Then I see OSSEC's report of a level 10 event.

** Alert 1230260730.394490: mail - syslog,sshd,authentication_failures,
2008 Dec 25 22:05:30 (r200a) 172.16.2.1->/var/log/messages
Rule: 5720 (level 10) -> 'Multiple SSHD authentication failures.'
Src IP: 192.168.2.101
User: root
Dec 25 22:05:25 r200a sshd[49450]: error: PAM: authentication error
for root from 192.168.2.101
Dec 25 22:05:24 r200a sshd[49445]: error: PAM: authentication error
for root from 192.168.2.101
...truncated...

A look at the active-responses.log on the gateway shows a new rule adding that blocks the offending IP.

r200a:/root# tail -n 1 /var/ossec/logs/active-responses.log
Thu Dec 25 22:05:28 EST 2008 /var/ossec/active-response/bin/firewall-drop.sh
add - 192.168.2.101 1230260730.395394 5720

Checking Pf we see the new rule.

r200a:/root# pfctl -t ossec_fwtable -T show
No ALTQ support in kernel
ALTQ related functions disabled
192.168.2.101

If I want to manually remove the block I can do this:

r200a:/root# /var/ossec/active-response/bin/firewall-drop.sh
delete - 192.168.2.101
r200a:/root# pfctl -t ossec_fwtable -T show
No ALTQ support in kernel
ALTQ related functions disabled

That worked just as I hoped. Now I have a way to limit scanners who hammer at SSH on port 22. Yes, I could take a lot of other actions, but this is what I wanted to document.


Richard Bejtlich is teaching new classes in DC and Europe in 2009. Register by 1 Jan and 1 Feb, respectively, for the best rates.

9 comments:

jtimberman said...

For what it's worth (to you or your readers) fail2ban does similar on Linux with iptables.

mr_clark said...

Hey Richard. Your link to ossec is incorrect. It should be http://www.ossec.net not .org.

Great post.

Richard Bejtlich said...

Fixed, thanks.

James Turnbull said...

And if you don't want to run fail2ban - you can just do it with iptables.

Charlene said...

I am curious about OSSEC. Is it better than Snort, or an alternative, or to be used in conjunction with it.

I'm an inexperienced Sys Admin for some freeBSD servers through an ISP (so I don't have full responsibility). One of our servers got badly hacked and a client paid for an outside vendor to check out the servers. Of course he's trying to sell his own hosting service, and I want to be sure that we really need to go that route.

Richard Bejtlich said...

Hi Charlene,

I would use OSSEC in conjunction with Snort. The class I'm writing for Black Hat right now describes how to do that.

Anonymous said...

Just wondered if you could give any direction as you have mentioned both projects before. I currently use splunk to index/aggregate my logs and have a decent number of custom apps/bundles and reports for events across my network. I also aggregate my httpd logs, mail logs, vpn access logs, etc to help our helpdesk. I've started deploying ossec agents to most of the same hosts that are sending off their logs via syslog and was wondering if you had any experience with implementing ossec and splunk in the same environment without duplicated log aggregation efforts.

oy said...
This comment has been removed by a blog administrator.
Anonymous said...

Nice article, thanks for this!
On your setup the ossec server and pf daemon are running on the same box (gateway)? Is it possible to have ossec server located on another device to talk to another box pf?