Saturday, July 29, 2017

Steganography with a modified VeraCrypt

So VeraCrypt is a great encryption tool. It is open source, has broad OS support, has lots of good features, works generally very good and has been through several security audits (including TrueCrypt) and subsequent bugfixes. Still I always thought it would be fun and interesting to load containers from anywhere on a disk or file by using offset. That way you could challenge your creativity and skills when storing (hiding) the container. There are a number of methods available to achieve that, but the motivation was to make it possible natively in the tool without depending on a mixture of tools for loading and decryption. Linux is slightly easier to play with as for example explained here https://blog.linuxbrujo.net/posts/plausible-deniability-with-luks/ even though it's not exactly a oneliner. The original patch was made for TrueCrypt about 3 years ago, and now recently I decided to apply the patch to the latest VeraCrypt version 1.21 and have a play with it. The source is available at; https://github.com/jschicht/VeraCrypt We will go through some interesting examples of usage with that special version in this post.

Brief description of the patch. A new command line parameter, /i have been introduced. It defaults to 0, but can be overridden with an offset by placing a decimal value like /i 4096. Basically changes were required in order to pass the offset from commandline usermode into the kernelmode driver. This is the reason for the incompatibility with the legacy version mentioned later.

First off, a huge warning. 
This patch is more of a hack than anything else. It is certainly not provided for showing off excellence in programming. It is a PoC and nothing more. It may also have introduced bugs. Do not perform testing on volumes with content you are not ready to loose! But enough about warnings, let's continue.

The earliest references I could find about steganography and hidden containers with TrueCrypt/VeraCrypt was http://keyj.emphy.de/real-steganography-with-truecrypt/ That trick is about creating a hybrid file format and putting the hidden volume part of the header at a fixed offset 0x10000. That would leave 0x10000 bytes to play with for creating a custom file header for a tweaked file format hiding the container. The obvious drawbacks with this are the limited set of file formats that play well with it, the fixed offset and the lack of support for both normal + hidden volume. The appealing thing is the added layer of protection for the encrypted file by hiding it within another file without invalidating its format/structure.

Now moving a step ahead, by supporting any offset for the container, we can get slightly more exotic in our data hiding test. An important thing to keep in mind is that data must always be stored at sector size aligned offset, when using this particular patch. An easy example would be to place some container data in unpartitioned space on the disk. However a more interesting place would be to store it inside something else on the disk. The success in doing so directly relates to how tweakable a file format is, but also depends on how certain files are being used. I will explain 4 different methods. At this point is worth mentioning that I created a package with some tools a few years ago to prepare such hybrid file formats for hiding these encrypted containers;  https://github.com/jschicht/MakeContainer

Preparation procedure

Before we go to the examples, let me explain the procedure for preparing the custom containers.

  1. Run the VeraCrypt wizard and create an encrypted file container, either normal or hidden. Don't put anything inside it yet.
  2. Run any of the mentioned tools to hide the container in some other file. A bat file will be generated with an example command line for loading it later on. This is of cource just a sample file to show the command, and obviously not meant to be placed on the system.
  3. Run the patched VeraCrypt with a command like the one specified in the example bat file that was generated in step 2. Now you will have to format the the volume once more time after it is decrypted. This is because the physical offset changed. When the volume is formatted the second time, it is ready for use. This is the same for both standard and hidden volumes.
  4. Make sure the host file that contains the hidden container does not get modified at the offsets where the container bytes are stored. Static files are of cource safest to use, but it is for instance possible to store the container inside a text based logfile as long as all new log entries are written to EOF and the logfile is not recycled. Please note that VeraCrypt puts a lock on the file, so it the container is hidden in an exe, then you might not be able to execute it if VeraCrypt has mounted it. Mounting an exe that has a process running, might work though.


Example scenarios

1. Inject encrypted container into the authenticode digital signature of an executable.
The funny issue with Authenticode seems first time described here; https://blog.barthe.ph/2009/02/22/change-signed-executable/ and https://blog.didierstevens.com/2009/01/17/playing-with-authenticode-and-md5-collisions/ In essence it is about modifying the Authenticode signature in signed executables.
To speed up the process of container creation, use the tool MakeContainer-Authenticode. The tool injects the container at a sector size aligned offset within the signature. This is how the original VeraCrypt.exe looks with a container injected into the digital signature signed with IDRIX's certificate and mounting it.


Digital signature still ok after we have mounted an encrypted container from within it. During the tests I noticed that Microsoft has put an upper limit of signature size. Anything beyond exactly 100.000 kb (minus 8 byte header) is disregarded from evaluation, leaving the executable file assumed as unsigned.

2. Locked system file.
In this example we will hide an encrypted container inside the hibernation file, hiberfil.sys. With hibernation activated, this file is completely locked by the system. However, reading the raw sectors from disk is still possible, which we will take advantage of. Due to the method used in this example, on nt6.x and later we are restricted to reading from the volume due to https://msdn.microsoft.com/en-us/library/windows/hardware/ff551353(v=vs.85).aspx and VeraCrypt not using SL_FORCE_DIRECT_WRITE as in https://msdn.microsoft.com/en-us/library/windows/hardware/ff549427(v=vs.85).aspx. For this particular reason, as an initial write operation is needed, we need to take some rather unusual steps to place the container where we need it to be. In XP that is not needed as you can write to anywhere. So we need to boot into WinPE, where we can do whatever we want with the disk when the local system is not running. Actually it would be far easier and faster to boot into linux and use dd to write the container, but has we anyway need our Windows only custom VeraCrypt for preparation, we will stick with WinPE. For the test a custom Win10PE SE was used. When booted, we start by opening the disk with WinHex and click on hiberfil.sys to check the sectors.


Pay attention to the "Logical Sector No.: 24964832". Now run the old nfi.exe tool from microsoft to check the blocks. A command like this would do;
nfi.exe c: 24964832


There we find 2 extents consisting of roughly 2 GB and 1 GB. Due to how Windows uses the hibernation file, it is somewhat safe to store some data towards the end of it. In theory this may of course not be bullet proof, but in practice it may work fine. Just don't hibernate the system when it is heavily used and swapping, because that will likely overwrite the portions of the file where our data is stored. We therefore choose the second extent. This will obviously vary from system to system. First we need to check the partition offset. As we are using WinHex anyway, we open PhysicalDrive0.


The partition with system volume is starting on sector 718848. In order to write to the volume we must first unlock the volume. We temporarily wipe the partition type indicator field in the partition table of mbr (in this case offset 0x1D2), and rescan the volumes with the Windows own diskmanagement.msc. Now that volume is unlocked, we can write our container bytes to the offset. For easyness we place it at partition start + the logical sector of the second extent. That becomes sector;

718848 + 22460800 = 23179648

or disk offset;

23179648 x 512 = 11867979776 (0x2C3630000)

The equivalent dd command to write the container to disk would for example have been;

dd if=c:\temp\container.bin of=\\.\PhysicalDrive0 seek=23179648

As described earlier, with this VeraCrypt hack, we need to first launch our custom VeraCrypt and mount the volume, to prepare it, and also write what we need to write while volume is unlocked. The command in this case would be;

VeraCrypt.exe /v "\Device\Harddisk0\DR0" /l t /a /p joakim /i 11867979776

Ok cool, it mounted. Now format the volume and place some files there. I exaggerated a bit and made a 700 MB volume. When done, unmount the volume, redo the wipe we did of FS field in partition table, and lastly rescan the volumes as we did earlier. Now data is prepared and hidden, and we can get out of WinPE and reboot into the local system. When booted, we can attempt to mount our extremely well hidden container. The reason why we chose Harddisk and not Partition or Volume for access, is because Windows would then block VeraCrypt's access attempt. See:


and

We therefore access \\.\PhysicalDrive0 with a command like this;

VeraCrypt.exe /v "\Device\Harddisk0\DR0" /l t /a /p joakim /m ro /i 11867979776

Notice the read-only switch we added compared to the command run earlier. This is how it looks like;


Let us verify with chkdsk that both the system volume and our mounted volume from within hiberfil.sys, is in a healthy state;



This is what the start of second extent of hiberfil.sys now looks like in our hex editor;


It is not possible to tell that these bytes are suspicious, just by looking at it like that. If you were to extract and analyze hiberfil.sys, you probably would not find much. Most tools would fail at parsing a modern hibernation file anyway, and those that can, would not be able to identify anything unusual. The only exception here is Hibernation Recon, https://arsenalrecon.com/apps/hibernation-recon/ which processes the file much more thoroughly and can differentiate real hibernation data and data that is not. However it can't spoon feed you with a "hey watch out for offset blabla because there is an encrypted container there!". The VM this test was performed in, was thus running on HDD. For systemdrives on SSD this particular trick with hiberfil.sys would not work, and you should choose another file.

3. Bitmap + Portable Executable.
Let's modify an executable (exe), and inject a container as a custom resource in the resource section. We will create another custom prepared bitmap first, that we will inject into the exe. For the bitmap, we use MakeContainer-Bmp, for storing the container inside the bitmap. Verify that the bitmap is fine afterwords. Then we use MakeContainer-PEResource to inject our custom bitmap into an exe. I took 7zFM.exe from 7zip package. Since we double hid the container we need to add the offset provided from MakeContainer-Bmp and the offset provided from MakeContainer-PEResource to the get the real offset for VeraCrypt.


The raw offset of 0xC480C (see Stud_PE) for the injected bitmap is just for the program to behave well. The bitmaps real offset is found at 0xC4A00 (see WinHex) after being aligned to an offset at sector size, and random data filled in between.

4. Text based log files and legacy version.
Lastly we will look at an example similar to what Martin Fiedler did with an mp4 video file (referenced at the top), but with a simple text based log file found in %TEMP%. Not going into all the details, as Martin did that perfectly in 2011. Be sure the container has a hidden volume. There are many files in %TEMP%, so I just chose dd_vcredistMSI27A3.txt out of random. Chop off the first 0x10000 bytes from container and copy the rest over to the log file and write it at offset 0x10000. That's it. No need to run the hacked VeraCrypt version. But you need to mount the file using the hidden volumes password. When opening the file in a text editor, it looks alright until offset 0x10000.



The 4 examples was hopefully bringing some entertainment along when showing some of the potential that VeraCrypt has got when introducing offset to the game.

Some limitations to be aware of.

  • The patched version is currently Windows only. I have attempted a linux patch, but without luck so far.
  • Only available on commandline.
  • Only mount operations work using offset.
  • The container used with this special version are not compatible with legacy VeraCrypt version.
  • The binaries from this special version are incompatible with the legacy version. So using the exe from this version and the driver from the legacy version does not work. You can have it on the same system, but in portable mode.
  • The drivers are signed with a test certificate, meaning you need to configure TESIGNING ON in BCD when using 64-bit Windows. For 32-bit OS it just works as is because that requirement for signed drivers are not present.
  • And there could be more that I am currently not aware of.


For those still reading, here's the bonus part.
Fortunately, the makers of Hibernation Recon as mentioned above, also provide another excellent tool called Arsenal Image Mounter which is found at https://github.com/ArsenalRecon/Arsenal-Image-Mounter. Inside the package there's a little tool called aim_ll.exe that expose the advanced configurations, and in particular we are interested in offset and size. The short version of this part is that we can achieve the same as above by loading a physical disk from an offset in a file, and then use VeraCrypt legacy version to handle it as a harddisk device with full disk encryption. Let us redo example 1 with this method;

#1
Create an empty file of approximately 10 mb in size;
fsutil file createnew %CD%\10mb.bin 10240000

#2
Run MakeContainer-Authenticode. Choose an exe with a signature and attach the 10mb.bin file. Pay attention to the output file generated where the offset is specified. Let's say offset=5598208.

#3
Calculate the size parameter to be used in aim_ll.exe;
Size = 10240000/512 = 20000 blocks (of 512 bytes)

#4
Mount the disk;
aim_ll.exe -a -t file -b 5598208 -s 20000b -f VeraCrypt.exe.D6C5.exe
Look at the device generated in the output.


#5
Finally run VeraCrypt legacy version and create volume with the method "Encrypt a non-system partition/drive". We can create either Standard or Hidden volume. At the selection of device make sure to select the correct one as seen in output of  #4. Select "Create encrypted volume and format it", and continue wizard by setting the password.

#6
Mount the volume by selecting device, choosing the correct one, setting the password and that's it.



It is worth mentioning that ProxyCrypt found at https://sourceforge.net/projects/proxycrypt/ may support offset and size. However it has not been part of the test.

2 comments:

  1. Thanks for this article and for mentioning ProxyCrypt. I confirm that it supports any offset and size since the very first version, but it is Windows-only and does not support VeraCrypt containers.

    ReplyDelete