ext2 trick

In the following, I will try to explain how to hide data in the spare data of the superblock of an Ext2 filesystem with common tools available.
But before this, read the disclaimer.

DISCLAIMER:

The following manipulations can greatly damage your data and your ext2 filesystem if you try the manipulations directly on it. All the following is provided only for information and the author can't be responsible for any loss of data or any king of damage.
Please re-read this three time...

 

Without the need of a special utility, you will see that you can hide data within the spare data an Ext2 superblock.
I recommend you to try this on a floppy or on file that you can mount as a loop device :


# dd if=/dev/zero of=ext2.img bs=1M count=2
2+0 records in
2+0 records out
# mke2fs -b 2048 -F ext2.img
mke2fs -b 2048 -F ext2.img
mke2fs 1.27 (8-Mar-2002)
Filesystem label=
OS type: Linux
Block size=2048 (log=1)
Fragment size=2048 (log=1)
256 inodes, 1024 blocks
51 blocks (4.98%) reserved for the super user
First data block=0
1 block group
16384 blocks per group, 16384 fragments per group
256 inodes per group

Writing inode tables: done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 27 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.
#

We created an empty ext2 filesystem with block of 2048 bytes long.
First important thing we learned from this is that the first data block is the block 0. This means that the superblock is not at the offset 0, but is preceeded by the boot strap data block.
(for an existing ext2 filesystem, you can know what is the first data block by using tune2fs.)

boot strap block
(optional)
Superblock
Group descriptor block
 
boot strap
(optional)
superblock data
(208 bytes)
spare data
. . .

So now, how can we safely know the offset where to start for writing our data.
The first superblock always start at offset 1024. If the blocksize is 1024 bytes, the first data block is the block 1, block 0 then contain the boot strap data; but if the blocksize is greater than 1024, the boot strap (1024 bytes long) is contained in the superblock.
This means that for a block size of 1024 or 2048 bytes, the spare data (after the superblock) is the same:

1024 - 208 = 816 bytes

This becomes more interesting with a block size of 4096 bytes:

4096 - 1024 - 208 = 3280 bytes.

This is not huge, but this can be useful...

Let's try with a silly example:

# ls -l /etc/passwd
-rw-r--r-- 1 root root 747 Feb 6 19:27 /etc/passwd
# cp /etc/passwd .
# gzip passwd
# ls -l passwd.gz
-rw-r--r-- 1 root root 397 Mar 25 01:26 passwd.gz
# dd if=passwd.gz of=ext2.img obs=1 seek=1300 conv=notrunc
0+1 records in
397+0 records out
# e2fsck ext2.img
e2fsck 1.27 (8-Mar-2002)
ext2.img: clean, 11/256 files, 29/1024 blocks
# dd if=ext2.img of=passwd.recovered.gz bs=1 skip=1300 count=500
500+0 records in
500+0 records out
# gzip -d passwd.recovered.gz
# md5sum passwd.recovered
d49ab54909d6ca5dc851c733a5c04ed3 passwd.recovered
# gzip -d passwd.gz
# md5sum passwd
d49ab54909d6ca5dc851c733a5c04ed3 passwd
#

Gzip is very useful because it doesn't require us to remember the exact size of the stored data. Also, it allows to store more data is the spare space.