How to build a sensor

Building a sensor doesn’t just require knowing LibPrelude, hence this tutorial, but it is certain that having read this tutorial about LibPrelude can help. This tutorial tries to give a few hints on how to build your own sensor with LibPrelude, regardless of the language used. In order to build your sensor you will ask yourself these questions :

 

  • Where do I add my code ?
  • What should I fill my alert with ?
  • How can I add LibPrelude to the project ?

Why build a sensor ?

This question is actually a very good question. We are indeed already able to create IDMEF alerts from almost every log using Prelude-LML. Then why spend time on building a sensor that should do the exact same thing, just a bit sooner ?
First of all, it is much easier to extract information from the structures containing it in the tool than from a line of text which does not necessarily contain everything needed. Most of the time, indeed, you will be able to add a lot more to your IDMEF alert than what Prelude-LML cane extract from the log.
Then, it’s also a good way to standardize the way alerts are written. If you are familiar with IDMEF, (if not then check here), you should know that some field are not enumeration but still extremely useful for correlation. For example, classification.text is not an enumeration, thus you can describe your alert the way you want. When dealing with huge networks, it is more efficient to be sure that this field is standardized so the alerts are suited for correlation. As for whether a sensor should be built on tool or not, Prelude’s developers can see here a list of criteria the tool has to comply with in order to build the sensor?

First baby step

If the project you’re trying to add a prelude sensor to is not your project, if it’s the first time you are working on it or if you are not familiar with it, try installing it and observing the tool, especially logs and other outputs. If you really think you will need some help, most projects have a mailing list and you can try writing to them.

Where to…?

Add your code

You will try not to be excessively intrusive. In order not to modify excessively the initial project’s code, add your own file or files containing all the functions/methods/objects you will need. And only add inclusions and function calls in the rest of the project. Your files shall not be in the wrong place so take a look at how the other files are ordered. Your file should most probably be with the logs.

Initialize the library and create a client

This should be done when the tool starts. To know where to call your init function, find the main function, where everything is started, and add here your function call. Please note that you must be sure that you are not creating the client in a thread that will be deleted. The client should be accessible when creating an alert since it will send it. Thus, pay attention to the way it is stocked. We suggest using a global variable, even though it is not really clean to add a global variable, or adding the newly created client in an already existing structure/class containing global data. Don’t forget to call this function only if LibPrelude has been compiled with the project. We will see how to do it later.

Create a new alert

An alert should at least be sent every time a dangerous event is logged. First, try searching where the tool logs event. You can filter them on their dangerousness and call your alert function from there.
But don’t forget to verify if you can send alerts from elsewhere.

Destroy the client

It could be helpful, when using Prelude, to know whether an agent is down because of real problem or was just shut down.
LibPrelude allows you to close your prelude client neatly and that should always be done when you can find how the tool is closed.

Creating the client

When creating the client, some options have to be set. Let’s review the most important :

 

  • Analyzer name : There are two analyzer names. One to identify it from a human operator perspective, another to communicate with the manager. The one provided when creating the client has to be the same name that was used to register the agent to the manager. Since it has to be handwritten by the user, we suggest you let the user choose the name in a configuration file, for example. Usually, one name is used for both of this fields, but you can choose to use two different names, as it pleases you.
  • Client flags : These are options configuring timers, heartbeats and so on. You can find the available flags here
  • Other analyzer information : This contains version, model, class and manufacturer. You should try to fill it as much as you can because in case of huge networks, agents can be of very different types. You can find hints on how to classify analyzers on prelude’s wiki.

Filling the alert

With what ?

Most security tools try to allow several log formats, each containing different fields. To store this information, you will most probably find a global structure (maybe the one you used to store the client) containing every thing that should be known in order to send an alert. You should thus fill your alert with, at least, what is contained in the logs. But remember, you can maybe find other important hints to add to your alert. You can also fetch information using other functions like getPid() for example.

Which fields should I fill ?

Some fields are almost required. You can find them in the How to use IDMEF section. Apart from this there are a few things to know about IDMEF alerts and how to fill them. First, try, as much as possible, not to use the Additional Data class. This class isn’t standardized and it is almost impossible to correlate alerts based on it. Thus avoid using Additional Data and try to map correctly the other fields. You may need it though when dealing with webservices as a lot of fields are still missing in the IDMEF schema concerning this section. You should also indicate, when possible, the target of the event. Even when it seems obvious, this can still be useful when dealing with a lot of data. Then fill in as much fields as you can, the more the merrier !

Import Libprelude

In order to build a sensor, the first thing you should do is to add libprelude to the project.

In c/c++

This tutorial will aim to show you how to compile you’re project in c/c++ with libprelude. Indeed if you are working in another language, the import will be pretty easy.

Basic example

To compile a really basic c file with libprelude, you juste have to put the prelude flag like this :

gcc example.c -l prelude -o example

With a Makefile

Assuming you use a Makefile for your project, as described bellow, you will have to had to your project the CFLAGS prelude :

CFLAGS=prelude

With AutoGen

If you use AutoGen for your compiling process, and want to had the prelude support as an option, you will first have to include this m4 file : prelude.m4. It will add the function AM_PATH_LIBPRELUDE :

AM_PATH_LIBPRELUDE([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]], THREAD_SUPPORT)

You can then access to this function to find the path of libprelude, it will also throw an error if there is no correct version installed. You can now configure your configure.ac as you want, or add this example of implementation :

AC_ARG_ENABLE(prelude,
            AS_HELP_STRING([--enable-prelude],
                            [Enable Prelude support for alerts.]),
[
    if test "$enableval" != "no"; then
        AM_PATH_LIBPRELUDE(0.9.9, , AC_MSG_ERROR(Cannot find libprelude: Is libprelude-config in the path?), no)
        CPPFLAGS="${CPPFLAGS} ${LIBPRELUDE_CFLAGS}" 
        LDFLAGS="${LDFLAGS} ${LIBPRELUDE_LDFLAGS}" 
        LDFLAGS="${LDFLAGS} ${LIBPRELUDE_LIBS}" 
        AC_DEFINE([PRELUDE], [1], [Libprelude support enabled])
    fi
],)

In other languages

In other languages it will be pretty much easier, since you don’t have to compile. You will juste have to import the prelude bindings only in the file wich will require libprelude.

prelude.m4 – Prelude m4 File to help finding prelude (7.88 KB)