I’ve always been fascinated by Alternate Data Streams, ever since first learning about them back in 2005 in Security 504. Just the fact they existed was appealing to me in the same way as a book safe or secret pocket in a suitcase – someplace to hide something that no one else knows about, unless you read airline catalogs or take security classes. It was just so sneaky sounding! Consequently, I’ve kept looking at them and the tools to work with them and especially been on the lookout for new capabilities One of my favorites is over SMB, but not from Windows systems. I like using my Mac.
Mounting a SMB share on a Mac (running OS X) has some interesting quirks. Folders that would normally be hidden in a command window on the Windows host system show up as normal files over SMB. Alternate data streams are more readily visible from a command line on the Mac, as the combination of Apple’s SMB and bash interprets them as extended attributes. I covered this in more depth on my blog last year, but the basics are as follows:
- Use the ls -l command to locate alternate data streams – any file or folder with an ADS attached will be marked with an @ symbol after the permissions column:
rons-Mac:Temp ron$ ls
-l
total 10
-rwx------ 1 ron staff
1620 Feb 9 19:39 UserList.txt
-rwx------@ 1 ron staff
24 Apr 3 02:33
file201904030227.txt
-rwx------ 1 ron staff
0 Mar 24 00:34 fromLinux0234
-rwx------@ 1 ron staff
395 Feb 15 14:14 sprayed-creds.txt
- Use xattr to view, create and manipulate alternate data streams
- By itself, the command lists the extended attributes or streams
- – w writes to an extended attribute, -p displays the contents
rons-Mac:Temp ron$ xattr *
file201904030227.txt: ads0233.txt
sprayed-creds.txt: ads.txt
sprayed-creds.txt: nc.exe
rons-Mac:Temp ron$ xattr -w ads0239 'written ~ 0239'
file201904030227.txt
rons-Mac:Temp ron$ xattr -p ads0239 file201904030227.txt
written ~ 0239\
(Note: if the stream contains binary data, xattr converts it to hex before printing it to the console.)
So – neat! If we can gain SMB access to a Windows share from our Mac, we can see, create and export the output from alternate data streams. Of course, I’m a geek – like most geeks I’m all in favor of doing something just because it’s unusual, but wouldn’t it be nice if this gave us something … extra?
Turns out, when I worked on my first blogging foray into alternate data streams, I did notice something … extra. When I used ‘xattr -w’ to create a new alternate data stream, the modified times didn’t change on the target file, either when viewing it from the Mac over SMB or viewing it in a command prompt on the Windows side – here’s the same directory I was manipulating above, viewed from the Windows 10 machine where it resided:
C:\Temp>dir /r
Volume in drive C has no label.
Volume Serial Number is FA12-EC34
Directory of C:\Temp
04/03/2019 02:27 AM <DIR> .
04/03/2019 02:27 AM <DIR> ..
04/03/2019 02:33 AM 24 file201904030227.txt
14 file201904030227.txt:ads0233.txt:$DATA
14 file201904030227.txt:ads0239:$DATA
03/24/2019 02:34 AM 0 fromLinux0234
02/15/2019 05:14 PM 395 sprayed-creds.txt
17 sprayed-creds.txt:ads.txt:$DATA
59,392 sprayed-creds.txt:nc.exe:$DATA
02/09/2019 10:39 PM 1,620 UserList.txt
4 File(s) 2,039 bytes
2 Dir(s) 4,688,662,528 bytes free
This was totally unexpected! The ads file201904030227.txt:ads0239 was written from the Mac at about 02:39am, as the name and contents imply. The ADS above it in the directory file201904030227.txt:ads0233.txt listing was written at 02:33am, as the name implies (yes, this kind of thing does keep me up past midnight. Or maybe it’s the energy drinks.)
While I don’t have an exhaustive Mac lab, containing every version known to man, I’ve tested this on multiple versions of OS X and found the behavior consistent, and used several different target OS’s and systems. This has shown to work the exact same way from Yosemite, Sierra, High Sierra and Mojave, and against targets including Windows 10, Windows Server 2012r2 NTFS and ReFS partitions and even a Synology BTRFS volume shared via SMB. (My other NAS, a Seagate ReadyNAS, does not support them. I believe the volume is formatted EXT4.)
This means we can create, access and delete alternate data streams via SMB without changing modification times on files. This gives us a potential new way to run under the radar. If we don’t change file times, we’re less likely to be noticed.
One example comes to mind – what if we take a directory where alternate data streams are expected to exist, and use that directory to hide data, scripts, or even executables? If you consider the User Downloads folder, it’s generally full of alternate data streams. We usually ignore them. If you were hunting for alternate data streams to look for bad things, you’d probably ignore this folder – too many false positives. We could add extra streams to some of them, or add the information we’re trying to hide to the contents of a Zone.Identifier. Were someone to compare the modified dates and times of the files in the download folder to the browser history information, they’d find nothing unusual. Now, a very sharp-eyed person could see that the average Zone.Identifer file is 26 bytes long, and take note of file sizes that differ. But, of course we can deal with this and script a way to stitch together multiple chunks strewn among data streams. Or, we could roll the dice that nobody notices, or that they assume that some third-party browser has changed the way they write Zone.Identifiers. (Which could be true – I’ve noticed in the past slight differences between Chrome, Edge and Firefox Zone.Identifier files – I’ve seen some in the past that included the full URL the file was downloaded from. If I saw a Zone.Identifier file with some funky Base64 inside it, I might investigate, or I might just assume the browser found some fun new way to monetize tracking me. I’d delete it – but I wouldn’t catch the real attacker!)
There’s another problem with this tactic – the Downloads folder can be temporal. Files are downloaded to the directory, then moved to another folder, or deleted if no longer needed because the user is going through their every other month pruning cycle because they’re running out of disk space. We need something more permanent, something that won’t be deleted, like maybe one of the standard Windows directories!
Directories present all kinds of ways to take advantage of alternate data streams, but here again, we’ve got to be careful. If you’re specifically looking for them you’ll see them – frankly they’ll kind of jump out at you. We need a directory that won’t be looked at, and won’t be deleted.
$Recycle.bin to the rescue.
The Recycle Bin is normally hidden. When you look at a directory listing in cmd or Powershell, it’s typically hidden – on most folders and systems, “Hide protected operating system files” is checked, and you get a very scary warning if you try to uncheck it. Even checked, it doesn’t show up when you run a directory in cmd.exe or Powershell. It’s rather hard to address it directly in a command line – you sometimes have to use a format called DOS Device Path Naming to access it – \\?\c:\$Recycle.bin, and even then, Powershell does not like this – it throws an error in the Get-Item cmdlet. You can find it with the /ah switch on dir, but again, it’s almost always overlooked.
But from the Mac? It’s totally visible and totally ready to manipulate! Here’s the root directory of the Windows 10 image we use in Security 504:
Olorin:c$ ron$ ls -l
Olorin:c$ ron$ ls -l
total 1344753
drwx------@ 1 ron
staff 16384 Dec 16
2016 $Recycle.Bin
-rwx------ 1 ron staff
1 Jul 16 2016 BOOTNXT
-rwx------ 1 ron staff
8192 Dec 16 2016 BOOTSECT.BAK
drwx------@ 1 ron staff 16384 Dec 16 2016 Boot
drwx------ 1 ron staff
16384 Dec 16 2016 Documents and
Settings
drwx------ 1 ron staff
16384 Jul 16 2016 PerfLogs
drwx------ 1 ron staff
16384 Jul 5 2018 Program Files
drwx------ 1 ron staff
16384 Apr 7 20:33 Program Files
(x86)
drwx------ 1 ron staff
16384 Jul 5 2018 ProgramData
drwx------ 1 ron staff
16384 Dec 16 2016 Recovery
drwx------ 1 ron staff
16384 Jul 18 2018 System Volume
Information
drwx------ 1 ron staff
16384 Apr 3 04:14 Temp
drwx------ 1 ron staff
16384 Mar 24 02:16 Tools
drwx------ 1 ron staff
16384 Dec 16 2016 Users
drwx------@ 1 ron staff 16384 Mar 24 00:56 Windows
-rwx------ 1 ron staff
389408 Dec 9 2016 bootmgr
-rwx------ 1 ron staff
671088640 Apr 3 04:11
pagefile.sys
-rwx------ 1 ron staff
16777216 Apr 3 04:11 swapfile.sys
drwx------ 1 ron staff
16384 Jun 1 2018 tmp
drwx------@ 1 ron staff 16384 Jul 18 2018 wiki
Notice the ampersands? Yeah, I’ve already muddled around with this particular image. In this case I was spelunking through the directory structure looking for places to hide things. I found that some directories could not accept an alternate data stream whether created from Windows or a Mac, particularly the user libraries. These folders are rather special in Windows, and are treated differently, although over SMB and to the user they present as normal folders.
However, some other special folders allowed me to add alternate data streams just fine, like Boot and Windows … and the Recycle Bin.
Now, adding text using xattr is easy – you can use the -w option. The format is
xattr -w <ads-name> <ads-content> <file to attach to>
It works very well, and if you need spaces, just put quotes around the content text. However, binary data is a little harder. What if we want to copy our little friend netcat into a stream? It’s small – 59,392 bytes to be exact – but it’s not exactly text-friendly. Fortunately, xattr can handle this – if you want to write binary data, you just have to pass it the hex equivalent and use the -x flag. So, if we can convert the binary to hex, we can put anything we want into a stream attached to almost any Windows file, all over SMB. The trick is to string everything together in the right way.
xattr -x -w nc.exe "`xxd -ps Temp/nc.exe`" \$Recycle.bin
Because not everyone gets to script in bash regularly, let’s break this down. The -x option tells xattr it’s receiving binary data in hex format. The -w tells it to write an extended attribute (which will be converted to an alternate data stream by the OS X SMB stack.). The next section is where we create the hex: the double quotes are necessary to keep it all as one token for the xattr command. The backward quotes (or backticks if you prefer) tell bash to run the command inside them and capture the output as text. The xxd command with -r and -p reads a binary file and prints the hex equivalent. The last part is the file name, which we have to fiddle with because the $ is a special character in Bash – so we escape it.
The outcome? Hop over to Windows and see if it worked:
C:\>streams64
c:\$Recycle.bin
streams v1.60 - Reveal NTFS alternate streams.
Copyright (C) 2005-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
c:\$Recycle.Bin:
:nc.exe:$DATA 59392
Woot! We’ve created an alternate data stream, containing an executable, on a file that most Windows users and admins will never pay a second thought to. If you run dir /r to look for alternate data streams, it won’t show up:
C:\>dir /r
Volume in drive C has no label.
Volume Serial Number is FA12-EC34
Directory of C:\
04/02/2019 01:51 AM 6,148 .DS_Store
60
.DS_Store:AFP_AfpInfo:$DATA
07/16/2016 06:47 AM <DIR> PerfLogs
07/05/2018 09:53 PM <DIR> Program Files
04/07/2019 08:33 PM <DIR> Program Files (x86)
04/09/2019 04:24 PM <DIR> Temp
06/01/2018 02:04 PM <DIR> tmp
03/24/2019 02:16 AM <DIR> Tools
12/16/2016 01:37 AM <DIR> Users
07/18/2018 07:56 PM <DIR> wiki
22
wiki:ads0141:$DATA
03/24/2019 12:56 AM <DIR> Windows
28
Windows:ads0055:$DATA
22
Windows:ads0137:$DATA
1 File(s) 6,148 bytes
One final test – can we run it? We can use wmic:
wmic process call create \\?\c:\$Recycle.bin:nc.exe
And the result?
A working netcat executable, attached to a folder that few people will even look at, let alone consider checking for alternate data streams, and if you noticed the modified date on the directory listing I pulled (from the Mac), the file times didn’t change.
Here’s the file times viewed from the Windows side (with protected file viewable checked.)
Ok, putting back on my blue team hat (it feels so comfy), how can we detect this. Well, we have to dig into our toolbag, because native Windows doesn’t have a lot of ability for this.
For example – Powershell’s Get-Item cmdlet can find alternate data streams with the -streams * option added on:
PS C:\> get-item -path * -stream *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\.DS_Store::$DATA
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\
PSChildName : .DS_Store::$DATA
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName : C:\.DS_Store
Stream : :$DATA
Length : 6148
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\.DS_Store:AFP_AfpInfo
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\
PSChildName : .DS_Store:AFP_AfpInfo
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName : C:\.DS_Store
Stream : AFP_AfpInfo
Length : 60
But it doesn’t see the streams we already know are attached to Windows, Boot and the Recycle Bin.
PS
C:\> get-item -path Windows\ -stream *
PS C:\> get-item -path Boot\ -stream *
get-item : Could not find
item C:\Boot\.
At line:1 char:1
+ get-item -path Boot\ -stream *
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Boot\:String)
[Get-Item], IOException
+ FullyQualifiedErrorId :
ItemNotFound,Microsoft.PowerShell.Commands.GetItemCommand
PS C:\>
PS C:\> get-item -path \\?\c:\$Recycle.bin
-stream *
Get-Item : A parameter
cannot be found that matches parameter name ‘stream’.
At line:1 char:37
+ get-item -path \\?\c:\$Recycle.bin
-stream *
+
~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Item],
ParameterBindingException
+ FullyQualifiedErrorId :
NamedParameterNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Fortunately, we have some other handy tools: lads and Streams.
PS C:\> c:\tools\lads\lads
LADS - Freeware version 3.21
(C) Copyright 1998-2003 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:\
size ADS in file
----------
---------------------------------
59392 C:\$Recycle.Bin\:nc.exe
60 C:\.DS_Store:AFP_AfpInfo
22 C:\Boot\:ads0202
Error 32 opening C:\pagefile.sys: The process cannot access the file because it
is being used by another process
Error 32 opening C:\swapfile.sys: The process cannot access the file because it
is being used by another process
22 C:\wiki\:ads0141
28 C:\Windows\:ads0055
22 C:\Windows\:ads0137
The following summary might be incorrect because there was at least one error!
59546 bytes in 6 ADS listed
PS C:\> streams c:\*.*
streams v1.60 - Reveal NTFS alternate streams.
Copyright (C) 2005-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
c:\$Recycle.Bin:
:nc.exe:$DATA 59392
c:\.DS_Store:
:AFP_AfpInfo:$DATA 60
c:\Boot:
:ads0202:$DATA 22
Error opening c:\pagefile.sys:
The process cannot access the file because it is being used by another process.
Error opening c:\swapfile.sys:
The process cannot access the file because it is being used by another process.
c:\wiki:
:ads0141:$DATA 22
c:\Windows:
:ads0055:$DATA 28
:ads0137:$DATA 22
PS C:\>
Note: Lads does not work on ReFS volumes, only NTFS. If you run lads in a directory on an ReFS volume, it will complain the ReFS does not support alternate data streams, which at one time was true, but not today. Streams is perfectly happy on both NTFS and ReFS and even on BTRFS served over SMB.
So, we do have the ability to hunt for this, if we have an inkling that an attacker is using this tactic. Of course, you can use a Mac to do this as well, as long as the folder you’re checking is accessible via SMB. Or you can use the Linux smbclient – new versions include the allinfo command, which will identify the existence of alternate data streams, even on special directories like Boot and $Recycle.bin. Finally, it’s a good bet that your EDR, if you use one, also will detect this behavior, although the jury’s out on if it will raise an alert or simply create an event that you’d have to hunt for.
One final note: When I turned on file access auditing, file access times did change when using xattr, both to view and to write streams. Modified times remained the same.