Detecting Extended Attributes (ZeroAccess) and other Frankenstein’s Monsters with HMFT

The topic of Extended Attributes (EA) has been recently covered in an excellent post by Corey. Entitled Extracting ZeroAccess from NTFS Extended Attributes it goes into (amazing) depth explaining on what EA is and how to extract this artifact from the system. It’s a pure forensic gold and if you haven’t read this post yet, please go ahead and do so before reading mine.

Similarly to Corey, I was very interested in researching EA, and I finally took some time tonight to have a deeper look at it myself. I actually wanted to dig in the code more than the $MFT artifacts alone not only to have something to write about (after all, Corey already covered everything! :-)), but also because I wanted to see how the EA is actually created and what system functions/APIs are used by malware. The reason behind this curiosity was improvement of my analysis tools and techniques, and a few other ideas that I will be quiet about for the moment.

I first assumed that the ZeroAccess’ EAs are created using ZwSetEaFile/NtSetEaFile function from ntdll.dll. I saw this API name popping up on some blogs and I saw it being referenced in my ZeroAccess memory/file dumps so it was a natural ‘breakpoint’ choice for OllyDbg analysis:

zeroaccess_ea_1

To my surprise, none of the samples I checked used this function at all!

Curious, I started digging into it a bit more and realized that for the samples I looked at, the EAs are actually created not by  ZwSetEaFile/NtSetEaFile function, but by ZwCreateFile/NtCreateFile.

Surprised?

I was!

Looking at a documentation, you can see the following function parameters described on MSDN:

NTSTATUS NtCreateFile(
  _Out_     PHANDLE FileHandle,
  _In_      ACCESS_MASK DesiredAccess,
  _In_      POBJECT_ATTRIBUTES ObjectAttributes,
  _Out_     PIO_STATUS_BLOCK IoStatusBlock,
  _In_opt_  PLARGE_INTEGER AllocationSize,
  _In_      ULONG FileAttributes,
  _In_      ULONG ShareAccess,
  _In_      ULONG CreateDisposition,
  _In_      ULONG CreateOptions,
  _In_      PVOID EaBuffer,
  _In_      ULONG EaLength
);

Yes, it’s that simple.

One thing to note – the EA is added to files on both windows XP and Windows 7, but only under Windows 7 I observed the modification of services.exe. On Windows XP, it only appended EA to the  ‘U’ file and nothing else.

Okay, I mentioned I had a couple of ideas why I wanted to research this feature. Now it’s time to reveal them!

Idea #1 – POC

Once I found out what APIs are being used by the malware, I was also able to produce a simple snippet of code that reproduces the functionality:

.586
.MODEL FLAT,STDCALL

 o equ OFFSET
 include    windows.inc
 include    kernel32.inc
 includelib kernel32.lib
 include    ntdll.inc
 includelib ntdll.lib
 include    masm32.inc
 includelib masm32.lib

IO_STATUS_BLOCK STRUCT
    union
    Status        dd ?
    Pointer        dd ?
    ends
    Information    dd ?
IO_STATUS_BLOCK ENDS

.data?
 file db 256 dup (?)
 fa   db 256 dup (?)
 _FILE_FULL_EA_INFORMATION struct
   NextEntryOffset dd ?
   Flags           db ?
   EaNameLength    db ?
   EaValueLength   dw ?
   EaName          db ?
 _FILE_FULL_EA_INFORMATION ends
 FEA equ _FILE_FULL_EA_INFORMATION
 io IO_STATUS_BLOCK <>
.code
  Start:
  invoke GetCL,1, o file
  lea    edi,[fa+_FILE_FULL_EA_INFORMATION.EaName]
  invoke GetCL,2, edi
  invoke lstrlenA,edi
  lea    esi,[fa+_FILE_FULL_EA_INFORMATION.EaNameLength]
  mov    [esi],al
  add    edi,eax
  inc    edi
  invoke GetCL,3, edi
  invoke lstrlenA,edi
  lea    esi,[fa+_FILE_FULL_EA_INFORMATION.EaValueLength]
  mov    [esi],al
  add    edi,eax
  invoke CreateFileA, o file, \
                      GENERIC_WRITE, \
                      0, \
                      NULL, \
                      CREATE_NEW, \
                      FILE_ATTRIBUTE_NORMAL, \
                      NULL
  xchg   eax,ebx
  mov    eax,edi
  sub    eax,o fa
  invoke NtSetEaFile,ebx,o io,o fa, eax
  invoke CloseHandle,ebx
  invoke ExitProcess,0
END Start

This code can be used for testing purposes in a lab environment.

You can either compile the code yourself using masm32 or you can use a precompiled binary – download it here.

To run:

ea.exe <full path name to a file> <EA name> <EA value>

e.g.:

ea.exe g:\test.txt foo bar

Remember to specify a full path to a file. Also, choose a non-existing file name for a file (the program won’t work with files that are already present).

Last, but not least – there is no error checks, you can add it yourself if you wish 🙂

Idea #2 – Reduce the FUD factor

While it is a novelty technique, it is not very advanced –  a single API call does all the dirty job to _create_ the EA.

To _detect_ EA is not very difficult either – as long as you have a right tool to do so 🙂

Idea #3 – Show how to detect EA on a live system

Now that I got a POC, I can run it:

g:\test.txt foo bar

and then analyze changes introduced to the file system.

I can do it quickly  with hmft.

hmft -l g: mft_list

I tested the program on a small drive that I use for my tests. I formatted it first to ensure its MFT is clean:
hmft_ea_1

I then opened the mft_list file in a Total Commander’s Lister and searched for MFTA_EA. hmft_ea_2

I am pasting the full record for your reference:

  [FILE]
    SignatureD                    = 1162627398
    OffsetToFixupArrayW           = 48
    NumberOfEntriesInFixupArrayW  = 3
    LogFileSequenceNumberQ        = 1062946
    SequenceValueW                = 1
    LinkCountW                    = 1
    OffsetToFirstAttributeW       = 56
    FlagsW                        = 1
    UsedSizeOfMFTEntryD           = 368
    AllocatedSizeOfMFTEntryD      = 1024
    FileReferenceToBaseRecordQ    = 0
    NextAttributeIdD              = 5
   --

    RESIDENT ATTRIBUTE
      AttributeTypeIdentifierD = 16
      LengthOfAttributeD       = 96
      NonResidentFlagB         = 0
      LengthOfNameB            = 0
      OffsetToNameW            = 0
      FlagsW                   = 0
      AttributeIdentifierW     = 0
      --
      SizeOfContentD          = 72
      OffsetToContentW        = 24
      --
        MFTA_STANDARD_INFORMATION
            CreationTimeQ         = 130036100539989520
            ModificationTimeQ     = 130036100539989520
            MFTModificationTimeQ  = 130036100539989520
            AccessTimeQ           = 130036100539989520
            FlagsD                = 32
            MaxNumOfVersionsD     = 0
            VersionNumberD        = 0
            ClassIdD              = 0
            OwnerIdD              = 0
            SecurityIdD           = 261
            QuotaQ                = 0
            USNQ                  = 0
            CreationTime (epoch)    = 1359136453
            ModificationTime (epoch)  = 1359136453
            MFTModificationTime (epoch)  = 1359136453
            AccessTime (epoch)           = 1359136453
   --

    RESIDENT ATTRIBUTE
      AttributeTypeIdentifierD = 48
      LengthOfAttributeD       = 112
      NonResidentFlagB         = 0
      LengthOfNameB            = 0
      OffsetToNameW            = 0
      FlagsW                   = 0
      AttributeIdentifierW     = 2
      --
      SizeOfContentD          = 82
      OffsetToContentW        = 24
      --
        MFTA_FILE_NAME
            ParentID6             = 5
            ParentUseIndexW       = 5
            CreationTimeQ         = 130036100539989520
            ModificationTimeQ     = 130036100539989520
            MFTModificationTimeQ  = 130036100539989520
            AccessTimeQ           = 130036100539989520
            CreationTime (epoch)    = 1359136453
            ModificationTime (epoch)  = 1359136453
            MFTModificationTime (epoch)  = 1359136453
            AccessTime (epoch)           = 1359136453
            AllocatedSizeQ        = 0
            RealSizeQ             = 0
            FlagsD                = 32
            ReparseValueD         = 0
            LengthOfNameB         = 8
            NameSpaceB            = 3
     FileName = test.txt
   --

    RESIDENT ATTRIBUTE
      AttributeTypeIdentifierD = 128
      LengthOfAttributeD       = 24
      NonResidentFlagB         = 0
      LengthOfNameB            = 0
      OffsetToNameW            = 24
      FlagsW                   = 0
      AttributeIdentifierW     = 1
      --
      SizeOfContentD          = 0
      OffsetToContentW        = 24
      --
        MFTA_DATA
   --

   
    RESIDENT ATTRIBUTE
      AttributeTypeIdentifierD = 208
      LengthOfAttributeD       = 32
      NonResidentFlagB         = 0
      LengthOfNameB            = 0
      OffsetToNameW            = 0
      FlagsW                   = 0
      AttributeIdentifierW     = 3
      --
      SizeOfContentD          = 8
      OffsetToContentW        = 24
      --
        MFTA_EA_INFORMATION
   --

    RESIDENT ATTRIBUTE
      AttributeTypeIdentifierD = 224
      LengthOfAttributeD       = 40
      NonResidentFlagB         = 0
      LengthOfNameB            = 0
      OffsetToNameW            = 0
      FlagsW                   = 0
      AttributeIdentifierW     = 4
      --
      SizeOfContentD          = 16
      OffsetToContentW        = 24
      --
        MFTA_EA

There are two EA-related entries here:

  • MFTA_EA_INFORMATION
  • MFTA_EA record

Manual analysis like this are quite tiring, so we can write a short perl snippet that can help us with postprocessing:

use strict;
my $f='';
my $l='';
while (<>)
{
  s/[\r\n]+//g;
  $f = $1 if /FileName = (.+)$/;
  print "$f has $1 record\n" if ($l =~ /(MFTA_EA(_[A-Z]+)?)/);
  $l = $_;
}

Saving it into ea.pl file, and running it as:

ea.pl mft_list

produces the following output:

hmft_ea_3

Idea #4 – Detect ZeroAccess with hmft

It’s simple 🙂

  • I ran hmft before the ZeroAccess installation
  • Then I infected my test box
  • I then ran hmft after the ZeroAccess installation

zeroaccess_ea_2

At this stage, all I had to do was to run ea.pl on both outputs and I got the following results:

zeroaccess_ea_3

Or, for the sake of copy & paste (and web bots :)):

r:\>ea.pl before_installation
V20~1.6 has MFTA_EA_INFORMATION record
V20~1.6 has MFTA_EA record

r:\>ea.pl after_installation
U has MFTA_EA_INFORMATION record
U has MFTA_EA record
V20~1.6 has MFTA_EA_INFORMATION record
V20~1.6 has MFTA_EA record
U has MFTA_EA_INFORMATION record
U has MFTA_EA record
services.exe has MFTA_EA_INFORMATION record
services.exe has MFTA_EA record/span>

As we can see, the malware activity is immediately visible.

Btw. V20~1.6 is a $MFT FILE record that refers to C:\Windows\CSC\v2.0.6 and is related to Offline files (client-side caching). I don’t have any information about the content of this EA. Perhaps someone will be more curious than me to poke around there 🙂

Idea #5 – Create a Frankenstein’s monster

Using EA and ADS (Alternate Data Streams) with a single file is also possible.

You can use ea.exe to create such Frankenstein’s monster in 2 simple steps:

  • by running it first with a  filename only – this will create EA record
  • and then re-runing it with a stream name, this will create the ADS, but EA for ADS will fail (sometimes it’s OK to fail :))

The result is shown on the following screenshot:
ea_frankensteins_monster_1

Using hmft and a combination of ea.pl and ads.pl (posted in older post related to HMFT) in a single eads.pl script:

use strict;
my $f='';
my $l='';
while (<>)
{
  s/[\r\n]+//g;
  $f = $1 if /FileName = (.+)$/;
  print "$f has $1 record\n" if ($l =~ /(MFTA_EA(_[A-Z]+)?)/);
  print "$f:$1\n" if ($l =~ /MFTA_DATA/&&/AttributeName = (.+)$/);
  $l = $_;
}

we can easily detect such beast as well.

That’s all, thanks for reading!

Beyond good ol’ Run key, Part 3

Possible Autostart/start mechanisms that are built-in ‘natively’ in Windows and also available by means of extra features offered by many applications go beyond typical path locations and registry keys highlighted by popular programs and scripts like Autoruns and SilentRunners. I have covered some of the non-standard persistence techniques in 2 older posts in the series here and here, but as usual – there is always more to write about.

In this post I will cover another batch of less known and possibly ‘obscure’ technique that could be potentially used for autostart/start purposes. I write ‘obscure’, because it is not a typical way of doing autostart, but let’s be honest – there is nothing really extraordinary about it – just a simple abuse of built-in features in both OS and applications.

Code-in-the-middle proxy

Long story short, it is a well known fact that many existing registry entries and files pointing to or containing code can be modified to introduce a code-in-the-middle proxy (DLL, EXE, etc.) that will be executed/loaded first instead of a legitimate entry. The original entries are preserved so that they can be transparently executed/loaded once malware is running. There are many existing examples of this technique already being used e.g. hijacks of Shell Open Command,  Image File Execution Options , etc., but it is important to remember that this technique can be extended literally to any registry key or file that is loaded either during autostart or often used by users.

Application Registration (App Paths) hijacking

Another proxy technique that could be used to hijack popular applications relies on registry entries stored under the following key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths

As per Microsoft:

The entries found under App Paths are used primarily for the following purposes:

  • To map an application’s executable file name to that file’s fully qualified path.
  • To pre-pend information to the PATH environment variable on a per-application, per-process basis.

A legitimate entry that can be found on many newer versions of Windows is shown below:

apppaths1

It is responsible for launching MS Paint program when someone tries to run it using a legacy ‘pbrush.exe’ name.

One could add a modification for e.g. calc.exe:

apppaths2

From now on, anytime someone tries to run calc.exe manually (e.g. via Start Menu/Run  window), Notepad will be launched. It may not be a main persistence mechanism, but could be used for re-infection purposes on systems that have been cleaned up, but not rebuilt.

You can test it (XP needed) by downloading this reg file , then applying it to your Registry and then launching Win+R and typing ‘calc’ or ‘calc.exe’ and hitting enter. Note: It doesn’t work from command line (a mistake in an older version of this post which I correct here).

Text Services (TSF)

Microsoft defines Text Services as:

Microsoft Windows Text Services Framework (TSF) is a system service available as a redistributable for Windows 2000. TSF provides a simple and scalable framework for the delivery of advanced text input and natural language technologies. TSF can be enabled in applications, or as a TSF text service. A TSF text service provides multilingual support and delivers text services such as keyboard processors, handwriting recognition, and speech recognition.

From a practical point of view, TSF offers ways to extend available input methods by allowing to install support for languages that are not natively supported by Windows. A good example of such extension is Ekaya – an extension for a Myanmar (Burmese) language.

In order for TSF to work on Windows XP, one has to enable the ‘Extended support of advanced text services to all programs’:

TextService-Step01.4

On Windows 7, it is enabled by default (but to install a TSF DLL one requires administrator privileges).

Examples on how to use TSF are provided in Microsoft SDK (look for ‘Samples\winui\Input\tsf\TextService’ directory). For the purpose of this article, I just picked up the simplest possible example i.e. a project from the ‘Samples\winui\Input\tsf\TextService\TextService-Step01’ subdirectory and updated it with a trivial cosmetic change – a call to OutputDebugString so that we can observe processes loading and unloading our test DLL.

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID pvReserved)
{
  TCHAR szFileFullPath[256];
  TCHAR buf[300];
    switch (dwReason)
    {
        case DLL_PROCESS_ATTACH:

            g_hInst = hInstance;
            GetModuleFileName (NULL,szFileFullPath,256);
             _tcscpy (buf, TEXT("TSF DLL loaded: "));
             _tcscat (buf, szFileFullPath);
            OutputDebugString(buf);
            if (!InitializeCriticalSectionAndSpinCount(&g_cs, 0))
                return FALSE;

            break;

        case DLL_PROCESS_DETACH:

            GetModuleFileName (NULL,szFileFullPath,256);
             _tcscpy (buf, TEXT("TSF DLL unloaded: "));
             _tcscat (buf, szFileFullPath);
            OutputDebugString(buf);

            DeleteCriticalSection(&g_cs);

            break;
    }

    return TRUE;
}

Once registered with Regsrv32.exe:

regsvr32 TextService-Step01.dll

TextService-Step01.1

the DLL is now active and it will now be loaded to each new process utilizing Text Services (pretty much every single GUI application, including these already running) as can be shown via DebugView from Sysinternals.

Running a few test applications shows the following output in DebugView:

TextService-Step01.2

Of course, it survives the reboot and is loaded next time user logs on and applications are executed + it works under Windows 7 without any problem:

TextService-Step01.5

You may be wondering if there is any visual indication of the DLL being present on the system.

There is.

If you look at the legitimate software like aforementioned Ekaya – it adds a set of icons to the Language Bar:

Ekaya1

and

Ekaya2

It can be also seen in Text Services and Input Languages section (you can find it under Regional Settings):

Ekaya3

There is no requirement for TSF DLLs to add extra features to the Language Bar, so the Text Services and Input Languages section under Regional Settings is the only place where it is possible to spot the loaded DLL – for our test sample it looks like this:

TextService-Step01.3

DLL load order

This is a trick relying on  DLL load order – it has been covered on many security blogs in last 2 years so I just mention it for completeness – there are many DLLs that can be ‘injected’ into a loading process of many popular programs. Two of them: fxsst.dll and ntshrui.dll have been covered by Nick Harbour from Mandiant in his posts from July 2010 and June 2011.

IIS Server Extensions (ISAPI filters)

In my older post I mentioned plugins and various extensions that can be loaded into various applications. There are really a lot of possibilities here, including multum of popular software, Windows Shell extensions, aforementioned Text services, IME, URL handlers, and so on and so forth. There are also possibilities of writing server environment-specific extensions e.g. ISAPI filters: As per the information on the page

Every ISAPI filter is contained in a separate DLL that must export two entry-point functions, GetFilterVersionand HttpFilterProc, and optionally export the TerminateFilter function. The metabase property, FilterLoadOrder, contains a list of all filters that IIS loads when the Web service is started.

 AppCertDlls

This is also a known technique – it has been researched and published by EP_X0FF in 2007 on sysinternals forum. There were a few follow-up posts about it, and a sample code can be found here, here and here. If you are interested you may also read ReactOS code that implements this feature here (search for ‘BasepIsProcessAllowed’).

Using a slightly modified code from one of the posts, we can build a DLL to demonstrate how it works.

First we need to add a registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDlls

then any REG_EXPAND_SZ value pointing to a DLL we have built.

appcertsdll1

 Now we need to restart the system to ensure a system-wide coverage. For testing purposes, it is okay to restart Windows Explorer so that it can refresh its internal program state to include these DLL in a process creation sequence. Or, one can simply launch cmd.exe and then run programs from command line to observe the DLL being loaded into each newly created process:

appcertsdll2

 You may be wondering how it works under 64-bit system. It works pretty well.

In fact, you can register both 32-bit and 64-bit DLLs as a notification on a 64-bit system:

appcertsdll3

to ensure notifications will be processed for both 64-bit and 32-bit programs:

 

appcertsdll6

 

That’s all ! Thanks for reading!