Tracking Malicious IP & Users with OSSEC

Below the RadarA few months ago I blogged about Active Lists in OSSEC. Active lists are common in SIEM environments to store temporary sensitive data like IP addresses, user names or any other relevant information. Once stored in active lists, data can be reused in rules and the security of an infrastructure can be increased. Here again, the goal is to give more value to the collected event.

Take the following example: a sysadmin who escalated his privileges to root access on a server is a regular event which may occur several times a day. But, if the same sysadmin became suspicious, his actions must be immediately processed with a higher priority. The same idea applies to IP addresses. A port-scan executed from an external IP address could be flagged as a medium-level event. On the other side, the same action performed from a blacklisted IP address could be flagged with a high priority!

In my previous article, I explained how to maintain an active list populated by OSSEC itself (using the active-response feature). But this way not very efficient and easy to re-use. The idea of a new implementation came when I found the tool ArcOSI (“ArcSight Open Source Intelligence“) developed by Greg Martin. Greg’s Python script parses specific URLs (like ISC or ZeusTracker) which compile lists of malicious IP addresses and domain names. Then, it sends CEF syslog events to an ArcSight product. Why not implement the same idea into OSSEC? The goal will be to generate a specific alert when some activity, based on information stored in active lists, is detected.

A successfully parsed OSSEC event may contain the following information: “srcip“, “dstip“, “srcuser” and “dstuser” (depending on the event source). Once decoded, the event is evaluated against all the defined rules. New checks will be implemented to detect if the decoded IP addresses or user are present in the corresponding active lists stored in a MySQL server. The big advantage with MySQL is the real-time management of the tables. It’s easy to add/remove IP addresses or users collected from external tools or online resources with a direct impact on the running OSSEC server. Once you defined your rules and alerts, no need to adapt the core OSSEC configuration every time.

If you don’t have a deep OSSEC background, you have to know the software works. OSSEC is based on a client-server model and is process the data via several software components (daemons) which perform specific tasks like:

  • Collecting the logs at source
  • Sending alerts
  • Executing scripts (active-response)
  • Analyzing the events

Some daemons are running on both servers and agents, others are running only on servers. For more details, consult the OSSEC website. The OSSEC component that will receive our attention is “analysisd“. This daemon runs only on the server side, receives events collected by the “logcollector” processes and analyzes (decodes, filters and classifies) them. That’s the perfect place to implement the active lists. An overview of the architecture follows:

Active Lists Implementation
(Click to enlarge)

To build an autonomous system, a “feeder” will inject IP addresses and users in the active lists. For each event processed by the analysisd daemon, a lookup will be performed. To implement this, the following steps must be performed:

1. Install a standard OSSEC with DB support. By enabling the database support, OSSEC will write alerts into a SQL database (MySQL in this case). You will need a MySQL server properly configured and the development libraries and include files. Configure and install the whole stuff using the installation script.

2. Create the new MySQL tables in the OSSEC database. To perform a cleanup, each record will have an expiration date. The “source” field is a free string and will be displayed in the alerts created by analysisd.

  CREATE TABLE suspicious_ip (
    ip VARCHAR(15) NOT NULL UNIQUE,
    date_created DATETIME,
    date_expire DATETIME,
    source VARCHAR(255),
    PRIMARY KEY(ip)
  );
  CREATE TABLE suspicious_user (
    user VARCHAR(64) NOT NULL UNIQUE,
    date_created DATETIME,
    date_expire DATETIME,
    source VARCHAR(255),
    PRIMARY KEY(user)
  );

3. In the /src/analysid source tree, patch the analysisd daemon to add the MySQL support as well as the Makefile. Recompile the daemon and replace the installed binary with the new one. Restart OSSEC. Once started, the daemon will keep a session open to the MySQL as described in the ossec.conf.

When a received event is parsed and an IP address or user is decoded, a lookup is performed against the newly created tables. In case of a positive match, a new alert is generated with a specific rule ID and level and a class called “suspicious“:

  ** Alert 1296586822.17371: - suspicious,
  2011 Feb 01 20:00:22 vmubuntu ->/var/log/auth.log
  Rule: 99999 (level 12) -> 'Suspicious user (Source: Test)'
  Src IP: 192.168.254.205
  User: xavier
  Feb  1 20:00:21 vmubuntu sshd[24465]: Accepted password for xavier from 192.168.254.205 port 63618 ssh2

Another example with a suspicious user. A user gaining root access generates an alert with level 3. Depending on your OSSEC configuration, this will not trigger a mail. But, the fact that the same user is present in the active list, an alert with level 12 will be generated:

  ** Alert 1296640271.5124: - suspicious,
  2011 Feb 02 10:51:11 vmubuntu->/var/log/auth.log
  Rule: 99999 (level 12) -> 'Suspicious user (Source: HR-dept)'
  Src IP: (none)
  User: root
  Feb  2 10:51:11 vmubuntu su[26457]: + /dev/pts/3 xavier:root

  ** Alert 1296640271.5356: - syslog, su,authentication_success,
  2011 Feb 02 10:51:11 vmubuntu->/var/log/auth.log
  Rule: 5303 (level 3) -> 'User successfully changed UID to root.'
  Src IP: (none)
  User: root
  Feb  2 10:51:11 vmubuntu su[26457]: + /dev/pts/3 xavier:root

4. Populate the tables! There are several ways to populate the active lists. By manual inputs, by analyzing other log files or by grabbing information from the Internet! As did Greg with his ArcOSI script, I wrote my own Perl tool to grab IP addresses from well-known sites and insert them into the MySQL database. By default, the script creates an expiration date five days later. This script can be executed at regular interval via a cron:

  # ./populate_ip_list.pl
  Connection to MySQL DB...
  Fetching IPs from http://www.mtc.sri.com/live_data/attackers/ ...
  Fetching IPs from http://isc.sans.edu/reports.html ...
  Fetching IPs from http://www.projecthoneypot.org/list_of_ips.php ...
  Fetching IPs from https://zeustracker.abuse.ch/blocklist.php?download=ipblocklist ...
  Fetching IPs from https://spyeyetracker.abuse.ch/blocklist.php?download=ipblocklist ...
  1191 IP addresses in the database.

What’s next? Some parameters are hard-coded at the moment (the alert ID and level). They could be moved to the OSSEC main config file. Another improvement could be to not create a new alert but increase the priority of an existing alert. Suggestions are welcome!

Related files:

The patches and scripts are provided “as is” without warranty of any kind. Feel free to use and adapt them to your needs.

9 comments

  1. Alright. in the patch what are the @@ and + symbols for ? are they part of the patch ??

  2. Thanks for sharing!I found four warnings when I recompiled analysisd.c ,just shown below.
    analysisd.c: In function ‘IsIPSuspicious’:
    analysisd.c:1877: warning: implicit declaration of function ‘osdb_seterror’
    analysisd.c:1901: warning: return makes pointer from integer without a cast
    analysisd.c: In function ‘IsUserSuspicious’:
    analysisd.c:1952: warning: return makes pointer from integer without a cast

    And when I replaced the binary,there comes the problem,the ossec can not start.
    Started ossec-csyslogd…
    Started ossec-maild…
    Started ossec-execd…
    Started ossec-analysisd…
    Started ossec-logcollector…
    Started ossec-remoted…
    2011/06/30 00:32:31 ossec-syscheckd(1210): ERROR: Queue ‘/var/ossec/queue/ossec/queue’ not accessible: ‘Connection refused’.
    2011/06/30 00:32:31 ossec-rootcheck(1210): ERROR: Queue ‘/var/ossec/queue/ossec/queue’ not accessible: ‘Connection refused’.
    2011/06/30 00:32:39 ossec-syscheckd(1210): ERROR: Queue ‘/var/ossec/queue/ossec/queue’ not accessible: ‘Connection refused’.
    2011/06/30 00:32:39 ossec-rootcheck(1210): ERROR: Queue ‘/var/ossec/queue/ossec/queue’ not accessible: ‘Connection refused’.
    2011/06/30 00:32:52 ossec-syscheckd(1210): ERROR: Queue ‘/var/ossec/queue/ossec/queue’ not accessible: ‘Connection refused’.
    2011/06/30 00:32:52 ossec-rootcheck(1211): ERROR: Unable to access queue: ‘/var/ossec/queue/ossec/queue’. Giving up..

    I don not know why,can anyone help me?
    Thanks very much!

  3. Unfortunately using mysql requires mysql. 😉

    The read-only nature of cdb is definitely a downside. I’ve thought of hacks around it (since the compiling doesn’t take long, and OSSEC doesn’t have to be restarted), but it’s kind of a pain.

  4. Thanks for the feedback! The cdb support implements indeed the same checks but has (IMHO) a major constraint : You need to build the files on the OSSEC server and recompile them.

    Using MySQL, theoretically *any* application can inject users/addresses in real time.

    In your case, domain names lookup can be interesting as they don’t change so often.

    /x

  5. Great post! This seems similar to the cdb support.

    I currently use it for looking up suspicious domain names (in named client query logs) and IP addresses (firewall logs).

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.