Skip to content

Instantly share code, notes, and snippets.

@HacKanCuBa
Created November 10, 2017 19:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HacKanCuBa/96abf0254de9caa1476ef3daee0ec812 to your computer and use it in GitHub Desktop.
Save HacKanCuBa/96abf0254de9caa1476ef3daee0ec812 to your computer and use it in GitHub Desktop.
#!/bin/bash
################################################################################
#
# ~~~~ Emergency Lockdown ~~~~
# Forces a lockdown on the system: kills the keys and luks headers,
# then reboots.
# Copyright (C) 2015 by HacKan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
#
# Version: 1.16 (tested)
# Add this to the sudoers file or as a new file:
# visudo -sf /etc/sudoers.d/emergencylockdown
# %USERGROUP ALL = NOPASSWD: /usr/bin/emergencylockdown
# Where %USERGROUP is your user group, i.e.: %hackan
# so that you can execute this script as a command without password
# be careful!
#
################################################################################
trap ctrl_c INT
declare -r true=1
declare -r false=
# Config
# Label of the device holding your keys
# (as in /dev/disk/by-label/<device_label>)
declare -r KEY_LABEL="<your_pendrive_label>"
# Enable or disable debug mode, which allows to do a dry-run
DEBUG=$true # DISABLE DEBUG MODE ON PRODUCTION!
# <>
function ctrl_c() {
[ "${DEBUG}" ] && exit 1 || echo "ah ah ah! you didn't say the magic word!"
}
function get_rand_str() {
# Returns a 7 char random hex string (not crypto safe!)
# Use: STR="$(get_rand_str)"
echo $RANDOM | md5sum | head -c 7
}
function e_debug() {
if [ "${DEBUG}" ]; then
echo "DEBUG### $@"
fi
}
function destroy_file() {
# Destroys a file using shred
local FILE="$1"
shred -fzn 5 "${FILE}" > /dev/null 2>&1
if [ $? -ne 0 ]; then
# Repeat. Sometimes, shred fails the first time, for unknow reasons
# but goes well the second time.
# However I'm not looping it until it works, it's not that important
# and I must hurry!
shred -fzn 5 "${FILE}" > /dev/null 2>&1
fi
}
function fake_key() {
local KEY="$1"
dd status=none if=/dev/urandom of="${KEY}" bs=1024 count=1
}
if [ "$(whoami)" = "root" ]; then
declare -r TMPFS_MOUNT="/root/$(get_rand_str)"
declare -ri TMPFS_SIZE=$(( 25 + ($RANDOM % 100) ))
declare -r HEADERFNAME="$(get_rand_str)"
if [ "${DEBUG}" ]; then
echo "Emergency lockdown taking place, stand by... DEBUG MODE" | wall
else
echo "Emergency lockdown taking place, stand by..." | wall
logger "Emergency lockdown taking place, stand by..."
fi
# List of LUKS devices
declare -ra LUKSDEV=( $(lsblk --fs -rno NAME,FSTYPE | grep crypto_LUKS | cut -f1 -d " ") )
echo "Devices to lockdown (${#LUKSDEV[@]}): ${LUKSDEV[@]}"
echo -en "Working..."
# Overwrites header + keys sequentially, increasing size of the data overwritten.
# Each iteration adds 1MB of data overwritten
# Uses the luks header size as blocksize
# WARNING: makes the device COMPLETELY UNRECOVERABLE, even having luks header backup
#for i in {1..10}; do
# for SDXX in "${LUKSDEV[@]}"; do
# DEV="/dev/${SDXX}"
# SIZE_LUKSHEAD=$(cryptsetup luksDump "${DEV}" | grep "Payload offset:" | cut -f2)
# #echo $DEV
# #echo $SIZE_LUKSHEAD
# dd status=none if=/dev/urandom of="${DEV}" bs=${SIZE_LUKSHEAD} count=$(( ${i} * 1048576 / ${SIZE_LUKSHEAD} ))
# #echo "$(( ${i} * 1048576 / ${SIZE_LUKSHEAD} ))"
# sync
# done
# echo -en "."
#done
#echo
# For a less overkill aproach, lets: backup header to get size,
# overwrite dev, destroy header
e_debug "TMPFS_SIZE=${TMPFS_SIZE}M"
e_debug "TMPFS_MOUNT=${TMPFS_MOUNT}"
e_debug "Header file: ${TMPFS_MOUNT}/${HEADERFNAME}"
mkdir -p "${TMPFS_MOUNT}"
mount -t tmpfs -o size="${TMPFS_SIZE}M" tmpfs "${TMPFS_MOUNT}"
# Even if the mount fails for some reason, we can still write files there
for i in {1..5}; do
for SDXX in "${LUKSDEV[@]}"; do
DEV="/dev/${SDXX}"
e_debug "DEV=${DEV}"
# Get header file
cryptsetup --batch-mode luksHeaderBackup "${DEV}" --header-backup-file "${TMPFS_MOUNT}/${HEADERFNAME}" > /dev/null 2>&1
# Calculate sizes
SIZE_HEADER=$(du -b "${TMPFS_MOUNT}/${HEADERFNAME}" | cut -f1)
SIZE_LUKSHEAD=$(cryptsetup --batch-mode luksDump "${DEV}" | grep "Payload offset:" | cut -f2)
e_debug "SIZE_HEADER=$SIZE_HEADER"
e_debug "SIZE_LUKSHEAD=$SIZE_LUKSHEAD"
e_debug "COUNT=$(( ${SIZE_HEADER} / ${SIZE_LUKSHEAD} ))"
# Destroy device header
DEVDD=
if [ "${DEBUG}" ]; then
DEVDD="${SDXX}"
else
DEVDD="${DEV}"
fi
dd status=none if=/dev/urandom of="${DEVDD}" bs=${SIZE_LUKSHEAD} count=$(( ${SIZE_HEADER} / ${SIZE_LUKSHEAD} ))
# Just in case the division operation isnt integer
dd status=none if=/dev/urandom of="${DEVDD}" bs=${SIZE_HEADER} count=1
# Destroy header file
destroy_file "${TMPFS_MOUNT}/${HEADERFNAME}"
# Repeat over the same file
sync
done
echo -en "."
done
# Remove header file
shred -ufzn 1 "${TMPFS_MOUNT}/${HEADERFNAME}"
# Overwrite
DELFNAME="$(get_rand_str)"
e_debug "DELFNAME=${DELFNAME}"
# Instead of filling the device, I set a size in case the tmpfs mount failed
dd status=none if=/dev/zero of="${TMPFS_MOUNT}/${DELFNAME}" bs=4096 count=$(( ${TMPFS_SIZE} * 256 ))
destroy_file "${TMPFS_MOUNT}/${DELFNAME}"
umount "${TMPFS_MOUNT}"
rm -rf "${TMPFS_MOUNT}"
echo "All done with devices, now destroy the keys"
# Try to destroy the keys, just in case
declare -r KEY_DEV="/dev/disk/by-label/${KEY_LABEL}"
# Verify that we have an actual device here
if [ -b "${KEY_DEV}" ]; then
# Mount device
KEY_MOUNT=
if [ "$(mount | grep ${KEY_LABEL})" ]; then
# Already mounted, get directory
KEY_MOUNT="$(mount | grep ${KEY_LABEL} | cut -f3 -d ' ')"
else
# Make dir and mount
KEY_MOUNT="/root/$(get_rand_str)"
mkdir -p "${KEY_MOUNT}"
mount -t auto "${KEY_DEV}" "${KEY_MOUNT}"
fi
e_debug "KEY_MOUNT=${KEY_MOUNT}"
# Note: dont use " with the ls command!!
for KEYFILE in $(ls ${KEY_MOUNT}/*.key "${KEY_MOUNT}/.hidden"); do
e_debug "KEYFILE=${KEYFILE}"
if [ "${DEBUG}" ]; then
e_debug "shred -ufzn 5 ${KEYFILE} ..."
else
destroy_file "${KEYFILE}"
fake_key "${KEYFILE}"
fi
done
umount "${KEY_MOUNT}"
rmdir "${KEY_MOUNT}" > /dev/null 2>&1
else
echo "Key device ${KEY_DEV} not found, skipping..."
fi
echo "All done"
echo "Good bye :)" | wall
e_debug "Remember to disable debug mode!!"
[ "${DEBUG}" ] && { echo "Emergency lockdown DEBUG: poweroff" | wall; } || poweroff
else
# Try to rerun
e_debug "Reruning: sudo $0"
sudo $0
exit
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment