Keylogger Data Stored in an ADS
If many malware samples try to be "filess" (read: they try to reduce their filesystem footprint to the bare minimum), another technique remains interesting: Alternate Data Streams or "ADS"[1]. This NTFS feature allows files to contain multiple data streams, enabling hidden or additional metadata to be stored alongside the main file content without being visible in standard file listings. A common usage of ADS is the "Mark of the Web"[2] that helps to flag files as suspicious or not depending on their origin.
I found a simple Python keylogger that implements an ADS to store the captured keystrokes:
hidden_dir = os.path.join(os.environ['APPDATA'], 'Microsoft\\Windows\\Cache') os.makedirs(hidden_dir, exist_ok=True) log_host_file = os.path.join(hidden_dir, "syscache.dat") log_file = log_host_file + ":logdata"
A second layer of protection is implemented to hide the file using SetFileAttributesW()[3] with the flag 0x02:
try: FILE_ATTRIBUTE_HIDDEN = 0x02 ctypes.windll.kernel32.SetFileAttributesW(log_host_file, FILE_ATTRIBUTE_HIDDEN) except Exception as e: print(f"Failed to hide host file: {e}")
The script is a classic keylogger but it also implements a clipboard monitor to capture all text content:
try: win32clipboard.OpenClipboard() if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_TEXT): data = win32clipboard.GetClipboardData() win32clipboard.CloseClipboard()
The script (SHA256:9927159c39a0201e2fcd558c4716fc5cab7e1c6ab69a311f7a21cab3c5667980) has a low VT score (only 3/64) even if not obfuscated. The script does not have an exfiltration mechanism, therefore I presume that another one will take care of this!
How to detect if files have ADS on your file system? This can be achieve with a few lines of PowerShell:
Get-ChildItem -Recurse -Path C:\ | ForEach-Object { $streams = Get-Item $_.FullName -Stream * -ErrorAction SilentlyContinue if ($streams.Count -gt 1) { $streams } }
Example:
PS C:\Users\REM> C:\Users\REM\Documents\ads_search.ps1 PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\REM\Desktop\PURCHASE_ORDER.exe::$DATA PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\REM\Desktop PSChildName : PURCHASE_ORDER.exe::$DATA PSDrive : C PSProvider : Microsoft.PowerShell.Core\FileSystem PSIsContainer : False FileName : C:\Users\REM\Desktop\PURCHASE_ORDER.exe Stream : :$DATA Length : 1044992 PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\REM\Desktop\PURCHASE_ORDER.exe:Zone.Identifier PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\REM\Desktop PSChildName : PURCHASE_ORDER.exe:Zone.Identifier PSDrive : C PSProvider : Microsoft.PowerShell.Core\FileSystem PSIsContainer : False FileName : C:\Users\REM\Desktop\PURCHASE_ORDER.exe Stream : Zone.Identifier Length : 608
[1] https://infosecwriteups.com/ntfs-filesystem-alternate-data-stream-ads-c0e4a2402563
[2] https://en.wikipedia.org/wiki/Mark_of_the_Web
[3] https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesw
Xavier Mertens (@xme)
Xameco
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
Comments