Tuesday, September 11, 2012

MoVP 1.2 Window Stations and Clipboard Malware

Month of Volatility Plugins 

We previously discussed sessions, which are containers for processes and other objects related to a user's logon session. Among those other objects are window stations, which act as security boundaries for processes and desktops. If you're not already familiar with these objects, see Sessions, Desktops, and Window Stations (Technet) or Window Stations and Desktops (MSDN). From a forensic standpoint, by analyzing window stations objects, you can detect applications snooping on clipboard activity along with the frequency of clipboard usage and the available data formats.

Data Structures 

The window station structure is tagWINDOWSTATION. A structure from Windows 7 64-bit is shown below.

>>> dt("tagWINDOWSTATION")
'tagWINDOWSTATION' (152 bytes)
0x0   : dwSessionId                    ['unsigned long']
0x8   : rpwinstaNext                   ['pointer64', ['tagWINDOWSTATION']]
0x10  : rpdeskList                     ['pointer64', ['tagDESKTOP']]
0x18  : pTerm                          ['pointer64', ['tagTERMINAL']]
0x20  : dwWSF_Flags                    ['unsigned long']
0x28  : spklList                       ['pointer64', ['tagKL']]
0x30  : ptiClipLock                    ['pointer64', ['tagTHREADINFO']]
0x38  : ptiDrawingClipboard            ['pointer64', ['tagTHREADINFO']]
0x40  : spwndClipOpen                  ['pointer64', ['tagWND']]
0x48  : spwndClipViewer                ['pointer64', ['tagWND']]
0x50  : spwndClipOwner                 ['pointer64', ['tagWND']]
0x58  : pClipBase                      ['pointer', ['array', <function <lambda> at 0x10195a848>, ['tagCLIP']]]
0x60  : cNumClipFormats                ['unsigned long']
0x64  : iClipSerialNumber              ['unsigned long']
0x68  : iClipSequenceNumber            ['unsigned long']
0x70  : spwndClipboardListener         ['pointer64', ['tagWND']]
0x78  : pGlobalAtomTable               ['pointer64', ['void']]
0x80  : luidEndSession                 ['_LUID']
0x88  : luidUser                       ['_LUID']
0x90  : psidUser                       ['pointer64', ['void']]

Key Points
  • dwSessionId can be used to link a window station to its owning session (it will match _MM_SESSION_SPACE.SessionId). 
  • rpwinstaNext can be used to enumerate all window stations in the same session as the current one. 
  • rpdeskList is a pointer to the window station’s first desktop.  
  • dwWSF_Flags can tell you if the window station is interactive or not (see the WSF_NOIO flag). 
  • Several of the fields can tell you which thread is viewing the clipboard, which thread owns the clipboard, and which thread (if any) may be listening to clipboard operations (i.e. snooping). 
  • pClipBase is a pointer to an array of tagCLIP structures that describe the available clipboard formats and contain handles to clipboard objects. The array size is taken from cNumClipFormats
  • iClipSequenceNumber increments by 1 for each object copied to the clipboard. By looking at this number, you can tell how frequently copy operations occur. 
  • pGlobalAtomTable points to the window station’s atom table.
The WndScan Plugin 

Window stations (and desktops) are securable objects. That means they’re allocated, managed, and freed by the same executive object manager that handles processes, threads, mutants, and registry keys. Thus, they have a _POOL_HEADER and a _OBJECT_HEADER and can easily be located in physical memory by sub-classing Volatility’s built-in scan.PoolScanner class.  Alternately, if PDB symbols are available, you can walk the list of window stations for a given session using win32k!_grpWinStaList

Also note the tagWINDOWSTATION structure does not have a name field, yet window stations are referred to by their name (such as WinSta0). That’s because the name field is in the _OBJECT_HEADER

In the output below, the first window station found is WinSta0 for session 2. This window station’s atom table is located at 0xe7981648, it contains three desktops (Default, Disconnect, and Winlogon), and rdpclip.exe is current viewing the clipboard, which makes sense since that is the process that handles copy & paste operations over RDP. There are 4 supported clipboard formats (such as ASCII, Unicode, bitmap, etc.) and so far the user has copied 9 items to the clipboard.  

$ python vol.py -f rdp.mem --profile=Win2003SP2x86 wndscan
Volatile Systems Volatility Framework 2.1_alpha
**************************************************
WindowStation: 0x8581e40, Name: WinSta0, Next: 0x0
SessionId: 2, AtomTable: 0xe7981648, Interactive: True
Desktops: Default, Disconnect, Winlogon
ptiDrawingClipboard: pid - tid -
spwndClipOpen: 0x0, spwndClipViewer: 0xbc6f2ca8 6772 rdpclip.exe
cNumClipFormats: 4, iClipSerialNumber: 9
pClipBase: 0xe6fe8ec8, Formats: CF_UNICODETEXT,CF_LOCALE,CF_TEXT,CF_OEMTEXT 
[snip] 

The next window station is named __X78B95_89_IW with a single desktop named __A8D9S1_42_ID. This is a standard naming convention used by inetinfo.exe, so you know the suspect system was running IIS at the time.  The last one shown in the example is WinSta0 for session 0. Although it’s interactive, the cNumClipFormats and iClipSerialNumber are both 0, meaning this window station’s clipboard has never been used. 

**************************************************
WindowStation: 0x990c760, Name: __X78B95_89_IW, Next: 0x0
SessionId: 0, AtomTable: 0xe26c6a60, Interactive: False
Desktops: __A8D9S1_42_ID
ptiDrawingClipboard: pid - tid -
spwndClipOpen: 0x0, spwndClipViewer: 0x0  
cNumClipFormats: 0, iClipSerialNumber: 0
pClipBase: 0x0, Formats: 
**************************************************
WindowStation: 0x9a0d148, Name: WinSta0, Next: 0x8a089c48
SessionId: 0, AtomTable: 0xe1b19b10, Interactive: True
Desktops: Default, Disconnect, Winlogon
ptiDrawingClipboard: pid - tid -
spwndClipOpen: 0x0, spwndClipViewer: 0x0  
cNumClipFormats: 0, iClipSerialNumber: 0
pClipBase: 0x0, Formats: 
[snip]

Clipboard Snooping Malware

Many malware samples snoop on clipboard operations. One method is by hooking SetClipboardData and stealing the data as its placed into the clipboard, but that modifies the system in obvious ways. Another method, which you probably will never see is calling GetClipboardData at a fast-paced regular interval (i.e. in a loop with Sleep(100)). Why is this a bad idea? Because before requesting the clipboard data, you must call OpenClipboard, and only one window can have the clipboard open at a time. If malware opens the clipboard to check for data every 100ms, it could accidentally prevent (by blocking) legit applications from accessing the clipboard.

The recommended way to access data as soon as its copied to the clipboard is to register as a clipboard viewer (SetClipboardViewer) or format listener (AddClipboardFormatListener). These functions allow applications to receive notifications (via WM_DRAWCLIPBOARD messages) whenever the content of the clipboard changes. They can then safely open the clipboard and query the data. As always, the most interesting part of all this is the laundry list of artifacts left in physical memory as a result of calling these APIs. The following example uses Nirsoft's clipboardic (you can also use InsideClipboard) to demonstrate. These tools use the same APIs that malware uses, and since they're not actually malicious, you can follow along on your own systems.

To help illustrate the exact changes made from specific behaviors, we'll start with a fresh system just rebooted (i.e. no clipboard activity yet). Here's the wndscan output for the user's WinSta0:

$ python vol.py -f memory.dmp --profile=Win7SP1x86 wndscan
**************************************************
WindowStation: 0x7ea45d00, Name: WinSta0, Next: 0x0
SessionId: 1, AtomTable: 0x93b107f0, Interactive: True
Desktops: Default, Disconnect, Winlogon
ptiDrawingClipboard: pid - tid -
spwndClipOpen: 0x0, spwndClipViewer: 0x0  
cNumClipFormats: 0, iClipSerialNumber: 0
pClipBase: 0x0, Formats: 

Notice the clipboard base is NULL, there are no formats, no clipboard owners or viewers, and the serial number is zero. We can use the wintree plugin (see a future MoVP post) to grep for the initial windows of the class CLIPBRDWNDCLASS.

$ python vol.py -f memory.dmp --profile=Win7SP1x86 wintree | grep CLIPBRDWNDCLASS
Volatile Systems Volatility Framework 2.2_alpha
.#10062  explorer.exe:372 CLIPBRDWNDCLASS
.#100f0  explorer.exe:372 CLIPBRDWNDCLASS
.#1011e  vmtoolsd.exe:2224 CLIPBRDWNDCLASS
.#1014a  SnagIt32.exe:2300 CLIPBRDWNDCLASS

As you can see, explorer, vmtoolsd (VMware Tools), and SnagIt32 (a screen shot application that allows you to copy/paste images) have windows of this class. That all makes perfect sense. Do you see other applications on your system? If so, do they have a functional need to access the clipboard? These are questions you'll ask yourself when trying to determine if there are malicious processes snooping on your clipboard.

Now, on my test VM, I opened Notepad++ and Nirsoft's clipboardic.exe program. I copied some data from my host OS and pasted it into the running VMware guest. I also copied some data from the Notepad++ release notes onto the clipboard. As you can see, the text was captured by clipboardic.exe as expected:


Let's take a second look at the physical memory after those actions. Keep in mind, malware would use the exact same APIs and produce similar effects.

$ python vol.py -f memory.dmp --profile=Win7SP1x86 wndscan
**************************************************
WindowStation: 0x7ea45d00, Name: WinSta0, Next: 0x0
SessionId: 1, AtomTable: 0x93b107f0, Interactive: True
Desktops: Default, Disconnect, Winlogon
ptiDrawingClipboard: pid - tid -
spwndClipOpen: 0x0, spwndClipViewer: 0xfea5db80 3616 Clipboardic.ex
cNumClipFormats: 4, iClipSerialNumber: 11
pClipBase: 0xfccb2be8, Formats: CF_UNICODETEXT,Unknown choice 8192,CF_TEXT,Unknown choice 197569

What do you see? A new clipboard viewer has been registered by pid 3616 (Clipboardic.exe). There are four clipboard formats, among them are ANSI text and Unicode text (the others are probably OLE data - more on that in a future MoVP post). The serial number has now been increased to 11. Furthermore, there are several new windows of the clipboard class:

$ python vol.py -f memory.dmp --profile=Win7SP1x86 wintree | grep CLIPBRDWNDCLASS
Volatile Systems Volatility Framework 2.2_alpha
.#10062  explorer.exe:372 CLIPBRDWNDCLASS
.#100f0  explorer.exe:372 CLIPBRDWNDCLASS
.#1011e  vmtoolsd.exe:2224 CLIPBRDWNDCLASS
.#1014a  SnagIt32.exe:2300 CLIPBRDWNDCLASS
.#4002c  vmtoolsd.exe:2224 CLIPBRDWNDCLASS
.#10288  notepad++.exe:3140 CLIPBRDWNDCLASS
.#1032c  Clipboardic.ex:3616 CLIPBRDWNDCLASS

Each application that's involved in the copy and paste operations is represented here. VMware Tools (vmtoolsd.exe) which was previously running has created a new window (#4002c) to pass the data from the host to the guest. Notepad++ has a window (#10288) to receive the data. Clipboardic.exe has a window (#1032c) to snoop on the data. 

Conclusion

By analyzing window station objects, you can get a better understanding of the GUI landscape at the time of a compromise or malware infection. Further more, you can easily enumerate desktops, locate atom tables, and determine which processes have registered to receive clipboard notifications. With Volatility, now you can detect which applications may be stealing clipboard data in entirely new ways!

More information on the wndscan plugin and its usages in forensic investigations will be presented at Open Memory Forensics Workshop (OMFW) 2012.

1 comment:

  1. Thanks for this blog entry - dug it up to help define my attack model for my password management research. Trying to understand how prevalent clipboard monitoring is and how might it be relevant to vulnerabilities associated with software-based password management solutions like KeePass.

    ReplyDelete