lunes, 17 de diciembre de 2012

Espiando la terminal

Algo que recientemente me puse a investigar fue sobre cómo espiar la terminal de otro usuario conectado al mismo servidor y ver que es lo que está haciendo en tiempo real. Así podría monitorear las acciones de los administradores u otros usuarios, saber si sospechan de mi presencia y poder reaccionar inmediatamente.

En este post hablaré de algunas aproximaciones para conseguir esto. Como imaginarán todas requieren de permisos de "root" en el sistema.

Empecemos...

El .bash_history

La primera aproximación fue emplear el fichero ".bash_history" del usuario en cuestión. Este fichero se encuentra en el home de cada usuario y guarda un historial de los comandos ejecutados por el usuario durante su sesión en el sistema. En teoría debía ser tan fácil como:

# tail -f /home/usuario/.bash_history

Sin embargo descarté esta opción debido a que los comandos no son enviados al ".bash_history" sino hasta el final de la sesión del usuario por lo que el monitoreo no sería en tiempo real y no serviría de mucho para mi propósito. No obstante este fichero sigue siendo una buena opción para obtener información detallada de lo que hizo un usuario en su sesión anterior.

Actualización 29/04/2014: Ignacio Martin nos deja en los comentarios una forma de hacer viable este método en tiempo real y con soporte para múltiples sesiones.

Tracear bash

La siguiente opción, sugerida por un amigo, fue "tracear" el proceso "bash" del usuario a espiar y observar en las llamadas a "read" lo que leía el proceso de la entrada estándar, osea los comandos que escribe el usuario. (sí, mi amigo es muy h4x0r)

El comando para esto es "strace". Y usarlo es tan sencillo como pasarle por parámetro el PID del proceso a tracear.

# strace -p PID

Pero... ¿Y cómo obtengo el PID del bash de otro usuario?

Una opción es esta:

1. Con "who" observar la lista de usuarios conectados y el nombre de su terminal asociada.

# who

2. Luego listar los procesos filtrando por el nombre de la terminal.

# ps axu | grep "pts/2"

3. Finalmente buscar en la lista el proceso "/bin/bash" y su PID asociado.

Traceando la terminal de otro usuario.
Nota: Si eres un troll de aquellos y quieres botar al usuario del sistema, ahora que tienes el PID de su bash, solo tienes que ejecutar esto:

# kill -9 PID

El problema con esta opción es que "strace" muestra demasiada información sobre lo que está haciendo internamente el proceso bash y no deja ver con claridad los comandos que escribe el usuario. Seguramente con algunos parámetros y filtrando un poco se pueda conseguir algo más de claridad pero decidí buscar más alternativas.

La pseudoterminal

Una terminal es la interfaz más básica para interactuar con el sistema. Consta de una entrada estandar y una salida estandar que normalmente son el teclado y el monitor conectados directamente al equipo. Sin embargo una sola terminal puede resultar insuficiente y por ello Linux hace uso de hasta siete "terminales virtuales" que van desde tty1 hasta tty7. Podemos acceder a estas terminales virtuales presionando [CTRL] + [ALT] + [FX] (siendo X el número de la terminal. La interfaz gráfica usualmente corre en la terminal virtual tty7. Además de ello existen las "pseudoterminales" que se asocian a programas como gnome-terminal, konsole, ssh, screen, etc. Tanto las pseudoterminales como las terminales virtuales son abstracciones de la entrada/salida para el interprete de comandos y linux las maneja a través de ficheros de dispositivo ubicados en el directorio "/dev".

Por ejemplo, si tenemos una terminal tty, el fichero asociado estará en "/dev/ttyx" y si tenemos una terminal pts (pseudoterminal), el fichero estará en "/dev/pts/x" siendo "x", en ambos casos, el número de la terminal.

Como ya se dijo, este fichero representa un dispositivo virtual que viene a ser la entrada y salida estándar de la terminal asociada. En otras palabras lo que se escribe en este fichero va a la salida estandar, es decir, se muestra en la terminal y lo que se lee de este fichero es la entrada estandar, osea, lo que escribe el usuario en la terminal.

Como pueden suponer si leemos este fichero podremos ver lo que el usuario esta tecleando en su terminal. Suponiendo que el usuario tiene la terminal "pts/2", bastaría con ejecutar esto:

# cat /dev/pts/2

Sin embargo hay un serio inconveniente. Sucede que ahora tendremos dos procesos compitiendo por leer la entrada estándar de la pseudoterminal. Por un lado la consola del usuario y por el otro nuestro cat. En consecuencia observaremos que parte de lo que escribe el usuario se mostrará en nuestra pantalla y otra parte en la de él. Así que el usuario no podrá trabajar normalmente y nosotros tampoco conseguiremos nuestro objetivo por lo que también descartaré esta opción.

El comando "script"

Esta es hasta ahora la mejor opción que encontré.

El comando "script" enviá a un fichero toda la actividad que se realiza en la terminal, es decir cada tecla que se pulsa y cada carácter que se muestra en pantalla. Luego solo tenemos que revisar el archivo que genera para ver que está haciendo el usuario.

El modo de empleo es el siguiente:

# script -f -q /tmp/archivo

El problema en este caso es conseguir que el usuario en cuestión ejecute el comando anterior sin percatarse para luego revisar su actividad en "/tmp/archivo". Para resolver este problema se me ocurrió que podía reemplazar un comando de uso frecuente como "ls" por un script en bash que ejecute el comando script además de llamar al comando "ls" original.

El script en bash me quedó así:

ls.sh
#!/bin/bash

cmd="/bin/ls_old";
pts=`tty | cut -d / -f 4`;
act=`ps axu | grep "pts/$pts" | grep "bash -i" | sed "/grep/d"`;

$cmd $*;

if [ "$act" == "" ]; then
 script -f -q /tmp/$pts;
 rm -f /tmp/$pts;
fi

Por el momento solo funciona con pseudoterminales (pts). La configuración es sencilla:

1. Renombrar el comando "ls"

# mv /bin/ls /bin/ls_old

2. Copiar el script en "/bin/ls"

# cp ls.sh /bin/ls

3. Asignar permisos de ejecución al script

# chmod +x /bin/ls

Luego cuando un usuario ejecute el comando "ls" en realidad llamará al script bash y este hará la llamada al comando "script". A partir de ese momento podremos ver la actividad del usuario en "/tmp/PTS" (donde PTS es el número de pseudoterminal) así:

# tail -f /tmp/PTS

Ya para terminar, también estuve investigando sobre como ejecutar algo en la terminal de otro usuario y así meterlo dentro de una sesión de "script" sin necesidad de reemplazar ningún binario del sistema, que luego uno se olvida y también queda metido en una sesión "script" xD. Pero seguro ya hablaré de eso en otro post...

Un saludo.

4 comentarios:

  1. Leyendo este artículo recorde otro de Security By Default sobre este mismo tema:

    http://www.securitybydefault.com/2012/11/sudosh2-registra-comandos-de-la-shell.html

    También comentar que además de rootsh,sudosh,sudosh2,etc existen otras como snoopy logger

    ResponderEliminar
  2. Excelente, gracias por el aporte!

    Un saludo.

    ResponderEliminar
  3. Repasando las diferentes opciones que comentabas al principio de este post, estuve informandome un poco más sobre la que pienso que es la idonea para el tema que planteabas.
    Bajo mi punto de vista me quedo con la primera opción que planteabas es decir con la del history aunque con algunas modificaciones al de por defecto.

    En el de por defecto tenemos cuatro temas a tratar:

    -El primero que no se guardan los comandos en real time en el fichero .bash_history sino que tenemos que esperar a cerrar la sesión para tal efecto.
    -El segundo viene con las sesiones simúltaneas, es decir tenemos dos conexiones simultaneas con root a la misma máquina, ¿que pasa con los comandos ejecutados?, ¿se pueden llegar a sobrescribir unos con otros?
    -La tercera es para otros tipos de terminales virtuales como puede ser screen.
    -La cuarta es disponer del timestamp de todos los comandos, cosa que no viene nada mal para saber que día y a que hora se ejecutó un comando.

    Bueno todas estas últimas las he solucionado con el siguiente script el cuál se cargará al inicio de todos los perfiles de usuario de la máquina.

    [root@server ~]# more /etc/profile.d/user.sh
    # Enable timestamp logging in bash commands history
    HISTSIZE=1000
    HISTFILESIZE=40000
    HISTTIMEFORMAT="[%F %T %Z] "
    export HISTSIZE HISTFILESIZE HISTTIMEFORMAT
    # Save your terminal commands in bash history in realtime
    shopt -s histappend ; PROMPT_COMMAND="history -a;$PROMPT_COMMAND"

    Con el comando shopt tendriamos garantizado que no se sobreescriben comandos cuando tienes multiples sesiones simultáneas y con el PROMPT_COMMAND garantizamos que los comandos se guardan en real time.

    Espero que esto te sea de ayuda ya que de alguna forma sería una forma nativa que ofrece la propia shell en este caso bash (comentar que shopt solo es valido para bash y sh, para zsh tienes setopt)

    Referencias:

    http://www.commandlinefu.com/commands/view/8555/save-your-terminal-commands-in-bash-history-in-real-time
    http://linuxcommando.blogspot.com.es/2007/11/keeping-command-history-across-multiple.html
    http://unix.stackexchange.com/questions/99325/automatically-save-bash-command-history-in-screen-session
    http://stackoverflow.com/questions/5510217/using-screen-command-in-linux-does-not-allow-command-history-to-be-logged

    ResponderEliminar
  4. Hola Ignacio, vaya tío... tu sí ah! Muchas gracias... lo menos que puedo hacer es poner una actualización haciendo referencia a tu comentario que seguramente nos ayudará a más de uno.

    P.D.: Acabo de revisar tu perfil para ver si tenías un blog o web para linkear y vaya sorpresa que me he llevado! xD

    Un saludo.

    ResponderEliminar