Monitorización

A lo largo de la practica se ha ido viendo como registrabamos los eventos del sistema por medio de las funciones de log definidas. Estas se encuentran en el paquete Utils y dan soporte a distintas acciones.

Registro de eventos

Estos scripts hacen uso de syslog (rsyslog) y almacenan los registros con distintos prioridades y tipos (LOG_AUTH, LOG_USER, ...).

Log general.

sub log($$$)
{
    my ($facility, $priority, $msg) = @_;
    eval{
        Sys::Syslog::openlog($programname, "", "LOG_USER");
        Sys::Syslog::syslog($priority, $msg);
        Sys::Syslog::closelog();
    }
}

Log relacionado con la autenticación.

sub authlog($$$$)
{
    my ($action, $user, $ip, $result) = @_;

    eval
    {
        Sys::Syslog::openlog($programname, "", "LOG_AUTH");
        Sys::Syslog::syslog("LOG_INFO", "Action: $action, User: $user, IP: $ip, Result: $result");
        Sys::Syslog::closelog();
    }
}

Log para los servicios generales.

sub servicelog($$$)
{
    my ($action, $user,  $result) = @_;

    eval
    {
        Sys::Syslog::openlog($programname, "", "LOG_USER");
        Sys::Syslog::syslog("LOG_INFO", "Service: $action, User: $user, Result: $result");
        Sys::Syslog::closelog();
    }
}

Log de copias de seguridad.

sub backuplog($$$$$$)
{
    my ($type, $from, $to,  $date, $level,$result) = @_;

    eval
    {
        Sys::Syslog::openlog($programname, "LOG_USER");
        Sys::Syslog::syslog("LOG_INFO", "$type: $from, To: $to, Date: $result, Level:$level, Result: $result");
        Sys::Syslog::closelog();
    }
}

Log de restauración de copias de seguridad.

sub restorelog($$$$)
{
    my ($type, $from,  $date,$result) = @_;

    eval
    {
        Sys::Syslog::openlog($programname, "", "LOG_USER");
        Sys::Syslog::syslog("LOG_INFO", "$type: $from, To: $to, Date: $result, Level:$level, Result: $result");
        Sys::Syslog::closelog();
    }
}

Archivo de Log propio

Las funciones anteriores harán que se almacenen los registros junto a los de otras aplicaciones en los ficheros definidos por rsyslog.

Estos archivos se irán rotando y nosotros deseamos poder mantener un registro histórico de estos log que sería periodicamente almacenado en una fuente de almacenamiento externa. En esta ocasión no estará disponible dicho almacenamiento, pero aún así deseamos mantener una copia de este registro separada del resto.

Esto se puede conseguir mediante el archivo de configuración de syslog, /etc/rsyslog.conf. Añadiremos al final de este archivo la siguiente linea.

:programname, contains , "tronco"   /var/log/tronco/tronco.log

En el código anterior veiamos que se habría el log con el parámetro $programname, que era igual a tronco. Esto significa que el log seguardará con ese nombre de programa.

En la linea del archivo de configuración se indica que queremos que las entradas con ese nombre también se almacenen en /var/log/tronco/tronco.log.

Podemos comprobar la apariencia que tiene este archivo.

../_images/log.png

Vemos que nos muestra toda la información útil. El tipo de acceso, la hora, la IP desde la que se ha realizado cuando es pertinente y el resultado de la operación.

Informes

Si bien los resultados anteriores nos serán útiles, suponen la necesidad de acceder de forma manual al archivo de syslog y un escaneo del archivo para encontrar eventos que sea necesario antender.

Para suplir esta necesidad utilizamos el script analizarAccesos.pl. Este script analizará el log y nos mostrará un resumen de los últimos accesos.

En concreto se ha diseñado para ser ejecutado diariamente y enviar por correo a los administradores esa información.

Lo más relevante del script es lo siguiente.

Se define el correo electrónico al que se enviará el informe.

my $adminmail = "cactus\@cactus.rufian.eu";

Se indica el archivo que se analizará.

my $logfile = "/var/log/tronco/tronco.log";

Se crea un elemento parser utilizando el módulo Parse::Syslog utilizando como argumento nuestro archivo de log.

my $parser = Parse::Syslog->new($logfile, allow_future => 1);

Creamos uan serie de variables en las que almacenar distintos tipos de eventos. Tanto realizados correctamente como fallidos.

my $accesos = "";
my @login = (0,0);
my @newUser =(0,0);
my @deleteUser =(0,0);
my @changePass = (0,0);
my @resetPass = (0,0);
my @restoreBackup = (0,0);
my @createWeb = (0,0);
my @deleteWeb = (0,0);

Definimos al hora actual, ya que solo queremos registrar los últimos eventos. Con esta hora se compararán las entradas del archivo de log.

use DateTime::Format::Strptime;
my $fmt = '%a %b %d %H:%M:%S %Y';
my $tparser = DateTime::Format::Strptime->new(pattern => $fmt);
my $nowtime = localtime;
my $now = $tparser->parse_datetime($nowtime) or die;

Ahora, para cada elemento encontrado se comprobará que es del programa tronco (aunque ya definimos que serán los que aparezcan en este archivo). También comprobamos que la fecha se encuentre en el rango realizado. Para tener un margen ligeramente superior, se recogerá la información sobre el último día y las 3 horas anteriores.

while(my $sl = $parser->next) {
    if ($sl->{program} eq "tronco")
    {
        my $logdate = localtime($sl->{timestamp});
        my $datecomp = $tparser->parse_datetime($logdate) or die;
        my $dif = $now - $datecomp;
        unless($dif->days >1 or ($dif->days==1 and $dif->hours>=3))
        {

Después se distinguirá entre las entradas correctas e incorrectas. Para estas últimas además se guardará en una lista la linea, ya que será importante comunicarle esta información al administrador.

            if($sl->{text} =~ /OK$/)
            {
                if($sl->{text} =~ /^Action: Login, User:/){$login[0]++;}
                if($sl->{text} =~ /^Action: Change Password, User:/){$changePass[0]++;}
                if($sl->{text} =~ /^Action: New User, User:/){$newUser[0]++;}
                if($sl->{text} =~ /^Action: Delete User , User:/){$deleteUser[0]++;}
                if($sl->{text} =~ /^Action: Reset Password, User:/){$resetPass[0]++;}
                if($sl->{text} =~ /^Restore: /){$restoreBackup[0]++;}
                if($sl->{text} =~ /^Service: Remove Web/){$deleteWeb[0]++;}
                if($sl->{text} =~ /^Restore: Create Web/){$createWeb[0]++;}

            }else
            {

                my @split = split(",", $sl->{text});
                my $date = scalar(localtime(($sl->{timestamp})));
                $accesos .= "$date\t\t\t";
                foreach my $s (@split)
                {
                    $accesos .=  sprintf "%-25s", $s;
                }
                $accesos .=  "\n";

                if($sl->{text} =~ /^Action: Login, User:/){$login[1]++;}
                if($sl->{text} =~ /^Action: Change Password, User/){$changePass[1]++;}
                if($sl->{text} =~ /^Action: New User, User:/){$newUser[1]++;}
                if($sl->{text} =~ /^Action: Delete User , User:/){$deleteUser[1]++;}
                if($sl->{text} =~ /^Action: Reset Password, User:/){$resetPass[1]++;}
                if($sl->{text} =~ /^Restore: /){$restoreBackup[1]++;}
                if($sl->{text} =~ /^Service: Remove Web/){$deleteWeb[1]++;}
                if($sl->{text} =~ /^Restore: Create Web/){$createWeb[1]++;}
            }
        }
    }
}

Una vez recopilados todos los datos se guardan en la variable buf en un formato legible que haga más sencillo al administrador su análisis.

Se separa el resumen de accesos válidos e inválidos y después se imprime la lista de accesos inválidos.

my $buf = "Cactus: Informe diario.\n\n\n";


$buf .= sprintf "%-35s%s\n", "Login:", $login[0] ;
$buf .= sprintf "%-35s%s\n", "Nuevos Usuarios:", $newUser[0];
$buf .= sprintf "%-35s%s\n", "Usuarios Eliminados:", $deleteUser[0] ;
$buf .= sprintf "%-35s%s\n", "Cambios de Contraseña:", $changePass[0] ;
$buf .= sprintf "%-35s%s\n", "Recordatorios de Contraseña:", $resetPass[0] ;
$buf .= sprintf "%-35s%s\n", "Backups Restaurados:", $restoreBackup[0] ;
$buf .= sprintf "%-35s%s\n", "Webs Creadas:", $createWeb[0] ;
$buf .= sprintf "%-35s%s\n", "Webs Eliminadas:", $deleteWeb[0] ;



$buf .= "=======================================================";
$buf .= "\n\n" . "Accesos inválidos\n\n";

$buf .= sprintf "%-35s%s\n", "Login:", $login[1] ;
$buf .= sprintf "%-35s%s\n", "Nuevos Usuarios:", $newUser[1];
$buf .= sprintf "%-35s%s\n", "Usuarios Eliminados:", $deleteUser[1] ;
$buf .= sprintf "%-35s%s\n", "Cambios de Contraseña:", $changePass[1] ;
$buf .= sprintf "%-35s%s\n", "Recordatorios de Contraseña:", $resetPass[1] ;
$buf .= sprintf "%-35s%s\n", "Backups Restaurados:", $restoreBackup[1] ;
$buf .= sprintf "%-35s%s\n", "Webs Creadas:", $createWeb[1] ;
$buf .= sprintf "%-35s%s\n", "Webs Eliminadas:", $deleteWeb[1] ;



$buf .= "=======================================================";
$buf .= "\n\n" . "Listado de accesos inválidos" . "\n\n". $accesos;
$buf .= "\n\n\n";


print $buf;

Para finalizar se utilizan los módulos Email::MIME y Email::Sender::Simple para enviar el informe por correo.

my $message = Email::MIME->create(
header_str => [
    From    => 'root@cactus.rufian.eu',
    To      => $adminmail,
    Subject => 'Cactus: Informe de Accesos',
],
attributes => {
    encoding => 'quoted-printable',
    charset  => 'ISO-8859-1',
},
body_str => "$buf",
);

#sendmail($message);

Ahora que tenemos listo el script lo añadiremos a cron como en ocasiones anteriores. Se realizará cada día a las 0:20 horas.

# crontab -e

    ### Analisis estadistico
    00 20 * * * /usr/local/tronco/analisisAccessos.pl
    ################################################

Un ejemplo de este informe, recibido por email, es el siguiente.

Vemos los accesos válidos e inválidos, donde podríamos detectar, por ejemplo, una gran cantidad de accesos inválidos a un mismo servicio que nos haría sospechar.

../_images/val.png

Y el listado de accesos inválidos.

../_images/inval.png

Seguridad con tripwire

Con lo anterior hemos conseguido poder llevar un registro de lo que sucede en el sistema pero de forma complementaria se instala tripwire. Con tripwire seremos avisados en caso de cambios en archivos críticos del sistema.

En primer lugar instalamos tripwire.

# apt-get install tripwire

Durante la instalación nos pedirá seguir varios pasos para generar las dos claves que utiliza, publica y de sitio.

../_images/1.png ../_images/8.png ../_images/18.png

Finalmente acaba la instalación y nos recomienda no permitir la escritura en los binarios y la base de datos de Tripwire, además de leer el archivo de ayuda. En este caso no tenemos la posibilidad de guardar las claves en un archivo extenso pero tenemos en cuenta que sería lo idoneo.

../_images/19.png

Lo siguiente será configurar el archivo de políticas. Tenemos una plantilla en /etc/tripwire/twpol.txt, por lo que la usaremos eliminando los archivos que no nos interese que sean seguidos por tripwire. En concreto eliminaremos algunos elementos de la carpeta /root que no tenemos y el directorio /proc ya que cambiará frecuentemente.

Una vez elegidos los directorios hay que instalar este archivo con la orden twadmin.

# twadmin -m P /etc/tripwire/twpol.txt

Se contruye la base de datos de Tripwire.

# tripwire -m i

Habrá que realizar esto hasta que no nos avise de ningún error, por ejemplo, si hay algún directorio o archivo que no tengamos en nuestro sistema.

Ahora tripwire estará configurado correctamente. Podemos comprobar si el sistema ha sido alterado con:

# tripwire -m c

Como no deseamos hacer manualmente esto añadimos al cron diario esta acción e indicamos que se reciba por email. Pondremos en /etc/cron.daily/tripwire un archivo con el contenido siguiente.

/usr/sbin/tripwire -m c | mail "carlos@cactus.rufian.eu, rufian@cactus.rufian.eu"

Ahora que hemos acabado con la configuración eliminaremos los archivos cifrados /etc/tripwire/tw.cfg y /etc/tripwire/tw.pol ya que no los necesitaremos por ahora.

rm /etc/tripwire/twcfg.txt /etc/tripwire/twpol.txt

Los informes que recibimos tienen la pinta siguiente, en este caso hay una gran cantidad de cambios.

Open Source Tripwire(R) 2.4.1 Integrity Check Report

Report generated by:          root
Report created on:            Thu May 23 21:39:47 2013
Database last updated on:     Never

===============================================================================
Report Summary:
===============================================================================

Host name:                    cactus
Host IP address:              192.168.1.222
Host ID:                      None
Policy file used:             /etc/tripwire/tw.pol
Configuration file used:      /etc/tripwire/tw.cfg
Database file used:           /var/lib/tripwire/cactus.twd
Command line used:            tripwire -m c

===============================================================================
Rule Summary:
===============================================================================

-------------------------------------------------------------------------------
Section: Unix File System
-------------------------------------------------------------------------------

Rule Name                       Severity Level    Added    Removed  Modified
---------                       --------------    -----    -------  --------
Invariant Directories           66                0        0        0
Tripwire Data Files             100               0        0        0
Other binaries                  66                0        0        0
Tripwire Binaries               100               0        0        0
* Other libraries               66                28       0        2
Root file-system executables    100               0        0        0
* System boot changes           100               2        2        42
Root file-system libraries      100               0        0        0
(/lib)
* Critical system boot files    100               1        0        1
* Other configuration files     66                226      4        31
(/etc)
* Boot Scripts                    100               8        0        11
* Security Control                66                0        0        2
* Root config files               100               703      267      18
* Devices & Kernel information    100               3        3        5
(/dev)

Total objects scanned:  17516
Total violations found:  1359

===============================================================================
Object Summary:
===============================================================================

-------------------------------------------------------------------------------
# Section: Unix File System
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
Rule Name: Other libraries (/usr/lib)
Severity Level: 66
-------------------------------------------------------------------------------

Added:
"/usr/lib/perl5/List"
"/usr/lib/perl5/List/MoreUtils.pm"
"/usr/lib/perl5/auto/List"
"/usr/lib/perl5/auto/List/MoreUtils"
"/usr/lib/perl5/auto/List/MoreUtils/MoreUtils.so"
"/usr/lib/perl5/auto/List/MoreUtils/MoreUtils.bs"
"/usr/lib/perl5/auto/Params"
"/usr/lib/perl5/auto/Params/Validate"
"/usr/lib/perl5/auto/Params/Validate/Validate.so"
"/usr/lib/perl5/auto/Params/Validate/Validate.bs"
"/usr/lib/perl5/auto/DateTime"
"/usr/lib/perl5/auto/DateTime/DateTime.so"
"/usr/lib/perl5/auto/DateTime/DateTime.bs"
"/usr/lib/perl5/DateTimePPExtra.pm"
"/usr/lib/perl5/Params"
"/usr/lib/perl5/Params/Validate.pm"
"/usr/lib/perl5/Params/ValidatePP.pm"
"/usr/lib/perl5/Params/ValidateXS.pm"
"/usr/lib/perl5/DateTime.pm"
"/usr/lib/perl5/DateTime"
"/usr/lib/perl5/DateTime/Infinite.pm"
"/usr/lib/perl5/DateTime/Helpers.pm"
"/usr/lib/perl5/DateTime/LeapSecond.pm"
"/usr/lib/perl5/DateTime/Duration.pm"
"/usr/lib/perl5/Attribute"
"/usr/lib/perl5/Attribute/Params"
"/usr/lib/perl5/Attribute/Params/Validate.pm"
"/usr/lib/perl5/DateTimePP.pm"

Modified:
"/usr/lib/perl5"

...

Contenidos

Tema anterior

Copias de seguridad

Esta página