Shell Links or more commonly known to native Windows users as shortcut files — technically known by their extension LNK — serve to be one of the most fruitful initial access vectors for threat actors. A seemingly harmless file with a dubious icon and the hopes of malware operators on its back — the file kicks into action and spurs stages onto stages of malware to compromise a system — bravo!
The purpose of this article is to dig into the Shell Link Binary file format powering LNK files and analyzing how these simple shortcuts (LNKs) are potential gateways to havoc.
Shell Link Binary (File Format)
The Shell Link Binary Format is what powers LNK files. It describes a structure — say a container to hold objects in — called a ‘shell link’ — jargon for shortcut or an LNK file. The purpose of it is rather simple — to access one data object by means of another object. To do so, it’d have to store some form of reference to the target data object (called a ‘link target’) for the source to create a relation (called a ‘link’) to it.
Shell links are composed of several other structures which compose the file itself. These structures are listed below below:
Strap in — this isn’t going to be the most ‘fun’ section. Though you’ll need the information to make sense of the output from a parser (we’ll discuss that in the next section).
The SHELL_LINK_HEADER is the only structure within a link file which is mandatory for an LNK file to conform to the file format. This is due to the fact that this header contains key information about the target file, attributes pertaining to that file, and other structures such as LinkFlags to identify the presence of other optional headers (structures).
For example, for the LINKTARGET_IDLIST structure to exist, the HasLinkTargetIDList attribute would have to be set in the LinkFlags sub-structure of this header.
The complete list of attributes within LinkFlags is available at Microsoft’s documentation here.
Assuming HasLinkTargetIDList is set under LinkFlags in the previous structure, this structure stores references to the targets location(s) on the filesystem.
However, these references aren’t simple fully qualified paths (e.g., C:\ABC\aFile.txt). Rather, the Shell namespace organizes files (or objects) such that each file is known by its ItemID (the GetDisplayNameOf method within the IShellFolder interface can be used to convert pointers to these IDs to readable display names).
An organized list of these ItemIDs is what creates an IDList which is further encapsulated in the LINKTARGET_IDLIST structure.
Similarly, if the HasLinkInfo attribute is set under LinkFlags in the first header, the LINKINFO structure is populated. This structure holds information useful to resolve link targets and identify their location including the drive volume, serial numbers, labels, and local paths.
The STRING_DATA section is majorly controlled by the LinkFlags structure in the SHELL_LINK_HEADER. For example, if the HasWorkingDir and HasRelativePath attributes are set within LinkFlags, you’d be able to see the working directory and a relative path of the link target in this structure.
Another important attribute is HasArguments, which specifies the command-line argument with which the link shall be executed.
Now, the final structure in a link file is the EXTRA_DATA structure which holds all other complementing information about a link target. Although the complete list is available here, a few are worthy of a mention:
- EnvironmentVariableDataBlock structure is useful when the link target has a corresponding environment variable as well
- TrackerDataBlock offers another way to locate and resolve the link target using the Link Tracking Service — which can help identify if the target file was copied or moved. It can also return information such as the MachineID (NetBIOS name) where the target last existed and a MAC address
Parsing LNK Files
Isn’t it rather tedious to go through the specification each time? Luckily, our peers have done an awesome job at parsing LNK files and reveal data instantly.
To use it, simply pull the tool from the repo and run it from a shell. To view the help:
Here’s how I’ve parsed a sample:
LECmd.exe -f "C:\Users\X\Desktop\HxD.lnk"
Here’s a glimpse of the output:
If you’ve read it till here — you should have an idea as to what each section in the output represents. Now, let’s turn it up a notch and see how threat actors love to meddle with these files!
The Dark Side of LNK Files
Mostly, threat actors use the command-line feature of LNK files to enable the file to act as a downloader. Let’s take a look at how a typical but malicious LNK file looks to the user.
Dig into its properties and there’s a nasty call to… hsmta. Whatever that is.
So, it starts up in C:\Windows and moves on to its target location but there’s no hsmta. Well, there’s an mshta.exe (a Windows utility used to execute compiled HTML files) — and this utility is renown for malice. But what’s happening here?
If you were to press ‘Open File Location’ now — you’d hit ‘mshta’ even though the target box clearly mentions some other binary. Now, there were dozens of points where we saw references to the link target in the file specification. Let’s parse this file and view it in detail. Here’s a summary of those paths where a target’s path is parsed:
Relative Path: ..\..\..\Windows\System32\hsmta.exe...
Local path: C:\Windows\System32\hsmta.exe...
-File ==> mshta.exe
Short name: hsmta.exe
Modified: 2021-01-02 03:07:32
Extension block count: 1--------- Block 0 (Beef0004) ---------
Long name: mshta.exe
Created: 2021-01-02 03:07:32
Last access: 2021-01-02 03:07:32
MFT entry/sequence #: 215068/6 (0x3481C/0x6)...
Environment variables: %windir%\System32\hsmta.exe...
28636aa6-953d-11d2-b5d6-00c04fd918d0\30 Parsing Path ==> C:\Windows\System32\hsmta.exe
There are five instances where a fake executable name is registered here. LNK files go through several ways to hunt down the link target. Here, when the short name is rendered useless, the long name is used to resolve the link target (the path is actually taken from the EnvironmentVariableDataBlock, the absence of which will make the LNK useless) and execute the malicious link file.
Unfortunately, that’s not it.
You’d think the Target box in the file’s properties would be able to hold the entire command-line argument in it. But it can’t. The field is actually limited to 260 characters. Whereas the entire command-line argument field supports 4096 characters.
Threat actors are known to add whitespace or paddings to the field. This pushes malicious commands outside the scope of the box. Now if an uninformed user were to view the file for suspicious indicators, there would be nothing and a compromise might be underway.
What Can We Do About It?
Writing detection rules is perhaps one of the most efficient way to detect and thwart malicious attempts to execute LNK files.
Florian Roth’s Signature Base repository is also home to several good Yara rules to detect LNK files being dropped from an array of sources e.g. ZIP files or to detect a rather suspicious set of LinkFlags.
Using the TrackerDataBlock, you can also use the NetBIOS name, MAC address, and volume serial number to track an actor across multiple intrusions and campaigns. The metadata has proven to be quite useful as can be seen in this FireEye intrusion analysis.
Lastly, it’s never too late to gently inform your users of good and bad clicks. Through informed lessons of what to do when receiving devious emails or unknown files showing up conveniently — just don’t ever click it.
That’s it for this one, folks!