partitionhider

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

secretluks.txt (7666B)


      1 before start:
      2 
      3 1. be sure to overwrite the whole area with /dev/urandom
      4 
      5 ---
      6 
      7 1: Hiding a crypt partition
      8 
      9 Example: 8gb usb drive.
     10 
     11 (find a drive where the size doesn't say on it)
     12 
     13 Partition the visible space to a plausible size as if fully formatted (half).
     14 
     15 The idea is that on normal inspection, the disk will look fully utilized, for example so:
     16 
     17 # fdisk -l /dev/sdc
     18 Disk /dev/sdc: 7.5 GiB, 8004304896 bytes, 15633408 sectors
     19 Units: sectors of 1 * 512 = 512 bytes
     20 Sector size (logical/physical): 512 bytes / 512 bytes
     21 I/O size (minimum/optimal): 512 bytes / 512 bytes
     22 Disklabel type: dos
     23 Disk identifier: 0x2f95ed70
     24 
     25 Device     Boot   Start      End Sectors  Size Id Type
     26 /dev/sdc1          2048  7816704 7814657  3.7G  b W95 FAT32
     27 /dev/sdc2       7817216 15633408 7816192  3.7G 83 Linux
     28 
     29 ---
     30 
     31 Now let's prepare the partitions:
     32 
     33 $ mkfs.ext -F32 /dev/sdc1
     34 $ cryptsetup luksFormat /dev/sdc2
     35 $ cryptsetup open /dev/sdc2 gone
     36 $ mkfs.ext4 /dev/mapper/gone
     37 $ mount /dev/mapper/gone /mnt/point
     38 $ echo xyzzy > /mnt/point/foo.txt
     39 $ umount /mnt/point
     40 $ cryptsetup close gone
     41 
     42 ---
     43 
     44 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:
     45 
     46 hexdump -e '16/1 "%02x " "\n"' -s0x01ce -n16 /dev/sdc
     47 00 72 49 fe 83 b1 ef fc 00 48 77 00 00 44 77 00
     48 
     49 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!
     50 
     51 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:
     52 
     53 $ dd if=/dev/zero of=/dev/sdc seek=1 bs=512 count=2047
     54 ...
     55 $ hexdump -s0x01b0 -n`calc 2048*512` /dev/sdc
     56 00001b0 00a4 0002 0000 0000 ed70 2f95 0000 2100
     57 00001c0 0003 690b fe77 0800 0000 3e01 0077 7200
     58 00001d0 fe49 b183 fcef 4800 0077 3bc5 0077 0000
     59 00001e0 0000 0000 0000 0000 0000 0000 0000 0000
     60 00001f0 0000 0000 0000 0000 0000 0000 0000 aa55
     61 0000200 0000 0000 0000 0000 0000 0000 0000 0000
     62 *
     63 0100000 58eb 6d90 666b 2e73 6166 0074 0802 0020
     64 ...
     65 
     66 (the * means same data in the interval)
     67 
     68 We can still mount and write data:
     69 
     70 $ mount /dev/sdc1 /mnt/point
     71 $ dd if=/dev/urandom of=/mnt/point/foo bs=1024 count=1024
     72 $ hexdump /mnt/tmp/foo | tail -n2
     73 00ffff0 b1f4 175d 0325 2708 a2a3 b9e7 d153 4059
     74 0100000
     75 $ umount /mnt/point
     76 
     77 ---
     78 
     79 Let's hide the partition data in the gap:
     80 
     81 $ dd if=/dev/sdc of=/dev/sdc skip=462 seek=1300 bs=1 count=16
     82 
     83 $ hexdump -e'16/1 "%02x "' -n16 -s1300 /dev/sdc
     84 //00 72 49 fe 83 b1 ef fc 00 48 77 00 c5 3b 77 00
     85 00 72 49 fe 83 b1 ef fc 00 48 77 00 00 44 77 00
     86 
     87 or with diff to be sure:
     88 
     89 $ diff <(hexdump -e'16/1 "%x"' -n16 -s0x01ce /dev/sdc) <(hexdump -e'16/1 "%x"' -n16 -s1300 /dev/sdc)
     90 
     91 --
     92 
     93 the magic moment. Overwrite the partition entry with zeros:
     94 
     95 $ dd if=/dev/zero of=/dev/sdc bs=1 count=16 seek=462
     96 
     97 $ hexdump -e'16/1 "%02x " "\n"' -n16 -s462 /dev/sdc
     98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
     99 
    100 $ fdisk /dev/sdc -l
    101 ...
    102 Device     Boot Start     End Sectors  Size Id Type
    103 /dev/sdc1        2048 7816704 7814657  3.7G  b W95 FAT32
    104 
    105 (lsblk may still show the partition, dunno why, remove and insert medium and it will be updated)
    106 
    107 --
    108 
    109 More magic: restore:
    110 
    111 $ dd if=/dev/sdc of=/dev/sdc bs=1 count=16 seek=462 skip=1300
    112 
    113 $ fdisk /dev/sdc -l
    114 
    115 (lsblk shows straight away)
    116 
    117 ===
    118 
    119 2. cryptpart
    120 
    121 $ hexdump -s`calc 7817216*512` -n32 -e'128/1 "%_c" "\n"' /dev/sdc
    122 LUKS272276\0001aes\0\0\0\0\0
    123 
    124 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.
    125 
    126 ---
    127 
    128 let's start over, but this time not use the whole disk:
    129 
    130 # fdisk -l /dev/sdc
    131 Disk /dev/sdc: 7.5 GiB, 8004304896 bytes, 15633408 sectors
    132 Units: sectors of 1 * 512 = 512 bytes
    133 Sector size (logical/physical): 512 bytes / 512 bytes
    134 I/O size (minimum/optimal): 512 bytes / 512 bytes
    135 Disklabel type: dos
    136 Disk identifier: 0x2f95ed70
    137 
    138 Device     Boot   Start      End Sectors  Size Id Type
    139 /dev/sdc1          2048  7816704 7814657  3.7G  b W95 FAT32
    140 /dev/sdc2       7817216 15631300 7814085  3.7G 83 Linux
    141 
    142 ----
    143 
    144 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.
    145 
    146 We are short 2107 sectors, or 1078784 bytes. Why did we choose this number?
    147 
    148 1) luksheader = 1052672 bytes = 2056 * 512 sectors
    149 2) we also need one extra sector for encrypting of luks header
    150 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.
    151 
    152 ---
    153 
    154 change to a tmpfs and backup the header
    155 
    156 $ mkdir /dev/shm/foo
    157 # mount /dev/shm/foo /mnt/point -t tmpfs
    158 
    159 $ cryptsetup luksHeaderBackup /dev/sdc2 --header-backup-file crypt.bak
    160 
    161 we may verify that it matches:
    162 
    163 $ diff <(hexdump -e'"%x"' luks.bak) <(hexdump -e'"%x"' -s`calc 7817216*512` -n1052672 /dev/sdc)
    164 
    165 ---
    166 
    167 ccrypt the backup. This will add 32 bytes to the start of the file.
    168 
    169 $ ls luks.bak*
    170 -r-------- 1 root root 1052672 Jan 25 03:20 luks.bak
    171 
    172 becomes:
    173 
    174 $ ls luks.bak*
    175 -r-------- 1 root root 1052704 Jan 25 03:41 luks.bak.cpt
    176 
    177 ---
    178 
    179 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.
    180 
    181 $ dd if=luks.bak.cpt of=/dev/sdc bs=512 seek=15631300
    182 2056+1 records in
    183 2056+1 records out
    184 1052704 bytes (1.1 MB, 1.0 MiB) copied, 0.313062 s, 3.4 MB/s
    185 
    186 You can verify that the data written is correct by comparing the first 1024 bytes of the outputs 8003225600 = 15631300 * 512
    187 
    188 $ hexdump -e'32/1 "%x" "\n"' -n1024 tmp/luks.bak.cpt
    189 $ hexdump -e'32/1 "%x" "\n"' -s8003225600 -n1024 /dev/sdc
    190 ($ hexdump -e'32/1 "%x" "\n"' -s`calc 15631300*512` -n1024 /dev/sdc
    191 
    192 diff <(hexdump -e'32/1 "%x"' -n1024 tmp/luks.bak.cpt) <(hexdump -e'32/1 "%x"' -s`calc 15631300*512` -n1024 /dev/sdc)
    193 
    194 ---
    195 
    196 Overwrite the existing luks header with garbage:
    197 
    198 $ dd if=/dev/urandom of=/dev/sdc bs=512 count=2056 seek=7817216
    199 
    200 Check that it's gone:
    201 
    202 $ hexdump -s`calc 7817216*512` -n16 -e'128/1 "%_c" "\n"' /dev/sdc
    203 XV216274271211@Z265324226270&210376D
    204 
    205 if still there, remove partition entry again
    206 
    207 ---
    208 
    209 Bring it back:
    210 
    211 write it back and decrypt:
    212 
    213 $ dd if=/dev/sdc of=luksrestored.cpt bs=512 count=2057 skip=15631300
    214 $ ccrypt -d luksrestored.cpt
    215 
    216 NB NB! The file will now be 1053152, ONE SECTOR BIGGER! If use dd to write back, specify bs=512 and count=2056
    217 Safer is restore from cryptsetup, it will only use the relevant bytes:
    218 
    219 we can check this by editing adding something at 0x101000 of the file and see if we find it after.
    220 
    221 $ cryptsetup luksHeaderRestore /dev/sdc2 --header-backup-file luksrestored
    222 
    223 (Bring back partition)
    224 
    225 ---
    226 
    227 should be able to:
    228 
    229 $ cryptsetup open /dev/sdc2 back
    230 $ mount /dev/mapper/back /mnt/point
    231 $ echo /mnt/point/foo.txt
    232 xyzzy
    233 
    234 ---
    235 
    236 May still be conspicuous that only half of disk is formatted, but:
    237 
    238 - it's plauisbly deniable that the random data is indeed random.
    239 - it's not TOTALLY unreasonable to have unpartitioned space for later
    240 
    241 ---
    242 
    243 There's nothing wrong with having the encrypted luks backup on a different drive etc.