Blog

Scripts antes de suspender: luksClose

Scripts antes de suspender: luksClose

Suspendo el ordenador en lugar de apagarlo. Tengo un disco cifrado (con LUKS) y quería cerrarlo (luksClose) automáticamente antes de que entre la suspensión.

Es mayormente paranoia, pero me quedé algo inquieto leyendo esto:

Hi,
today, the German news site heise leaked a list of password hacking software, that the German police buys and is particular happy with. One of those tools is the «Elcomsoft Forensic Disk Decryptor» promising access to BitLocker, PGP and TrueCrypt volumes:

http://www.elcomsoft.co.uk/efdd.html

What they say about their method is only that it «acquires protection keys from RAM dumps, hibernation files». Now I wonder, how does this attack work exactly and how vulnerable is cryptsetup against it in a linux environment?

Existe software que permite extraer la clave que reside en RAM mientras el disco esté abierto. Sería posible obtener la RAM con un cold boot attack, por ejemplo. Con luksClose o luksSuspend nos aseguramos de que desaparecen de memoria:

I tested it with the AES key finder (cold boot utilities) on memory image from suspended virtual machine (plus you need to find dmcrypt crypt structure with plain key). After luksClose and luksSuspend all previously visible keys in RAM must disappear.

Creo un fichero /usr/lib/systemd/system-sleep/my_sleep_tasks.sh, y le damos permisos de ejecución:

#!/bin/sh

goodsound="beep -f 2000"
badsound="beep -f 400 -l 3000"

case $1/$2 in
  pre/*)
    echo "Going to $2..."
    closeluks && eval "$goodsound" || eval "$badsound"
    ;;
  post/*)
    echo "Waking up from $2..."
    beep -f 1000
    #{ sleep 10; gnome-randr --output DP-2 --auto; beep; } &
    ;;
esac

Antes y después de suspender se llama a los scripts que tengamos en /usr/lib/systemd/system-sleep con los parámetros pre * o post *, respectivamente. He creado un comando closeluks en /usr/local/bin/closeluks. Si falla hago sonar la bocina interna del PC (que por cierto, muchos ordenadores modernos ya no tienen). Puede ocurrir bien porque el ejecutable se haya borrado/renombrado/le falten permisos de ejecución, bien por fallo interno). Me he ahorrado el if, hago shortcircuit con el operador ABD && y OR ||. He puesto sonidos diferentes (con el comando beep) para acierto o fallo.

#!/bin/sh
modprobe pcspkr
device_mapper_drive="encrypteddrive"
mount_point="/mnt/encrypted"

good="echo good"
bad="echo bad"
nothingdone="echo nothingdone"

encrypted_drives_count=$(dmsetup ls --target crypt | wc -l)
echo $encrypted_drives_count


if [[ $encrypted_drives_count -eq 0 ]]; then
        eval "$nothingdone"
        exit 0
elif [[ $encrypted_drives_count -eq 1 ]] && dmsetup info $device_mapper_drive ; then
        umount $mount_point
        if cryptsetup luksClose $device_mapper_drive; then
                eval "$good"
                exit 0
        fi
fi

eval "$bad"
exit 1

closeluks mira los device mapper de tipo cifrado. Si no hay ninguno, no hay nada que hacer. Si hay uno y coincide con el nombre especificado en la variable device_mapper_drive, se intenta desmontar y cerrar con luksClose. Cualquier otro caso (si hay uno y ha fallado el comando de desmontar o cerrar, o si hay más de uno) es un error.

Podemos ahorrarnos la llamada a modprobe pcspk creando un fichero /etc/modules-load.d/pcspkr.conf que simplemente contenga:

[j@localhost ~]$ cat /etc/modules-load.d/pcspkr.conf
pcspkr


Podemos también llamar al script ante una señal de DBus. Por ejemplo, cuando bloqueamos la pantalla. Creamos /usr/local/bin/lock_listener

#!/bin/bash

goodsound="beep -f 2000"
badsound="beep -f 400 -l 3000"

dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver'" |
  while read x; do
    case "$x" in
      *"boolean true"*) sudo closeluks && eval "$goodsound" || eval "$badsound";;
      *"boolean false"*) beep -f 2000;;
    esac
  done

Para que funcione sudo closeluks automáticamente sin introducir contraseñs debemos configurar con sudo visudo:

<usuario>     ALL = NOPASSWD:/usr/local/bin/closeluks

Creamos a continuación un fichero ~/.config/autostart/lock_listener.desktop para que arranque al iniciar sesión:

[Desktop Entry]
Encoding=UTF-8
Exec=/usr/local/bin/lock_listener &
Name=myscript
Comment=Lock screen dbus listener
Terminal=false
OnlyShowIn=GNOME
Type=Application
StartupNotify=false
X-GNOME-Autostart-enabled=true

He puesto los comandos de beep fuera de /usr/local/bin/closeluks porque beep no deja ejecutar con sudo, debido a una vulnerabilidad:

[j@localhost ~]$ sudo beep
beep: Error: Running as root under sudo, which is not supported for security reasons.
beep: Error: Set up permissions for the pcspkr evdev device file and run as non-root user instead.

Otra opción es utilizar los shortcuts de GNOME. Podemos quitar Super+L para lock screen y asignarlo a un script propio:

/usr/local/bin/lock_shortcut contiene:

#!/bin/bash
goodsound="beep -f 2000"
badsound="beep -f 400 -l 3000"
sudo closeluks && 
        eval "$goodsound" &&
        dbus-send --type=method_call --dest=org.gnome.ScreenSaver \
                 /org/gnome/ScreenSaver org.gnome.ScreenSaver.Lock
        || eval "$badsound"

La verdad es que me gusta más así, porque sólo se bloquea si la llamada a closeluks ha funcionado correctamente.