partitionhider

Dangerous and risky bash scripts to conceal and recover partitions using literal writes to MBR
git clone git://git.defalsify.org/partitionhider.git
Log | Files | Refs | README | LICENSE

commit cbe241c3962e257190993667494e239c132065ea
parent 9f2436f758635d4ebb83ba250d6cbd70a059b781
Author: nolash <dev@holbrook.no>
Date:   Fri, 20 Apr 2018 05:58:52 +0200

Initial commit

Diffstat:
MREADME.md | 7++++++-
Adraft/secretluks.txt | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ar.sh | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aw.sh | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 523 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md @@ -1,2 +1,7 @@ # partitionhider -Studies on how to encrypt and store partitions with plausible deniability + +***WARNING WARNING WARNING*** + +**The contents of this repository are programs which mess around with raw partitions and the MBR. They are experimental, so be sure you know what you are doing when you attempt to use them. Author assumes NO liability for their usage** + +How to hide data on a block device while hiding that you are hiding the data diff --git a/draft/secretluks.txt b/draft/secretluks.txt @@ -0,0 +1,243 @@ +before start: + +1. be sure to overwrite the whole area with /dev/urandom + +--- + +1: Hiding a crypt partition + +Example: 8gb usb drive. + +(find a drive where the size doesn't say on it) + +Partition the visible space to a plausible size as if fully formatted (half). + +The idea is that on normal inspection, the disk will look fully utilized, for example so: + +# fdisk -l /dev/sdc +Disk /dev/sdc: 7.5 GiB, 8004304896 bytes, 15633408 sectors +Units: sectors of 1 * 512 = 512 bytes +Sector size (logical/physical): 512 bytes / 512 bytes +I/O size (minimum/optimal): 512 bytes / 512 bytes +Disklabel type: dos +Disk identifier: 0x2f95ed70 + +Device Boot Start End Sectors Size Id Type +/dev/sdc1 2048 7816704 7814657 3.7G b W95 FAT32 +/dev/sdc2 7817216 15633408 7816192 3.7G 83 Linux + +--- + +Now let's prepare the partitions: + +$ mkfs.ext -F32 /dev/sdc1 +$ cryptsetup luksFormat /dev/sdc2 +$ cryptsetup open /dev/sdc2 gone +$ mkfs.ext4 /dev/mapper/gone +$ mount /dev/mapper/gone /mnt/point +$ echo xyzzy > /mnt/point/foo.txt +$ umount /mnt/point +$ cryptsetup close gone + +--- + +In the MBR the two partition entries are 16 bytes at 0x01be and 0x01ce respectively. We want to backup the 16 bytes somewhere and delete them from the MBR. We can check the data as so: + +hexdump -e '16/1 "%02x " "\n"' -s0x01ce -n16 /dev/sdc +00 72 49 fe 83 b1 ef fc 00 48 77 00 00 44 77 00 + +Here we look for the first byte 00 means inactive partition, and the fifth byte 83 (linux partition type). Last four bytes is the partition size 0xc53b7700 (little endian) = 7814085. Looks good! + +The only thing being used in the first 2048 sectors is the first for the MBR (fdisk by default reserves this boundary). We can write zero to all the others, and still the disk will work. Let's try: + +$ dd if=/dev/zero of=/dev/sdc seek=1 bs=512 count=2047 +... +$ hexdump -s0x01b0 -n`calc 2048*512` /dev/sdc +00001b0 00a4 0002 0000 0000 ed70 2f95 0000 2100 +00001c0 0003 690b fe77 0800 0000 3e01 0077 7200 +00001d0 fe49 b183 fcef 4800 0077 3bc5 0077 0000 +00001e0 0000 0000 0000 0000 0000 0000 0000 0000 +00001f0 0000 0000 0000 0000 0000 0000 0000 aa55 +0000200 0000 0000 0000 0000 0000 0000 0000 0000 +* +0100000 58eb 6d90 666b 2e73 6166 0074 0802 0020 +... + +(the * means same data in the interval) + +We can still mount and write data: + +$ mount /dev/sdc1 /mnt/point +$ dd if=/dev/urandom of=/mnt/point/foo bs=1024 count=1024 +$ hexdump /mnt/tmp/foo | tail -n2 +00ffff0 b1f4 175d 0325 2708 a2a3 b9e7 d153 4059 +0100000 +$ umount /mnt/point + +--- + +Let's hide the partition data in the gap: + +$ dd if=/dev/sdc of=/dev/sdc skip=462 seek=1300 bs=1 count=16 + +$ hexdump -e'16/1 "%02x "' -n16 -s1300 /dev/sdc +//00 72 49 fe 83 b1 ef fc 00 48 77 00 c5 3b 77 00 +00 72 49 fe 83 b1 ef fc 00 48 77 00 00 44 77 00 + +or with diff to be sure: + +$ diff <(hexdump -e'16/1 "%x"' -n16 -s0x01ce /dev/sdc) <(hexdump -e'16/1 "%x"' -n16 -s1300 /dev/sdc) + +-- + +the magic moment. Overwrite the partition entry with zeros: + +$ dd if=/dev/zero of=/dev/sdc bs=1 count=16 seek=462 + +$ hexdump -e'16/1 "%02x " "\n"' -n16 -s462 /dev/sdc +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +$ fdisk /dev/sdc -l +... +Device Boot Start End Sectors Size Id Type +/dev/sdc1 2048 7816704 7814657 3.7G b W95 FAT32 + +(lsblk may still show the partition, dunno why, remove and insert medium and it will be updated) + +-- + +More magic: restore: + +$ dd if=/dev/sdc of=/dev/sdc bs=1 count=16 seek=462 skip=1300 + +$ fdisk /dev/sdc -l + +(lsblk shows straight away) + +=== + +2. cryptpart + +$ hexdump -s`calc 7817216*512` -n32 -e'128/1 "%_c" "\n"' /dev/sdc +LUKS272276\0001aes\0\0\0\0\0 + +of course this is a problem, because the boundary of partition it's pretty obvious. Also, any full disk search for the LUKS identifier will show a valid luks partition. + +--- + +let's start over, but this time not use the whole disk: + +# fdisk -l /dev/sdc +Disk /dev/sdc: 7.5 GiB, 8004304896 bytes, 15633408 sectors +Units: sectors of 1 * 512 = 512 bytes +Sector size (logical/physical): 512 bytes / 512 bytes +I/O size (minimum/optimal): 512 bytes / 512 bytes +Disklabel type: dos +Disk identifier: 0x2f95ed70 + +Device Boot Start End Sectors Size Id Type +/dev/sdc1 2048 7816704 7814657 3.7G b W95 FAT32 +/dev/sdc2 7817216 15631300 7814085 3.7G 83 Linux + +---- + +Notice that the last partition doesn't extend to the end of the disk. Still, the size is reported as 3.7G. Unless sector count is scrutinized, this will probably look convincing. + +We are short 2107 sectors, or 1078784 bytes. Why did we choose this number? + +1) luksheader = 1052672 bytes = 2056 * 512 sectors +2) we also need one extra sector for encrypting of luks header +3) to remember where the data resides, we pick a number easy to remember, like a PIN. In this case we pick the number 13, and choose the offset where there's enough room for 1 and 2, and fill the rest with 0's. Since one magnitude lower, 15633130, only would yield 277 sectors = 141824 bytes, that's too little. + +--- + +change to a tmpfs and backup the header + +$ mkdir /dev/shm/foo +# mount /dev/shm/foo /mnt/point -t tmpfs + +$ cryptsetup luksHeaderBackup /dev/sdc2 --header-backup-file crypt.bak + +we may verify that it matches: + +$ diff <(hexdump -e'"%x"' luks.bak) <(hexdump -e'"%x"' -s`calc 7817216*512` -n1052672 /dev/sdc) + +--- + +ccrypt the backup. This will add 32 bytes to the start of the file. + +$ ls luks.bak* +-r-------- 1 root root 1052672 Jan 25 03:20 luks.bak + +becomes: + +$ ls luks.bak* +-r-------- 1 root root 1052704 Jan 25 03:41 luks.bak.cpt + +--- + +write this data to some address in the unpartitioned space, use an easy to remember number, for example next free sector you can use 13 as high order numbers. In this case 7816704 is the last used sector, so 13000000 is an obvious candidate. NOTE don't make this too easy to guess, but not too hard either; if you forget it, your data is gone, gone, gone. + +$ dd if=luks.bak.cpt of=/dev/sdc bs=512 seek=15631300 +2056+1 records in +2056+1 records out +1052704 bytes (1.1 MB, 1.0 MiB) copied, 0.313062 s, 3.4 MB/s + +You can verify that the data written is correct by comparing the first 1024 bytes of the outputs 8003225600 = 15631300 * 512 + +$ hexdump -e'32/1 "%x" "\n"' -n1024 tmp/luks.bak.cpt +$ hexdump -e'32/1 "%x" "\n"' -s8003225600 -n1024 /dev/sdc +($ hexdump -e'32/1 "%x" "\n"' -s`calc 15631300*512` -n1024 /dev/sdc + +diff <(hexdump -e'32/1 "%x"' -n1024 tmp/luks.bak.cpt) <(hexdump -e'32/1 "%x"' -s`calc 15631300*512` -n1024 /dev/sdc) + +--- + +Overwrite the existing luks header with garbage: + +$ dd if=/dev/urandom of=/dev/sdc bs=512 count=2056 seek=7817216 + +Check that it's gone: + +$ hexdump -s`calc 7817216*512` -n16 -e'128/1 "%_c" "\n"' /dev/sdc +XV216274271211@Z265324226270&210376D + +if still there, remove partition entry again + +--- + +Bring it back: + +write it back and decrypt: + +$ dd if=/dev/sdc of=luksrestored.cpt bs=512 count=2057 skip=15631300 +$ ccrypt -d luksrestored.cpt + +NB NB! The file will now be 1053152, ONE SECTOR BIGGER! If use dd to write back, specify bs=512 and count=2056 +Safer is restore from cryptsetup, it will only use the relevant bytes: + +we can check this by editing adding something at 0x101000 of the file and see if we find it after. + +$ cryptsetup luksHeaderRestore /dev/sdc2 --header-backup-file luksrestored + +(Bring back partition) + +--- + +should be able to: + +$ cryptsetup open /dev/sdc2 back +$ mount /dev/mapper/back /mnt/point +$ echo /mnt/point/foo.txt +xyzzy + +--- + +May still be conspicuous that only half of disk is formatted, but: + +- it's plauisbly deniable that the random data is indeed random. +- it's not TOTALLY unreasonable to have unpartitioned space for later + +--- + +There's nothing wrong with having the encrypted luks backup on a different drive etc. diff --git a/r.sh b/r.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +which ccrypt 2> /dev/null || exit 2 +which blockdev 2> /dev/null || exit 2 +which hexdump 2> /dev/null || exit 2 + +DEV=$1 +PART=$2 + +tmpdir=`mktemp -d` +if [ $? != 0 ]; then + exit 3 +fi + +mbroffset=$((446+(($PART-1)*16))) + +sizehex=`hexdump -e '1/4 "%08x"' -s$((mbroffset+8)) -n4 $DEV` +echo $sizehex +OFFSET=`printf "%d" 0x$sizehex` +OFFSET_DATA=$(($OFFSET+1000)) + +insize=`blockdev --getsize64 $DEV$PART` +if [ $? != 0 ]; then + exit 4 +fi +secsize=`blockdev --getss $DEV` +if [ $? != 0 ]; then + exit 4 +fi + +outbytesoffset=$(($secsize*$OFFSET)) + +echo "mbroffset $mbroffset" +# ccrypt prepends a magic number of 32 bytes at start of file +insize=$((insize+32)) + +cat <<EOF +*** WARNING WARNING WARNING *** + +This will write $(($insize+(4*$secsize))) bytes on $DEV at sector offset $OFFSET (byte $outbytesoffset) +Any existing data will be destroyed! + +It will also overwrite the partition entry for $DEV$PART + +EOF + +read -p "proceed? (type uppercase YES): " confirm +if [ -z "$confirm" ] || [ $confirm != "YES" ]; then + echo "aborted" + exit 1 +fi +read -sp "encryption password: " pass +echo +echo $pass > ${tmpdir}/.pass + +echo using tmpdir ${tmpdir} +echo "dumping data..." +dd if=$DEV$PART of=${tmpdir}/foo +if [ $? != 0 ]; then + exit 5 +fi + +echo "encrypting data..." +ccrypt ${tmpdir}/foo -k ${tmpdir}/.pass +if [ $? != 0 ]; then + exit 6 +fi + +# TODO: check if its on a boundary + +echo "writing data..." +dd if=$DEV of=$DEV skip=$mbroffset seek=$((($secsize*$OFFSET_DATA)+32)) bs=1 count=16 +dd if=${tmpdir}/foo.cpt of=$DEV seek=$((($secsize*$OFFSET_DATA)+16+32)) oflag=seek_bytes +if [ $? != 0 ]; then + exit 7 +fi + +shred ${tmpdir}/foo.cpt + +# create a file fs to write the encrypted scripts to +mkdir ${tmpdir}/mnt +dd if=/dev/zero of=${tmpdir}/scripts_blocks bs=$secsize count=1000 +if [ $? != 0 ]; then + exit 8 +fi + +mkfs.ext4 ${tmpdir}/scripts_blocks +if [ $? != 0 ]; then + exit 9 +fi + +mount ${tmpdir}/scripts_blocks ${tmpdir}/mnt +if [ $? != 0 ]; then + exit 10 +fi + +# create a tar of the scripts +cp w.sh r.sh ${tmpdir}/mnt +if [ $? != 0 ]; then + exit 11 +fi +cat <<eof > ${tmpdir}/mnt/data +$DEV $PART $secsize $((($secsize*$OFFSET_DATA)+32)) $insize $pass +eof + +umount ${tmpdir}/mnt +if [ $? != 0 ]; then + exit 12 +fi + +# encrypt the scripts +ccrypt ${tmpdir}/scripts_blocks -k ${tmpdir}/.pass +if [ $? != 0 ]; then + exit 13 +fi +dd if=${tmpdir}/scripts_blocks.cpt of=$DEV seek=$OFFSET +if [ $? != 0 ]; then + exit 14 +fi + +shred ${tmpdir}/.pass +shred ${tmpdir}/scripts_blocks.cpt +rm ${tmpdir} -rf + +echo "removing partition entry" +dd if=/dev/zero of=$DEV seek=$mbroffset bs=1 count=16 +if [ $? != 0 ]; then + exit 15 +fi + +read -p "Remove script files? (type uppercase YES):" y +if [ $y == "YES" ]; then + `shred w.sh` + `shred r.sh` + `rm -v w.sh` + `rm -v r.sh` +fi diff --git a/w.sh b/w.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +which ccrypt 2> /dev/null || exit 2 +which blockdev 2> /dev/null || exit 2 +which hexdump 2> /dev/null || exit 2 + +DEV=$1 +PART=$2 + +tmpdir=`mktemp -d` +if [ $? != 0 ]; then + exit 3 +fi + +mbroffset=$((446+(($PART-1)*16))) + +sizehex=`hexdump -e '1/4 "%08x"' -s$((mbroffset+8)) -n4 $DEV` +echo $sizehex +OFFSET=`printf "%d" 0x$sizehex` +OFFSET_DATA=$(($OFFSET+1000)) + +insize=`blockdev --getsize64 $DEV$PART` +if [ $? != 0 ]; then + exit 4 +fi +secsize=`blockdev --getss $DEV` +if [ $? != 0 ]; then + exit 4 +fi + +outbytesoffset=$(($secsize*$OFFSET)) + +echo "mbroffset $mbroffset" +# ccrypt prepends a magic number of 32 bytes at start of file +insize=$((insize+32)) + +cat <<EOF +*** WARNING WARNING WARNING *** + +This will write $(($insize+(4*$secsize))) bytes on $DEV at sector offset $OFFSET (byte $outbytesoffset) +Any existing data will be destroyed! + +It will also overwrite the partition entry for $DEV$PART + +EOF + +read -p "proceed? (type uppercase YES): " confirm +if [ -z "$confirm" ] || [ $confirm != "YES" ]; then + echo "aborted" + exit 1 +fi +read -sp "encryption password: " pass +echo +echo $pass > ${tmpdir}/.pass + +echo using tmpdir ${tmpdir} +echo "dumping data..." +dd if=$DEV$PART of=${tmpdir}/foo +if [ $? != 0 ]; then + exit 5 +fi + +echo "encrypting data..." +ccrypt ${tmpdir}/foo -k ${tmpdir}/.pass +if [ $? != 0 ]; then + exit 6 +fi + +# TODO: check if its on a boundary + +echo "writing data..." +dd if=$DEV of=$DEV skip=$mbroffset seek=$((($secsize*$OFFSET_DATA)+32)) bs=1 count=16 +dd if=${tmpdir}/foo.cpt of=$DEV seek=$((($secsize*$OFFSET_DATA)+16+32)) oflag=seek_bytes +if [ $? != 0 ]; then + exit 7 +fi + +shred ${tmpdir}/foo.cpt + +# create a file fs to write the encrypted scripts to +mkdir ${tmpdir}/mnt +dd if=/dev/zero of=${tmpdir}/scripts_blocks bs=$secsize count=1000 +if [ $? != 0 ]; then + exit 8 +fi + +mkfs.ext4 ${tmpdir}/scripts_blocks +if [ $? != 0 ]; then + exit 9 +fi + +mount ${tmpdir}/scripts_blocks ${tmpdir}/mnt +if [ $? != 0 ]; then + exit 10 +fi + +# create a tar of the scripts +cp w.sh r.sh ${tmpdir}/mnt +if [ $? != 0 ]; then + exit 11 +fi +cat <<eof > ${tmpdir}/mnt/data +$DEV $PART $secsize $((($secsize*$OFFSET_DATA)+32)) $insize $pass +eof + +umount ${tmpdir}/mnt +if [ $? != 0 ]; then + exit 12 +fi + +# encrypt the scripts +ccrypt ${tmpdir}/scripts_blocks -k ${tmpdir}/.pass +if [ $? != 0 ]; then + exit 13 +fi +dd if=${tmpdir}/scripts_blocks.cpt of=$DEV seek=$OFFSET +if [ $? != 0 ]; then + exit 14 +fi + +shred ${tmpdir}/.pass +shred ${tmpdir}/scripts_blocks.cpt +rm ${tmpdir} -rf + +echo "removing partition entry" +dd if=/dev/zero of=$DEV seek=$mbroffset bs=1 count=16 +if [ $? != 0 ]; then + exit 15 +fi + +read -p "Remove script files? (type uppercase YES):" y +if [ $y == "YES" ]; then + shred w.sh + shred r.sh + rm -v w.sh + rm -v r.sh +fi