Alternate Data Streams: Beware of Invisibility

A lot of people will hate on Microsoft or Windows or anything else that comes out the doors of 157th Avenue NE in Redmond, Washington for doing…well…just about anything. Nonetheless, I wanna say that I love Windows. I love it so much that I’ll actually thank Microsoft. I’ll thank them for making it so damn easy to completely and utterly compromise their systems with little to no effort at all. Thank you Microsoft for making my life that much easier.

Over the years, the list of “Microsoft mistakes” has grown longer and longer with each release. One such screw-up that I’d like to talk about is Alternate Data Streams (ADS). “What are Alternate Data Streams” you say? You say you’ve never heard of them before? Most people haven’t because it’s another one of their highly under-documented technologies. I don’t blame them for trying to hide it either because ADS is just downright stupid!

What is ADS?

Alternate Data Streams allows for one or more data streams to be associated with a file. It’s primarily meant for storing file attributes and other metadata. However, the size of the alternate stream in no way affects to total file size. Say you’ve got a 60 kB file with a 30 kB ADS associated with it. If you were to take a look at it with Windows Explorer or the command-line, they would still report the file as being only 60 kB. Because of this “feature”, it allows super evil bad guys to effortlessly hide data that can remain concealed until very close inspection.

You might be wondering, “Well what the hell Microsoft!? Why!?” The truth is that ADS was Microsoft’s attempt at implementing filesystem forks in order to maintain compatibility with other filesystems like Apple’s HFS+ and Novell’s NWFS and NSS. It was first introduced to NTFS in Windows NT 3.1 and was meant to store metadata like file attributes, icons, image thumbnails, that kinda thing. Sure it’s a reasonable idea but you have to wonder: given the choice between maintaining compatibility with a competitor’s technology versus introducing yet another means to exploit your product, which is more important? Apparently, the fools professionals at Microsoft are more interested in dancing pigs.

Using ADS With Text Files

Adding a data stream to a file is practically child’s play. An ADS is referenced using the notation filename:stream anywhere you’d normally use a regular filename.

You can use any existing file but I’m gonna start out making a new one.

C:\foo\bar>echo "They mostly come out at night...mostly." > newt.txt

C:\foo\bar>type newt.txt
"They mostly come out at night...mostly."

C:\foo\bar>dir
 Volume in drive C has no label.
 Volume Serial Number is FCE9-528D

 Directory of C:\foo\bar

08/30/2012  05:13 PM                    .
08/30/2012  05:13 PM                    ..
08/30/2012  05:15 PM                 44 newt.txt
               1 Files(s)             44 bytes
               2 Dir(s)    7,113,324,588 bytes free

Note the current file size of 44 bytes. Using the notation described above, tack on some text to an alternate stream.

C:\foo\bar>echo "Now all we need is a deck of cards." > newt.txt:hicks

C:\foo\bar>dir
 Volume in drive C has no label.
 Volume Serial Number is FCE9-528D

 Directory of C:\foo\bar

08/30/2012  05:13 PM                    .
08/30/2012  05:13 PM                    ..
08/30/2012  05:15 PM                 44 newt.txt
               1 Files(s)             44 bytes
               2 Dir(s)    7,113,324,588 bytes free

It’s still 44 bytes! If hicks were a normal file, it’d be 40 bytes so you’d think the total size of newt.txt would be 84 bytes. Nope. As far as we’re concerned, there’s nothing there but a plain ol’ text file. But just in case, let’s make sure our ADS is actually there.

C:\foo\bar>type newt.txt:hicks
The filename, directory name, or volume label syntax is incorrect.

Uh oh. Time out. What happened here? The ADS was created just fine but it couldn’t be read from. As the error message indicates, some commands tend to vomit all over the place when a colon is used anywhere but the drive letter (e.g. C: or D:).

The best way to read from an ADS is to use the more command.

C:\foo\bar>more < .\newt.txt:hicks
"Now all we need is a deck of cards."

Ah, that’s much better.

Hiding Media Files

This ADS stuff might not seem all that much of a threat since we’re just dealing with text files here. However, ADS can be used with any type of file. It’s just raw binary data.

Imagine that you’re really embarrassed about the fact that you like Nickelback but all your friends are huge Limp Bizkit fans instead. To make sure that everybody still thinks your cool, just hide your Nickelback MP3′s in an ADS. By the way, you should both be embarrassed and find a new group of friends!

C:\foo\bar>dir
 Volume in drive C has no label.
 Volume Serial Number is FCE9-528D

 Directory of C:\foo\bar

08/30/2012  05:22 PM                    .
08/30/2012  05:22 PM                    ..
08/30/2012  05:22 PM          4,198,147 limp_bizkit.mp3
08/30/2012  05:22 PM          4,031,881 nickelback.mp3
               1 Files(s)      8,230,028 bytes
               2 Dir(s)    7,121,554,572 bytes free

C:\foo\bar>type nickelback.mp3 > limp_bizkit.mp3:nickelback.mp3

C:\foo\bar>cat limp_bizkit.mp3:nickelback.mp3 > nb.mp3

You may have noticed my use of the cat tool even though we’re using Windows. Yes, there is such a thing. I decided to use CoreUtils for Windows instead of using double redirection since that can take a while.

You could do the same thing with video files if you wanted. The point is, it’s just raw data so any combination of filetypes can be used; they don’t even have to be the same.

Compatibility Issues

ADS compatibility between Windows versions is limited at best. Since Windows Vista, Microsoft has taken out some of the major security concerns with ADS but has left some features in tact for…wait for it…compatibility reasons! That’s right!

Up until this point, everything will work just fine on post-Vista versions (at the time of this writing, Windows 7 is still the hot product.) However, the next section on executables will not. Windows XP was the last version to support running executables from ADS streams. But that’s really not a big deal considering the large amount of individuals and businesses that are still reluctant to upgrade their machines (my mom’s computer is still running XP because she “doesn’t understand all those new fancy icons and just wants to be able to read her email.”)

There are a few more compatibility issues that I’ll mention as we come to them.

Using ADS With Executables

The real fun with ADS begins when you start using it to hide executables. There’s no need hide-and-unhide them as we did with the MP3 files. They can be run directly from the ADS.

Let’s try an example that hides notepad.exe within calc.exe. Remember, we’re talking about Windows XP (at least) right now. No more “fancy icons.”

C:\foo\bar>copy %windir%\System32\calc.exe .
        1 file(s) copied.

C:\foo\bar>dir
 Volume in drive C has no label.
 Volume Serial Number is FCE9-528D

 Directory of C:\foo\bar

08/30/2012  06:21 PM                    .
08/30/2012  06:21 PM                    ..
08/23/2001  07:00 AM            114,688 calc.exe
               1 Files(s)        114,688 bytes
               2 Dir(s)    7,114,243,072 bytes free

At this point, note that calc.exe is 114,688 bytes. This value is not going to change even after we tack on notepad.exe which is 69,120 bytes.

C:\foo\bar>type %windir%\System32\notepad.exe > calc.exe:notepad.exe

C:\foo\bar>dir
 Volume in drive C has no label.
 Volume Serial Number is FCE9-528D

 Directory of C:\foo\bar

08/30/2012  06:33 PM                    .
08/30/2012  06:33 PM                    ..
08/30/2012  06:33 PM            114,688 calc.exe
               1 Files(s)        114,688 bytes
               2 Dir(s)    7,114,243,072 bytes free

The file size hasn’t changed but if you look closely, something else has: the last modified timestamp. It now shows that calc.exe was last modified just now. Although very subtle, any potential evidence like this presents a problem for covering your tracks.

Modifying the Timestamp

There’s gotta be a way around this, right? Of course!

For the lazy and less ambitious, there’s plenty of third party tools. A popular one is SKTimeStamp. It’s a small shell extension that adds an extra tab to the Properties dialog in Windows Explorer which allows you to modify the Created, Last Modified, and Last Accessed timestamps.

I’m sure Stefan Küng’s little tool works just fine so I won’t tell you not to use it. However, we’re all hackers here (I hope) so let’s do it ourselves.

So what language should we choose? Well, we could always use a batch file or some VBScript but that’s just not ugly enough. I think PowerShell will satisfy my need for ugliness for now.

So start up vim and…<sigh>…I mean Notepad and write a little something like this:

# chtime.ps1

if ($args.Length -ne 2) {
    Write-Output @"
Usage: chtime.ps1  
     Must be of the form MM/DD/YYYY HH:MM AM/PM
     Name of file to modify
"@

    exit(1)
}

$date = Get-Date      $args[0]
$file = Get-ChildItem $args[1]

$msg = "File {0}: changing timestamp to {1}" `
    -f [IO.Path]::GetFileName($file), $date.DateTime

Write-Output $msg

$file.LastWriteTime = $date

Awww yeah. Now that’s good and ugly alright. Seriously, sometimes I wonder if 3 – 5 years experience of being in a brainless stupor is a job requirement to work at Microsoft because whoever helped develop PowerShell and thought something like this actually looks nice must’ve been an indubitable moron.

Alright, alright…enough trash talk. Start up PowerShell (XP require the KB968930 update here) and run the following commands:

PS C:\foo\bar> ls

    Directory: C:\foo\bar

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         8/30/2012   6:33 PM     114688 calc.exe
-a---         8/30/2012   6:41 PM        850 chtime.ps1

PS C:\foo\bar> .\chtime.ps1
Usage: chtime.ps1  
     Must be of the form MM/DD/YYYY HH:MM AM/PM
     Name of file to modify

PS C:\foo\bar> .\chtime.ps1 "08/23/2001 07:00 AM" .\calc.exe
File calc.exe: changing timestamp to Thursday, August 23, 2001 7:00:00 AM
PS C:\foo\bar> ls

    Directory: C:\foo\bar

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         7/13/2009   9:38 PM     114688 calc.exe
-a---         8/30/2012   6:42 PM        850 chtime.ps1

See? All better.

Having properly covered up our tracks, we can now run the executable from within the ADS.

C:\foo\bar>start .\calc.exe:notepad.exe

Notepad should start up just fine but if you take a look at the Task Manager, you’ll see that we didn’t achieve true stealth. :(

ADS as Hidden Processes

The advantage of using an executable as an ADS is that it allows you to hide the fact that it’s even running. When you run the ADS executable, the Task Manager reports the process as the original filename.

However, this too is dependent on certain Windows versions. Windows 2000 will not show the ADS process; only the original executable.

Windows 2000 Task Manager

Windows 2000 Task Manager showing only the original executable. The ADS process remains hidden.

On the other hand, Windows XP will show the ADS process in the Task Manager as filename:stream as you can see below.

Windows XP Task Manager

Windows XP Task Manager clearly showing both the original executable and the ADS.

Sure it’s not completely invisible anymore but this doesn’t present that much of a problem though. Considering that most people have never even heard of ADS, we can simply change the executable name to look like something more legitimate. Windows Service Host is always a favorite so let’s try that.

C:\foo\bar>copy %windir%\System32\svchost.exe .
        1 file(s) copied.

C:\foo\bar>dir
 Volume in drive C has no label.
 Volume Serial Number is FCE9-528D

 Directory of C:\foo\bar

08/30/2012  07:00 PM                   .
08/30/2012  07:00 PM                   ..
04/14/2008  12:42 AM            14,336 svchost.exe
               1 File(s)         14,336 bytes
               2 Dir(s)   7,113,338,880 bytes free

C:\foo\bar>type %windir%\System32\notepad.exe > svchost.exe:svchost.exe

C:\foo\bar>start .\svchost.exe:svchost.exe
Windows XP Task Manager With svchost.exe

Windows XP Task Manager showing the fake svchost.exe process.

Not so bad anymore, is it? You could even run it as Administrator for an extra layer of obscurity. It’s always fun making lemonade out of lemons.

Detecting ADS

The truth is, there’s no way to make ADS 100% invisible. You can minimize its footprint but, nevertheless, there’s still a footprint. Because of that, there are a few ways to search for ADS.

Starting with Windows Vista, Microsoft introduced the /R switch to the dir command that will display any ADS streams associated with a file. For example:

C:\foo\bar>dir /R
 Volume in drive C has no label.
 Volume Serial Number is BE91-B378

 Directory of C:\foo\bar

08/30/2012  07:24 PM                   .
08/30/2012  07:24 PM                   ..
08/30/2012  07:24 PM                44 newt.txt
                                    40 newt.txt:hicks:$DATA
               1 File(s)             44 bytes
               2 Dir(s)  58,964,307,968 bytes free

C:\foo\bar>rename newt.txt delete_me.txt

C:\foo\bar>type delete_me.txt > newt.txt

C:\foo\bar>del delete_me.txt

Practically speaking, this is only useful unless you already suspect some type of suspicious behavior coming from a particular directory. (If you’re curious what $DATA is, take a look here.)

Something a little more practical is to use a tool like LADS. Unlike the /R switch, LADS lists only the files with  ADS streams associated with them; not the entire directory contents. It also has more features like recursing through subdirectories and displaying a verbose report. The nice thing about it is that it works on Windows NT4, Windows 2000, Windows XP, Windows Server 2003, Windows Vista, and Windows 7.

C:\foo\bar>lads.exe .

LADS - Freeware version 4.10
(C) Copyright 1998-2007 Frank Heyne Software (http://www.heysoft.de)
This program lists files with alternate data streams (ADS)
Use LADS on your own risk!

Scanning directory C:\foo\bar\

      size  ADS in file
----------  ---------------------------------
    193536  C:\foo\bar\calc.exe:notepad.exe
        40  C:\foo\bar\newt.txt:hicks
     27136  C:\foo\bar\svchost.exe:svchost.exe

    220712 bytes in 3 ADS listed

But if you’re like me and are surrounded by people who wouldn’t know what a command-line even was, there are a few GUI tools as well. I’d recommend ADS Spy. Even though it doesn’t support the old Windows versions that LADS does, it does have the neat option of removing any ADS streams it finds. It can also calculate the MD5 checksum of the stream.

ADS Spy

ADS Spy scan reveals three alternate data streams.

LADS and ADS Spy are both great tools and I give them my full seal of approval. :)

Programming With ADS

Up until now, all examples involving the creation of ADS streams have been using the command-line. Additionally, you can also use ADS in the Windows C API.

// ads.cpp

#include <iostream>
#include <windows.h>

using namespace std;

#define FILENAME "fling.txt"
#define ADS      FILENAME ## ":flang.txt"

BOOL
Write(HANDLE *hHandle, char *lpczFile, char *lpczMsg, DWORD nByteSize)
{
    DWORD dwWritten;

    *hHandle = CreateFileA(lpczFile,
                          GENERIC_WRITE,
                          FILE_SHARE_WRITE,
                          NULL,
                          CREATE_ALWAYS,
                          0,
                          NULL);

    if (*hHandle == INVALID_HANDLE_VALUE)
        return FALSE;
    else
        WriteFile(*hHandle, lpczMsg, nByteSize, &dwWritten, NULL);

    return TRUE;
}

int
main(void)
{
    char *lpczFileMsg, *lpczStreamMsg;
    BOOL bStatus;
    DWORD dwFileSize, dwStreamSize;
    HANDLE hFile, hStream;

    lpczFileMsg = "Yap flopping flabrizzle!";
    dwFileSize  = strlen(lpczFileMsg);

    lpczStreamMsg = "Da woogle booshizzle!";
    dwStreamSize  = strlen(lpczStreamMsg);

    // Write to original file.
    bStatus = Write(&hFile, FILENAME, lpczFileMsg, dwFileSize);

    if (bStatus)
        cout << "Wrote '" << lpczFileMsg << "' to " << FILENAME << endl;
    else {
        cerr << "[ERROR] Failed to open " << FILENAME << endl;
        exit(EXIT_FAILURE);
    }

    // Write to alternate data stream.
    bStatus = Write(&hStream, ADS, lpczStreamMsg, dwStreamSize);

    if (bStatus)
        cout << "Wrote '" << lpczFileMsg << "' to " << ADS << endl;
    else {
        cerr << "[ERROR] Failed to open " << ADS << endl;
        exit(EXIT_FAILURE);
    }

    CloseHandle(hFile);
    CloseHandle(hStream);

    return 0;
}

Even if you’re unfamiliar with the Windows C API, this should still be fairly self-explanatory. You call CreateFile() as you normally would except using the filename:stream notation like we did on the command-line.

Just to double check that it works:

C:\foo\bar>cl /nologo ads.cpp
ads.cpp

C:\foo\bar>ads.exe
Wrote 'Yap flopping flabrizzle!' to fling.txt
Wrote 'Da woogle booshizzle!' to fling.txt:flang.txt

C:\foo\bar>type fling.txt
Yap flopping flabrizzle!
C:\foo\bar>more < .\fling.txt:flang.txt
Da woogle booshizzle!

Perfect. Additionally, you can use the same method when reading from an ADS with the ReadFile() function. You get the idea though. It’s simple stuff, really.

There’s one gotcha that’s worth noting: ADS cannot be used in .NET languages. This is due to the fact that the colon character is only allowed to appear directly after the drive letter.

Data Loss

The downside to ADS is that they’re only safe on NTFS drives. If you move a file that has an associated ADS to another location that does not support filesystem forks, you will lose everything in the ADS. Not only does that mean simply copying to something like a FAT32 formatted flash drive but it also includes communications like email or FTP. It gets even worse when you consider what would happen when transferring files between forks-aware filesystems but using a program that does not support them. The same can occur when compressing files that aren’t fork-aware either.

The bottom line, keep your ADS files put. Even though the whole notion of ADS was to be compatible with other fork-aware filesystems, there are just too many variables in between that can result in data loss.

The Future of ADS

As a legitimate solution to storing metadata, ADS has a very dull future. Because of all the compatibility problems and security concerns, manufacturers have largely moved over to extended file attributes. Extended file attributes are a much more practical solution to organizing metadata since data is organized into key-value pairs instead of just raw binary data and cannot exceed the size of the original file. It’s nice to see companies starting to realize that the security implications of filesystem forks far outweighs their usefulness. However, as long as filesystem forks like ADS are at least 1% supported, they’ll always pose some type of risk. And I’ll always be there to exploit it. :P

One response to “Alternate Data Streams: Beware of Invisibility

  1. Wow, this is incredibly useful for all the files I want to “hide” away. Makes me even more worried about Microsoft’s engineering practice though.