This document is a complete and introducing handbook for the KISS project. You will find here informations related to both installation and configuration of this intrusion detection system.
At the end of this manual, you can browse the usual FAQ (frequently asked questions).
This handbook is freely distributable under the terms of the BSD license. SGML sources can be found under the filename doc/handbook/manual.sgml from the root of your source tree.
Finally, as you could probably see, English is not my native language. Thanks in advance for e-mailing me corrections (if possible using the diff program from the SGML sources, instead of sending me the whole corrected file). Comments and critics are also welcome, this is by the way your handbook.
Synopsis
Welcome to this handbook. I hope you will find here all the stuff you need to use KISS as a tool to secure your computer. I enjoyed a lot the development of this project, and I wish you will get the same fun using it.
This part covers the few prerequisites in order to correctly apprehend KISS .
An intrusion detection system (IDS) is a set of programs which keeps an eye on the system in order to enhance the detection of intrusions. Its main goal is to detect malicious attacks and send complete reports to the computer analyst of the company. Note that ID tools can also change the behaviour of the system in order to block the attacker in the future, but it should not be capital. After all : " Prevention is better than cure. "
Nowadays ID systems are numerous and fundamentally different, this is why analysts tend to divide them into two categories :
"host-oriented" : detect local intrusions (on the machine where the sensor is started), by auditing system logs and monitoring system calls;
"network-oriented" : capture network packets on a targeted network (like a sniffer), and analyze them afterward in order to detect network attacks.
KISS is a host-based security improvement for BSD operating systems. KISS can be compared as a host intrusion detection system, but I personally think it is rather more than that. The more interesting quality of KISS is probably its highly flexible configuration.
KISS was designed and implemented during my training period at Datarescue . This project was part of my thesis at the Haute Ecole de la Province de Liege Rennequin Sualem .
KISS is a young, open-source project. You are free to add your own improvements, correct bugs...
Note: KISS is by the way the acronym for Kernel Improvement Security System.
Here are the features that KISS is able to bring you :
Checking the integrity of your binary files upon execution by computing digest MD5 signatures;
Hiding files and processes to a list of untrusted users, using a rule-based interface like a network firewall;
Handling actions on a few interesting internal kernel events, according to a set of processes, users or groups in the system using a tiny scripting language;
Exchanging alarms from one or more remote KISS systems, using either plain-text or SSL connections;
Loading plugins dynamically into gateways, and storing your alarms wherever you want. You can also write your own plugins, using the provided development kit for the C language. KISS comes with a MySQL plugin.
Here is the list of things you will need to build KISS on your system :
A supported BSD-based operating system :
Perl , without specific modules (should be already installed) *
Lex & Yacc (should be already installed)
If you plan to build and use the KISS MySQL plugin :
The libmysqlclient.a library to link with (normally build with the MySQL distribution) *
A MySQL server (to host the KISS database) *
Eventually, a Web server (try Apache *) configured to support a PHP engine * is required if you want to test the provided PHP front-head
If you plan to build the SSL support for the gateway, OpenSSL libraries and binaries are required (should be already installed) *
If you plan to build the documentation (which is not obligatory), you will need the following applications :
TeX / LaTeX *
Doxygen *
Jade and the Docbook DTD *
Note: The KISS installation process will try to detect if the system is compatible for KISS, and presents you the stuff you can build.
*: This application can be found in the ports collection of your BSD operating system.
KISS is released under the BSD license. Actually the only way to get KISS on your system is to build it from the sources. I don't really like releasing binaries, and I hope the project will stick to the sources.
There are several ways to retrieve them :
HTTP : Unixtech (BE)
CVS : soon on sourceforge...
Note: If you are downloading the tarball distribution, don't forget to take also the MD5 digest signature, and to check if it corresponds.
The user-friendly installation script is still in construction. Meanwhile, you will have to do the stuff by yourself. If you are familiar with other open-source projects, it should not be a problem... Here are the distinct steps :
Installation procedure
Edit the Makefile.config, and set the variables illustrated in the nearby table;
Type make to build KISS according to your previous choices;
Type make install to install the software;
Optionally, if you plan to take advantage of the MySQL plugin, you can run the create_database.sql script on the machine where the MySQL server is running. This script can be found in the src/plugins/mysql directory from the source tree.
Makefile.config embedded variables
Destination directory where to install the built binaries and their configuration. Default value: /usr/local/kiss.
Build the documentation ? Default value : no.
Build the sources with debugging extentions ? Default value : no.
Link the gateway with OpenSSL library ? Default value : yes.
Build the MySQL plugin ? Default value : no.
Specify the hostname of the machine where MySQL server is running.
Specify the TCP port of the machine where MySQL server is running.
Specify MySQL username.
Specify MySQL password.
Specify the MySQL database where the data will be inserted. You should keep this to the "kiss" value unless you have modified the create_database.sql script.
The KISS core is provided under the form of a shared kernel object :
/modules/kiss.ko on FreeBSD systems;
/usr/lkm/kiss.o on OpenBSD systems.
The module should not be loaded and unloaded manually, unless for debugging purposes. Instead you should use the kissctl program to do that.
kissctl is a multipurpose management tool, which accepts the following command-line options :
start : loads the KISS core within the kernel with the password provided at the passwd: prompt, and create a session for the current process;
stop (*) : unloads the KISS core;
login : requests a session, identified by the password provided at the passwd: prompt. If you already have a valid session, the prompt won't be displayed;
logout (*) : revokes a session;
fw (*) : manages the file / process filter, also called as the internal host-firewall. Here are the sub-options :
add {show|hide} {file|proc} filename... for username... [log] : inserts a rule in the internal firewall;
del rule_id : removes a rule, using its unique identifier;
list : prints all rules;
flush : removes all existing rules.
ids (*) : manages the IDS subsystem, which is dedicated to the scripting language. Here are the sub-options :
load filename : loads an event script in the KISS IDS subsystem;
flush : flushes the IDS subsystem.
digest (*) : manages the digest database, file integrity checker. Here are the sub-options :
add filename... : inserts a set of filenames into the digest list. Only regular files (VREG) will be added;
update filename... : updates internal MD5 signatures for a set of filenames;
del filename... : removes a set of filenames from the digest list;
list : prints the list of entries from the digest list, including the filename, MD5 signature and vnode id;
flush : removes all entries of the digest list.
*: A valid session is required to start this command.
The KISS gateway is meant to receive alarms from the core and any remote connected gateway which hostname figures by default in the /usr/local/kiss/conf/kissgw.allow file.
Note: You should have a valid KISS session before starting the gateway, otherwise it will fail, unless you specified the -na parameters.
Note: Alarms are buffered in the KISS core before being sent. So if some alerts are detected in the system before a gateway is started, alarms won't be lost. Each time a gateway connects itself to the core, it empties its alarms buffer.
Here is the list of command-line options for the kissgw program :
-d : runs as a daemon, and therefore log through syslogd instead of the standard output;
-p directory : points to a specified directory which should contain the plugin, instead of the default directory /usr/local/kiss/plugins;
-n : exchanges alarms over the network, this option is required for the following network related options ;
-a : alone mode, doesn't open the KISS core, therefore the gateway will only receive alarms from other gateways;
-A filename : specifies another filename which should contain the list of allowed hostnames to connect on the gateway, instead of the default file /usr/local/kiss/conf/kissgw.allow;
-m method : specifies the method to exchange alarms over the network. Can be either plaintext or ssl (if supported). By default, all connections will be in plaintext;
-r hostname... : configures a colon-separated list of hostnames to relay alarms once they are received;
-P port : configures the TCP port to use, which is set to 4000 by default.
The kissalarm is a tool which allows you, to forge and send, within the command-line, your own KISS alarms to remote gateways.
This tool can be used to test the right functionality of your KISS gateways network, and can be also called from shell script to increase the variety of your alarms.
Here is the list of command-line options :
-p pid (*) : sets the PID which will identify the process that has caused the alarm;
-a string (*) : sets the ASCII description of the alarm;
-l level (*) : sets the level of the alarm, can be at choice low, normal or high;
-H hostname (*) : sets the hostname of the gateway where the alarm should be sent to;
-P port : specifies the TCP port to use, which is set to 4000 by default;
-m method : configures the method to use, either plaintext (specified by default) or ssl (if supported).
This protection can help you to monitor a list of binary files, and to avoid their execution when they have been modified.
Note: When a file is added in the digest database, it becomes automatically protected against the unlink(2) system call, in other words the file cannot be removed from the filesystem. The reason of this is obvious, because the integrity module recognizes files which are part of the digest list with their vnode id, and this last became obviously obsolete when the file is deleted.
When a binary which is part of the digest list is modified, each execve(2) system call on it will returns the EPERM errno code (permission denied) and send a KISS alarm.
Example 4-1. File integrity feature
Output of the console :
[...] root@teneriel /tmp> echo "int main(void) { return 0; }" > test.c root@teneriel /tmp> gcc test.c -o test root@teneriel /tmp> kissctl digest add /tmp/test *** 1 file(s) added in the KISS digest database root@teneriel /tmp> kissctl digest list MD5 (/tmp/test) : F1E6D25F4E30F2737E5FA8459E0CE183 (vnode id: 0xc7c20) *** End of digest listing (1 item(s)) root@teneriel /tmp> ./test root@teneriel /tmp> echo "int main(void) { return 1; }" > test.c root@teneriel /tmp> gcc test.c -o test root@teneriel /tmp> ./test su: ./test: Operation not permitted root@teneriel /tmp> kissctl digest update /tmp/test *** 1 file(s) updated from the KISS digest database root@teneriel /tmp> ./test [...]
And the related informations (with snipped timestamps) from the kernel log, /var/log/security :
[...] teneriel /kernel: kiss: Added MD5 (/tmp/test 0xc7c20) = f1e6d25f4e30f2737e5fa8459e0ce183 teneriel /kernel: kiss: MD5 digest matching for /tmp/test teneriel /kernel: kiss: Reported alarm (HIGH id=0) [uid=0, gid=0, pid=19473] : Attempt to unlink test (which is in the digest list) teneriel /kernel: kiss: Reported alarm (HIGH id=1) [uid=0, gid=0, pid=19473] : Attempt to open test for writing (which is in the digest list) teneriel /kernel: kiss: Reported alarm (HIGH id=2) [uid=0, gid=0, pid=19474] : MD5 old signature for /tmp/test mismatch ! teneriel /kernel: kiss: Updated MD5 digest for /tmp/test teneriel /kernel: kiss: MD5 digest matching for /tmp/test [...]
This feature can be used in order to hide a list of filenames and processes for a set of users, including the super user root.
Example 4-2. File hiding
Output of the console :
[...] root@teneriel /> kissctl fw add hide file /etc/*passwd* for pinux log *** Adding rule 1 in the KISS firewall table root@teneriel /> kissctl fw list #1 hide file(s) /etc/passwd /etc/master.passwd for user pinux (log = yes) *** End of fw rules listing (1 item(s)) root@teneriel /> ls /etc/*passwd* /etc/master.passwd /etc/passwd root@teneriel /> su pinux pinux@teneriel /> ls /etc/*passwd* ls: /etc/*passwd*: No such file or directory pinux@teneriel /> exit root@teneriel /> kissctl fw del 1 *** Removed KISS fw rule number 1 root@teneriel /> kissctl fw list *** End of fw rules listing (0 item(s)) root@teneriel /> su pinux pinux@teneriel /> ls /etc/*passwd* /etc/master.passwd /etc/passwd [...]
And the related kernel log :
[...] teneriel /kernel: kiss: Adding rule 0 teneriel /kernel: kiss: -> make index for /etc/passwd teneriel /kernel: kiss: -> make index for /etc/master.passwd teneriel /kernel: kiss: Built 2 entries in the file index teneriel /kernel: kiss: Reported alarm (LOW id=0) [uid=1001, gid=0, pid=19597] : Attempt to display master.passwd (which is hidden by the fw) teneriel /kernel: kiss: Reported alarm (LOW id=1) [uid=1001, gid=0, pid=19597] : Attempt to display passwd (which is hidden by the fw) [...]
Note: Process hiding is still in development...
The event scripting allows to handle a set of actions on internal events for a list of actors, which can be processes, users, or user groups.
Here is the semantic of a event scripting rule :
when actor... event { action1 ; action2 ; ... ; }
Here are the possible actors :
proc {procname.. | PID..}
user {username.. | UID.. | all}
group {grouname.. | GID..}
Here are the possible events :
open [READ | WRITE] filename..
execve filename..
kill [SIGINT | SIGCONT | SIGSTOP | SIGHUP] {procname.. | PID..}
connect [TCP | UDP] hostname.. {port.. | port-range}
bind [TCP | UDP] {port.. | port-range}
unlink filename..
Here are the possible actions :
message username.., "message" ;
report {low | normal | high}, "alarm description" ;
logout username.. ;
kill {procname.. | PID..} ;
Here are the possible auto-variables that you can use in actions clauses :
$curproc
$curuser
Example 4-3. A KISS script
The following script example is not very difficult to understand.
# This line is a comment. # when proc /usr/sbin/sendmail execve /bin/sh, /bin/csh, /bin/ksh { report HIGH, "sendmail wants to start a shell!"; kill $curproc; } when proc /usr/sbin/sendmail bind TCP 1-24 26-65535 { report HIGH, "sendmail wants to bind an other tcp port that 25!"; kill $curproc; } when user all connect TCP 6667-7000 { message $curuser, "Sorry, IRC is disabled from this box!"; logout $curuser; } when user all unlink /kernel { message $curuser, "Sorry, autosuicide is disabled"; kill $curproc; } when user all execve /bin/as, /usr/local/bin/nasm { message $curuser, "Well, you are in the right way!"; message root, "Note: give more money to $curuser"; } when group guest open /etc/passwd, /etc/master.passwd { report NORMAL, "$curuser wants to open a password file"; kill $curproc; } when user all kill /sbin/init { message $curuser, "Please remove KISS before killing init!"; kill $curproc; }
Example 4-4. A single gateway listening to the core
The following example is quite simple: we load KISS in the system, start a gateway dedicated to listening alarms from the core (without the network support), and generate manually some alarms.
The first terminal; load KISS, start the gateway and listen... :
root@teneriel ~> kissctl start You need to enter a password. This password will be asked each time you want to open a kiss session. The security of your system will depend essentially on this password. Note that without it, you won't be able to unload kiss. Finally, do not enter the same password as your root account. passwd> confirm> *** Kiss 0.1 alpha is now loaded and operational. root@teneriel ~> kissgw -v PID (24953) successfully written in /var/run/kissgw.pid kissgw: No plugins founded in /usr/local/kiss/plugins.. Handled signals Sleeping... Local receiver thread started (TID 0x8051400) [...]
The second terminal; attempt to remove the /dev/kiss device node and to manage KISS without authentication :
root@teneriel ~> rm /dev/kiss rm: /dev/kiss: Operation not permitted root@teneriel ~> kissctl digest list kissctl: You don't have a KISS session ! root@teneriel ~> kissctl digest add /bin/ls kissctl: You don't have a KISS session !
We come back to our first terminal, and here is now the output of the gateway :
25/5/2002 20:59:11 @ teneriel.teledisnet.be (FreeBSD 4.5-STABLE) user root (0:0) ps rm (24962) => Attempt to unlink /dev/kiss without authentication (network relay complete) Relay finished for alarm 1 No more alarms to read... Sleeping... 25/5/2002 20:59:21 @ teneriel.teledisnet.be (FreeBSD 4.5-STABLE) user root (0:0) ps kissctl (24963) => Attempt to GET without authentication Relay finished for alarm 2 No more alarms to read... Sleeping... 25/5/2002 21:0:0 @ teneriel.teledisnet.be (FreeBSD 4.5-STABLE) user root (0:0) ps kissctl (24964) => Attempt to DIGEST_ADD without authentication Relay finished for alarm 3 No more alarms to read... Sleeping... [...]
Example 4-5. Two linked KISS gateways
For this example, we started the kissgw daemon on two distinct machines. Arrakis is obviously running with the network mode, using SSL as encryption engine and listening for alarms from the Teneriel host on TCP port 6000.
Teneriel is running the gateway with the same flags, except that she specified Arrakis as a relay, therefore it means that each alarm received by Teneriel will be transmitted automatically on Arrakis .
And finally, we used the kissalarm client to forge and send a KISS example alarm to Teneriel .
Here is the output of the Arrakis gateway :
root@arrakis ~> kissgw -navm ssl -P 6000 PID (4856) successfully written in /var/run/kissgw.pid kissgw: No plugins founded in /usr/local/kiss/plugins.. Adding teneriel (192.168.1.7) to the trusted-hostname list Enter PEM pass phrase: Waiting for SSL connections on tcp port 6000 Network gateway thread started (TID 0x8051800) Connection established with 192.168.1.7 Waiting for SSL connections on tcp port 6000 SSL DES-CBC3-MD5 handshake successfull Waiting an alarm from 192.168.1.7... 24/5/2002 17:19:28 @ teneriel.teledisnet.be (FreeBSD 4.5-STABLE) user pinux (1001:0) ps bash (829) => Hello, World (network relay complete) Relay finished for alarm 0 Waiting an alarm from 192.168.1.7... [...]
And the Teneriel gateway output :
root@teneriel ~> kissgw -navm ssl -P 6000 -r arrakis PID (14720) successfully written in /var/run/kissgw.pid kissgw: No plugins founded in /usr/local/kiss/plugins.. Adding localhost (127.0.0.1) to the trusted-hostname list Enter PEM pass phrase: Waiting for SSL connections on tcp port 6000 Network gateway thread started (TID 0x8051400) Connection established on 192.168.1.1:6000 SSL DES-CBC3-MD5 connection successfull Connection established with 127.0.0.1 Waiting for SSL connections on tcp port 6000 SSL DES-CBC3-MD5 handshake successfull Waiting an alarm from 127.0.0.1... 24/5/2002 17:19:28 @ teneriel.teledisnet.be (FreeBSD 4.5-STABLE) user pinux (1001:0) ps bash (829) => Hello, World Alarm 0 successfully relayed to 192.168.1.1 (network relay complete) Relay finished for alarm 0 Waiting an alarm from 127.0.0.1... Thread 0x8071000 is dying (without errors) : killing peer 127.0.0.1 [...]
And finally, the output of the kissalarm client :
root@teneriel ~> kissalarm -p 829 -H localhost -m ssl -P 6000 -a "Hello, World" -l normal Alarm ID 0 acknowledged
A KISS gateway can load plugins dynamically, and send them each alarm it receives, which can be either from the core or from another remote gateway.
A plugin must be written in the C language, and must give the implementation of the following routines, respecting scrupulously the given prototype:
int plugin_init(void); int plugin_info(struct plugin_info *); int plugin_recv(struct kiss_alarm *); int plugin_stop(void);
author : the author's fullname, and eventually his e-mail address;
comment : a short description of the plugin;
version : the current development version of the plugin.
Note: The definition for both plugin_info and kiss_alarm structures are provided in the include/kiss-plugin.h header in the root of your KISS source tree. Notice that this header is copied in the /usr/local/include directory during the installation procedure.
Note: Your plugin must be compiled and linked as a shared object (with an optionally .so extention). You can do this by manually, but this is probably easier to use the provided kiss.plugin.mk makefile, that can be found in the mk directory of your KISS source tree.
Note: The plugin must be afterwards installed in the /usr/local/kiss/plugins, or in another directory, that you specify to kissgw with the -p option.
Example 5-1. A plugin example for the KISS gateway
Below is the source of a KISS plugin example :
#include <kiss-plugin.h> #include <stdio.h> #define AUTHOR "Sansonetti Laurent <laurent@datarescue.be>" #define VERSION "1.0" #define COMMENT "Example plugin" int plugin_init(void) { printf("*** example plugin: initialization\n"); return NULL; } int plugin_info(infos) struct plugin_info *infos; { printf("*** example plugin: get information\n"); strcpy(infos->author, AUTHOR); strcpy(infos->version, VERSION); strcpy(infos->comment, COMMENT); return NULL; } int plugin_recv(a) struct kiss_alarm *a; { printf("*** example plugin: received alarm:\n"); printf("*** %s\n", a->header.msg); return NULL; } int plugin_stop(void) { printf("*** example plugin: shutdown\n"); return NULL; }
Now, we are going to test it. After having installed the plugin in the /usr/local/kiss/plugins directory, we start a KISS gateway, using the network mode in plaintext :
root@teneriel ~> kissgw -nav PID (25129) successfully written in /var/run/kissgw.pid Successfully linked /usr/local/kiss/plugins/example.so Initializing KISS plugins in /usr/local/kiss/plugins : *** example plugin: initialization *** example plugin: get information example.so 1.0 by Sansonetti Laurent <laurent@datarescue.be> : Example plugin (plugins initialization complete) Adding localhost (127.0.0.1) to the trusted-hostname list Waiting for PLAINTEXT connections on tcp port 4000 Network gateway thread started (TID 0x8051400) [...]
We can see that our plugin has been successfully loaded, and the plugin_init and plugin_info routines have been called. Now we can use the kissalarm client in a different terminal to generate a simple alarm :
root@teneriel ~> kissalarm -p 2 -a "I'm in love with pagedeamon" -H localhost -l low Alarm ID 0 acknowledged
Back to the first terminal, we can check that our plugin has successfully received the alarm :
Connection established with 127.0.0.1 Waiting an alarm from 127.0.0.1... 25/5/2002 22:19:28 @ teneriel.teledisnet.be (FreeBSD 4.5-STABLE) user root (0:0) ps pagedaemon (2) => I'm in love with pagedeamon (network relay complete) *** example plugin: received alarm: *** I'm in love with pagedeamon Alarm successfully relayed via example.so Relay finished for alarm 0 [...]
Note: If you don't find the solution of your problem in this handbook, feel free to e-mail your questions at laurent@datarescue.be.
1. Why is the kernel-part of KISS a loadable kernel module and not statically compiled within the kernel ?
Because the design of KISS was meant to be dynamic, for the following reasons :
KISS features can be easily removed from your system, you just have to unload the module by authenticating with the password you provided during the loading. You don't need to make a rescue copy of your system if you are afraid of the dark side of KISS ;)
An esoteric kernel re-compilation is always long and painfull for newbies, and of course you need to have the sources installed, which is not often the case for servers...
Actually, only OpenBSD and FreeBSD are supported. A NetBSD or MacOSX port should not be rather difficult to do, because the kernel looks similar. But the other non-BSD operating systems (i.e. Linux) have a different kernel interface... Remember that KISS is a kernel-oriented project, portability is not quite easy...
Because OpenBSD does not provide a dynamic interface to add MALLOC(9) definitions and sysctl(2) nodes, so you must patch the kernel once forever to access the KISS definitions.
According to Artur Grabowski, a famous OpenBSD kernel-hacker : " Since OpenBSD hasn't worked towards converting everything into kernel modules (we generally think it's just a waste of time), we don't have support for such dynamism in the kernel. "